github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/object_gomap_reflect.go (about) 1 package goja 2 3 import ( 4 "reflect" 5 6 "github.com/nuvolaris/goja/unistring" 7 ) 8 9 type objectGoMapReflect struct { 10 objectGoReflect 11 12 keyType, valueType reflect.Type 13 } 14 15 func (o *objectGoMapReflect) init() { 16 o.objectGoReflect.init() 17 o.keyType = o.fieldsValue.Type().Key() 18 o.valueType = o.fieldsValue.Type().Elem() 19 } 20 21 func (o *objectGoMapReflect) toKey(n Value, throw bool) reflect.Value { 22 key := reflect.New(o.keyType).Elem() 23 err := o.val.runtime.toReflectValue(n, key, &objectExportCtx{}) 24 if err != nil { 25 o.val.runtime.typeErrorResult(throw, "map key conversion error: %v", err) 26 return reflect.Value{} 27 } 28 return key 29 } 30 31 func (o *objectGoMapReflect) strToKey(name string, throw bool) reflect.Value { 32 if o.keyType.Kind() == reflect.String { 33 return reflect.ValueOf(name).Convert(o.keyType) 34 } 35 return o.toKey(newStringValue(name), throw) 36 } 37 38 func (o *objectGoMapReflect) _getKey(key reflect.Value) Value { 39 if !key.IsValid() { 40 return nil 41 } 42 if v := o.fieldsValue.MapIndex(key); v.IsValid() { 43 rv := v 44 if rv.Kind() == reflect.Interface { 45 rv = rv.Elem() 46 } 47 return o.val.runtime.toValue(v.Interface(), rv) 48 } 49 50 return nil 51 } 52 53 func (o *objectGoMapReflect) _get(n Value) Value { 54 return o._getKey(o.toKey(n, false)) 55 } 56 57 func (o *objectGoMapReflect) _getStr(name string) Value { 58 return o._getKey(o.strToKey(name, false)) 59 } 60 61 func (o *objectGoMapReflect) getStr(name unistring.String, receiver Value) Value { 62 if v := o._getStr(name.String()); v != nil { 63 return v 64 } 65 return o.objectGoReflect.getStr(name, receiver) 66 } 67 68 func (o *objectGoMapReflect) getIdx(idx valueInt, receiver Value) Value { 69 if v := o._get(idx); v != nil { 70 return v 71 } 72 return o.objectGoReflect.getIdx(idx, receiver) 73 } 74 75 func (o *objectGoMapReflect) getOwnPropStr(name unistring.String) Value { 76 if v := o._getStr(name.String()); v != nil { 77 return &valueProperty{ 78 value: v, 79 writable: true, 80 enumerable: true, 81 } 82 } 83 return o.objectGoReflect.getOwnPropStr(name) 84 } 85 86 func (o *objectGoMapReflect) getOwnPropIdx(idx valueInt) Value { 87 if v := o._get(idx); v != nil { 88 return &valueProperty{ 89 value: v, 90 writable: true, 91 enumerable: true, 92 } 93 } 94 return o.objectGoReflect.getOwnPropStr(idx.string()) 95 } 96 97 func (o *objectGoMapReflect) toValue(val Value, throw bool) (reflect.Value, bool) { 98 v := reflect.New(o.valueType).Elem() 99 err := o.val.runtime.toReflectValue(val, v, &objectExportCtx{}) 100 if err != nil { 101 o.val.runtime.typeErrorResult(throw, "map value conversion error: %v", err) 102 return reflect.Value{}, false 103 } 104 105 return v, true 106 } 107 108 func (o *objectGoMapReflect) _put(key reflect.Value, val Value, throw bool) bool { 109 if key.IsValid() { 110 if o.extensible || o.fieldsValue.MapIndex(key).IsValid() { 111 v, ok := o.toValue(val, throw) 112 if !ok { 113 return false 114 } 115 o.fieldsValue.SetMapIndex(key, v) 116 } else { 117 o.val.runtime.typeErrorResult(throw, "Cannot set property %s, object is not extensible", key.String()) 118 return false 119 } 120 return true 121 } 122 return false 123 } 124 125 func (o *objectGoMapReflect) setOwnStr(name unistring.String, val Value, throw bool) bool { 126 n := name.String() 127 key := o.strToKey(n, false) 128 if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() { 129 if proto := o.prototype; proto != nil { 130 // we know it's foreign because prototype loops are not allowed 131 if res, ok := proto.self.setForeignStr(name, val, o.val, throw); ok { 132 return res 133 } 134 } 135 // new property 136 if !o.extensible { 137 o.val.runtime.typeErrorResult(throw, "Cannot add property %s, object is not extensible", n) 138 return false 139 } else { 140 if throw && !key.IsValid() { 141 o.strToKey(n, true) 142 return false 143 } 144 } 145 } 146 o._put(key, val, throw) 147 return true 148 } 149 150 func (o *objectGoMapReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool { 151 key := o.toKey(idx, false) 152 if !key.IsValid() || !o.fieldsValue.MapIndex(key).IsValid() { 153 if proto := o.prototype; proto != nil { 154 // we know it's foreign because prototype loops are not allowed 155 if res, ok := proto.self.setForeignIdx(idx, val, o.val, throw); ok { 156 return res 157 } 158 } 159 // new property 160 if !o.extensible { 161 o.val.runtime.typeErrorResult(throw, "Cannot add property %d, object is not extensible", idx) 162 return false 163 } else { 164 if throw && !key.IsValid() { 165 o.toKey(idx, true) 166 return false 167 } 168 } 169 } 170 o._put(key, val, throw) 171 return true 172 } 173 174 func (o *objectGoMapReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 175 return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw) 176 } 177 178 func (o *objectGoMapReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) { 179 return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw) 180 } 181 182 func (o *objectGoMapReflect) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool { 183 if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) { 184 return false 185 } 186 187 return o._put(o.strToKey(name.String(), throw), descr.Value, throw) 188 } 189 190 func (o *objectGoMapReflect) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool { 191 if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) { 192 return false 193 } 194 195 return o._put(o.toKey(idx, throw), descr.Value, throw) 196 } 197 198 func (o *objectGoMapReflect) hasOwnPropertyStr(name unistring.String) bool { 199 key := o.strToKey(name.String(), false) 200 if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() { 201 return true 202 } 203 return false 204 } 205 206 func (o *objectGoMapReflect) hasOwnPropertyIdx(idx valueInt) bool { 207 key := o.toKey(idx, false) 208 if key.IsValid() && o.fieldsValue.MapIndex(key).IsValid() { 209 return true 210 } 211 return false 212 } 213 214 func (o *objectGoMapReflect) deleteStr(name unistring.String, throw bool) bool { 215 key := o.strToKey(name.String(), throw) 216 if !key.IsValid() { 217 return false 218 } 219 o.fieldsValue.SetMapIndex(key, reflect.Value{}) 220 return true 221 } 222 223 func (o *objectGoMapReflect) deleteIdx(idx valueInt, throw bool) bool { 224 key := o.toKey(idx, throw) 225 if !key.IsValid() { 226 return false 227 } 228 o.fieldsValue.SetMapIndex(key, reflect.Value{}) 229 return true 230 } 231 232 type gomapReflectPropIter struct { 233 o *objectGoMapReflect 234 keys []reflect.Value 235 idx int 236 } 237 238 func (i *gomapReflectPropIter) next() (propIterItem, iterNextFunc) { 239 for i.idx < len(i.keys) { 240 key := i.keys[i.idx] 241 v := i.o.fieldsValue.MapIndex(key) 242 i.idx++ 243 if v.IsValid() { 244 return propIterItem{name: newStringValue(key.String()), enumerable: _ENUM_TRUE}, i.next 245 } 246 } 247 248 return propIterItem{}, nil 249 } 250 251 func (o *objectGoMapReflect) iterateStringKeys() iterNextFunc { 252 return (&gomapReflectPropIter{ 253 o: o, 254 keys: o.fieldsValue.MapKeys(), 255 }).next 256 } 257 258 func (o *objectGoMapReflect) stringKeys(_ bool, accum []Value) []Value { 259 // all own keys are enumerable 260 for _, key := range o.fieldsValue.MapKeys() { 261 accum = append(accum, newStringValue(key.String())) 262 } 263 264 return accum 265 }