github.com/dop251/goja@v0.0.0-20240220182346-e401ed450204/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) builtin_newWeakMap(args []Value, newTarget *Object) *Object { 94 if newTarget == nil { 95 panic(r.needNew("WeakMap")) 96 } 97 proto := r.getPrototypeFromCtor(newTarget, r.global.WeakMap, r.global.WeakMapPrototype) 98 o := &Object{runtime: r} 99 100 wmo := &weakMapObject{} 101 wmo.class = classObject 102 wmo.val = o 103 wmo.extensible = true 104 o.self = wmo 105 wmo.prototype = proto 106 wmo.init() 107 if len(args) > 0 { 108 if arg := args[0]; arg != nil && arg != _undefined && arg != _null { 109 adder := wmo.getStr("set", nil) 110 adderFn := toMethod(adder) 111 if adderFn == nil { 112 panic(r.NewTypeError("WeakMap.set in missing")) 113 } 114 iter := r.getIterator(arg, nil) 115 i0 := valueInt(0) 116 i1 := valueInt(1) 117 if adder == r.global.weakMapAdder { 118 iter.iterate(func(item Value) { 119 itemObj := r.toObject(item) 120 k := itemObj.self.getIdx(i0, nil) 121 v := nilSafe(itemObj.self.getIdx(i1, nil)) 122 wmo.m.set(r.toObject(k), v) 123 }) 124 } else { 125 iter.iterate(func(item Value) { 126 itemObj := r.toObject(item) 127 k := itemObj.self.getIdx(i0, nil) 128 v := itemObj.self.getIdx(i1, nil) 129 adderFn(FunctionCall{This: o, Arguments: []Value{k, v}}) 130 }) 131 } 132 } 133 } 134 return o 135 } 136 137 func (r *Runtime) createWeakMapProto(val *Object) objectImpl { 138 o := newBaseObjectObj(val, r.global.ObjectPrototype, classObject) 139 140 o._putProp("constructor", r.getWeakMap(), true, false, true) 141 r.global.weakMapAdder = r.newNativeFunc(r.weakMapProto_set, "set", 2) 142 o._putProp("set", r.global.weakMapAdder, true, false, true) 143 o._putProp("delete", r.newNativeFunc(r.weakMapProto_delete, "delete", 1), true, false, true) 144 o._putProp("has", r.newNativeFunc(r.weakMapProto_has, "has", 1), true, false, true) 145 o._putProp("get", r.newNativeFunc(r.weakMapProto_get, "get", 1), true, false, true) 146 147 o._putSym(SymToStringTag, valueProp(asciiString(classWeakMap), false, false, true)) 148 149 return o 150 } 151 152 func (r *Runtime) createWeakMap(val *Object) objectImpl { 153 o := r.newNativeConstructOnly(val, r.builtin_newWeakMap, r.getWeakMapPrototype(), "WeakMap", 0) 154 155 return o 156 } 157 158 func (r *Runtime) getWeakMapPrototype() *Object { 159 ret := r.global.WeakMapPrototype 160 if ret == nil { 161 ret = &Object{runtime: r} 162 r.global.WeakMapPrototype = ret 163 ret.self = r.createWeakMapProto(ret) 164 } 165 return ret 166 } 167 168 func (r *Runtime) getWeakMap() *Object { 169 ret := r.global.WeakMap 170 if ret == nil { 171 ret = &Object{runtime: r} 172 r.global.WeakMap = ret 173 ret.self = r.createWeakMap(ret) 174 } 175 return ret 176 }