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