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  }