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 }
177
View as plain text