github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/builtin_weakmap.go (about) 1 package goja 2 3 type weakMap uint64 4 5 type weakMapObject struct { 6 baseObject 7 m weakMap 8 } 9 10 func (wmo *weakMapObject) init() { 11 wmo.baseObject.init() 12 wmo.m = weakMap(wmo.val.runtime.genId()) 13 } 14 15 func (wm weakMap) set(key *Object, value Value) { 16 key.getWeakRefs()[wm] = value 17 } 18 19 func (wm weakMap) get(key *Object) Value { 20 return key.weakRefs[wm] 21 } 22 23 func (wm weakMap) remove(key *Object) bool { 24 if _, exists := key.weakRefs[wm]; exists { 25 delete(key.weakRefs, wm) 26 return true 27 } 28 return false 29 } 30 31 func (wm weakMap) has(key *Object) bool { 32 _, exists := key.weakRefs[wm] 33 return exists 34 } 35 36 func (r *Runtime) weakMapProto_delete(call FunctionCall) Value { 37 thisObj := r.toObject(call.This) 38 wmo, ok := thisObj.self.(*weakMapObject) 39 if !ok { 40 panic(r.NewTypeError("Method WeakMap.prototype.delete called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj}))) 41 } 42 key, ok := call.Argument(0).(*Object) 43 if ok && wmo.m.remove(key) { 44 return valueTrue 45 } 46 return valueFalse 47 } 48 49 func (r *Runtime) weakMapProto_get(call FunctionCall) Value { 50 thisObj := r.toObject(call.This) 51 wmo, ok := thisObj.self.(*weakMapObject) 52 if !ok { 53 panic(r.NewTypeError("Method WeakMap.prototype.get called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj}))) 54 } 55 var res Value 56 if key, ok := call.Argument(0).(*Object); ok { 57 res = wmo.m.get(key) 58 } 59 if res == nil { 60 return _undefined 61 } 62 return res 63 } 64 65 func (r *Runtime) weakMapProto_has(call FunctionCall) Value { 66 thisObj := r.toObject(call.This) 67 wmo, ok := thisObj.self.(*weakMapObject) 68 if !ok { 69 panic(r.NewTypeError("Method WeakMap.prototype.has called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj}))) 70 } 71 key, ok := call.Argument(0).(*Object) 72 if ok && wmo.m.has(key) { 73 return valueTrue 74 } 75 return valueFalse 76 } 77 78 func (r *Runtime) weakMapProto_set(call FunctionCall) Value { 79 thisObj := r.toObject(call.This) 80 wmo, ok := thisObj.self.(*weakMapObject) 81 if !ok { 82 panic(r.NewTypeError("Method WeakMap.prototype.set called on incompatible receiver %s", r.objectproto_toString(FunctionCall{This: thisObj}))) 83 } 84 key := r.toObject(call.Argument(0)) 85 wmo.m.set(key, call.Argument(1)) 86 return call.This 87 } 88 89 func (r *Runtime) needNew(name string) *Object { 90 return r.NewTypeError("Constructor %s requires 'new'", name) 91 } 92 93 func (r *Runtime) getPrototypeFromCtor(newTarget, defCtor, defProto *Object) *Object { 94 if newTarget == defCtor { 95 return defProto 96 } 97 proto := newTarget.self.getStr("prototype", nil) 98 if obj, ok := proto.(*Object); ok { 99 return obj 100 } 101 return defProto 102 } 103 104 func (r *Runtime) builtin_newWeakMap(args []Value, newTarget *Object) *Object { 105 if newTarget == nil { 106 panic(r.needNew("WeakMap")) 107 } 108 proto := r.getPrototypeFromCtor(newTarget, r.global.WeakMap, r.global.WeakMapPrototype) 109 o := &Object{runtime: r} 110 111 wmo := &weakMapObject{} 112 wmo.class = classObject 113 wmo.val = o 114 wmo.extensible = true 115 o.self = wmo 116 wmo.prototype = proto 117 wmo.init() 118 if len(args) > 0 { 119 if arg := args[0]; arg != nil && arg != _undefined && arg != _null { 120 adder := wmo.getStr("set", nil) 121 adderFn := toMethod(adder) 122 if adderFn == nil { 123 panic(r.NewTypeError("WeakMap.set in missing")) 124 } 125 iter := r.getIterator(arg, nil) 126 i0 := valueInt(0) 127 i1 := valueInt(1) 128 if adder == r.global.weakMapAdder { 129 iter.iterate(func(item Value) { 130 itemObj := r.toObject(item) 131 k := itemObj.self.getIdx(i0, nil) 132 v := nilSafe(itemObj.self.getIdx(i1, nil)) 133 wmo.m.set(r.toObject(k), v) 134 }) 135 } else { 136 iter.iterate(func(item Value) { 137 itemObj := r.toObject(item) 138 k := itemObj.self.getIdx(i0, nil) 139 v := itemObj.self.getIdx(i1, nil) 140 adderFn(FunctionCall{This: o, Arguments: []Value{k, v}}) 141 }) 142 } 143 } 144 } 145 return o 146 } 147 148 func (r *Runtime) createWeakMapProto(val *Object) objectImpl { 149 o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject) 150 151 o._putProp("constructor", r.global.WeakMap, true, false, true) 152 r.global.weakMapAdder = r.newNativeFunc(r.weakMapProto_set, nil, "set", nil, 2) 153 o._putProp("set", r.global.weakMapAdder, true, false, true) 154 o._putProp("delete", r.newNativeFunc(r.weakMapProto_delete, nil, "delete", nil, 1), true, false, true) 155 o._putProp("has", r.newNativeFunc(r.weakMapProto_has, nil, "has", nil, 1), true, false, true) 156 o._putProp("get", r.newNativeFunc(r.weakMapProto_get, nil, "get", nil, 1), true, false, true) 157 158 o._putSym(SymToStringTag, valueProp(asciiString(classWeakMap), false, false, true)) 159 160 return o 161 } 162 163 func (r *Runtime) createWeakMap(val *Object) objectImpl { 164 o := r.newNativeConstructOnly(val, r.builtin_newWeakMap, r.global.WeakMapPrototype, "WeakMap", 0) 165 166 return o 167 } 168 169 func (r *Runtime) initWeakMap() { 170 r.global.WeakMapPrototype = r.newLazyObject(r.createWeakMapProto) 171 r.global.WeakMap = r.newLazyObject(r.createWeakMap) 172 173 r.addToGlobal("WeakMap", r.global.WeakMap) 174 }