github.com/nuvolaris/goja@v0.0.0-20230825100449-967811910c6d/object_goslice.go (about) 1 package goja 2 3 import ( 4 "math" 5 "math/bits" 6 "reflect" 7 "strconv" 8 9 "github.com/nuvolaris/goja/unistring" 10 ) 11 12 type objectGoSlice struct { 13 baseObject 14 data *[]interface{} 15 lengthProp valueProperty 16 origIsPtr bool 17 } 18 19 func (r *Runtime) newObjectGoSlice(data *[]interface{}, isPtr bool) *objectGoSlice { 20 obj := &Object{runtime: r} 21 a := &objectGoSlice{ 22 baseObject: baseObject{ 23 val: obj, 24 }, 25 data: data, 26 origIsPtr: isPtr, 27 } 28 obj.self = a 29 a.init() 30 31 return a 32 } 33 34 func (o *objectGoSlice) init() { 35 o.baseObject.init() 36 o.class = classArray 37 o.prototype = o.val.runtime.global.ArrayPrototype 38 o.lengthProp.writable = true 39 o.extensible = true 40 o.baseObject._put("length", &o.lengthProp) 41 } 42 43 func (o *objectGoSlice) updateLen() { 44 o.lengthProp.value = intToValue(int64(len(*o.data))) 45 } 46 47 func (o *objectGoSlice) _getIdx(idx int) Value { 48 return o.val.runtime.ToValue((*o.data)[idx]) 49 } 50 51 func (o *objectGoSlice) getStr(name unistring.String, receiver Value) Value { 52 var ownProp Value 53 if idx := strToGoIdx(name); idx >= 0 && idx < len(*o.data) { 54 ownProp = o._getIdx(idx) 55 } else if name == "length" { 56 o.updateLen() 57 ownProp = &o.lengthProp 58 } 59 60 return o.getStrWithOwnProp(ownProp, name, receiver) 61 } 62 63 func (o *objectGoSlice) getIdx(idx valueInt, receiver Value) Value { 64 if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) { 65 return o._getIdx(int(idx)) 66 } 67 if o.prototype != nil { 68 if receiver == nil { 69 return o.prototype.self.getIdx(idx, o.val) 70 } 71 return o.prototype.self.getIdx(idx, receiver) 72 } 73 return nil 74 } 75 76 func (o *objectGoSlice) getOwnPropStr(name unistring.String) Value { 77 if idx := strToGoIdx(name); idx >= 0 { 78 if idx < len(*o.data) { 79 return &valueProperty{ 80 value: o._getIdx(idx), 81 writable: true, 82 enumerable: true, 83 } 84 } 85 return nil 86 } 87 if name == "length" { 88 o.updateLen() 89 return &o.lengthProp 90 } 91 return nil 92 } 93 94 func (o *objectGoSlice) getOwnPropIdx(idx valueInt) Value { 95 if idx := int64(idx); idx >= 0 && idx < int64(len(*o.data)) { 96 return &valueProperty{ 97 value: o._getIdx(int(idx)), 98 writable: true, 99 enumerable: true, 100 } 101 } 102 return nil 103 } 104 105 func (o *objectGoSlice) grow(size int) { 106 oldcap := cap(*o.data) 107 if oldcap < size { 108 n := make([]interface{}, size, growCap(size, len(*o.data), oldcap)) 109 copy(n, *o.data) 110 *o.data = n 111 } else { 112 tail := (*o.data)[len(*o.data):size] 113 for k := range tail { 114 tail[k] = nil 115 } 116 *o.data = (*o.data)[:size] 117 } 118 } 119 120 func (o *objectGoSlice) shrink(size int) { 121 tail := (*o.data)[size:] 122 for k := range tail { 123 tail[k] = nil 124 } 125 *o.data = (*o.data)[:size] 126 } 127 128 func (o *objectGoSlice) putIdx(idx int, v Value, throw bool) { 129 if idx >= len(*o.data) { 130 o.grow(idx + 1) 131 } 132 (*o.data)[idx] = v.Export() 133 } 134 135 func (o *objectGoSlice) putLength(v uint32, throw bool) bool { 136 if bits.UintSize == 32 && v > math.MaxInt32 { 137 panic(rangeError("Integer value overflows 32-bit int")) 138 } 139 newLen := int(v) 140 curLen := len(*o.data) 141 if newLen > curLen { 142 o.grow(newLen) 143 } else if newLen < curLen { 144 o.shrink(newLen) 145 } 146 return true 147 } 148 149 func (o *objectGoSlice) setOwnIdx(idx valueInt, val Value, throw bool) bool { 150 if i := toIntStrict(int64(idx)); i >= 0 { 151 if i >= len(*o.data) { 152 if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok { 153 return res 154 } 155 } 156 o.putIdx(i, val, throw) 157 } else { 158 name := idx.string() 159 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok { 160 o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name) 161 return false 162 } else { 163 return res 164 } 165 } 166 return true 167 } 168 169 func (o *objectGoSlice) setOwnStr(name unistring.String, val Value, throw bool) bool { 170 if idx := strToGoIdx(name); idx >= 0 { 171 if idx >= len(*o.data) { 172 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok { 173 return res 174 } 175 } 176 o.putIdx(idx, val, throw) 177 } else { 178 if name == "length" { 179 return o.putLength(o.val.runtime.toLengthUint32(val), throw) 180 } 181 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok { 182 o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name) 183 return false 184 } else { 185 return res 186 } 187 } 188 return true 189 } 190 191 func (o *objectGoSlice) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) { 192 return o._setForeignIdx(idx, trueValIfPresent(o.hasOwnPropertyIdx(idx)), val, receiver, throw) 193 } 194 195 func (o *objectGoSlice) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 196 return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw) 197 } 198 199 func (o *objectGoSlice) hasOwnPropertyIdx(idx valueInt) bool { 200 if idx := int64(idx); idx >= 0 { 201 return idx < int64(len(*o.data)) 202 } 203 return false 204 } 205 206 func (o *objectGoSlice) hasOwnPropertyStr(name unistring.String) bool { 207 if idx := strToIdx64(name); idx >= 0 { 208 return idx < int64(len(*o.data)) 209 } 210 return name == "length" 211 } 212 213 func (o *objectGoSlice) defineOwnPropertyIdx(idx valueInt, descr PropertyDescriptor, throw bool) bool { 214 if i := toIntStrict(int64(idx)); i >= 0 { 215 if !o.val.runtime.checkHostObjectPropertyDescr(idx.string(), descr, throw) { 216 return false 217 } 218 val := descr.Value 219 if val == nil { 220 val = _undefined 221 } 222 o.putIdx(i, val, throw) 223 return true 224 } 225 o.val.runtime.typeErrorResult(throw, "Cannot define property '%d' on a Go slice", idx) 226 return false 227 } 228 229 func (o *objectGoSlice) defineOwnPropertyStr(name unistring.String, descr PropertyDescriptor, throw bool) bool { 230 if idx := strToGoIdx(name); idx >= 0 { 231 if !o.val.runtime.checkHostObjectPropertyDescr(name, descr, throw) { 232 return false 233 } 234 val := descr.Value 235 if val == nil { 236 val = _undefined 237 } 238 o.putIdx(idx, val, throw) 239 return true 240 } 241 if name == "length" { 242 return o.val.runtime.defineArrayLength(&o.lengthProp, descr, o.putLength, throw) 243 } 244 o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name) 245 return false 246 } 247 248 func (o *objectGoSlice) _deleteIdx(idx int64) { 249 if idx < int64(len(*o.data)) { 250 (*o.data)[idx] = nil 251 } 252 } 253 254 func (o *objectGoSlice) deleteStr(name unistring.String, throw bool) bool { 255 if idx := strToIdx64(name); idx >= 0 { 256 o._deleteIdx(idx) 257 return true 258 } 259 return o.baseObject.deleteStr(name, throw) 260 } 261 262 func (o *objectGoSlice) deleteIdx(i valueInt, throw bool) bool { 263 idx := int64(i) 264 if idx >= 0 { 265 o._deleteIdx(idx) 266 } 267 return true 268 } 269 270 type goslicePropIter struct { 271 o *objectGoSlice 272 idx, limit int 273 } 274 275 func (i *goslicePropIter) next() (propIterItem, iterNextFunc) { 276 if i.idx < i.limit && i.idx < len(*i.o.data) { 277 name := strconv.Itoa(i.idx) 278 i.idx++ 279 return propIterItem{name: newStringValue(name), enumerable: _ENUM_TRUE}, i.next 280 } 281 282 return propIterItem{}, nil 283 } 284 285 func (o *objectGoSlice) iterateStringKeys() iterNextFunc { 286 return (&goslicePropIter{ 287 o: o, 288 limit: len(*o.data), 289 }).next 290 } 291 292 func (o *objectGoSlice) stringKeys(_ bool, accum []Value) []Value { 293 for i := range *o.data { 294 accum = append(accum, asciiString(strconv.Itoa(i))) 295 } 296 297 return accum 298 } 299 300 func (o *objectGoSlice) export(*objectExportCtx) interface{} { 301 if o.origIsPtr { 302 return o.data 303 } 304 return *o.data 305 } 306 307 func (o *objectGoSlice) exportType() reflect.Type { 308 if o.origIsPtr { 309 return reflectTypeArrayPtr 310 } 311 return reflectTypeArray 312 } 313 314 func (o *objectGoSlice) equal(other objectImpl) bool { 315 if other, ok := other.(*objectGoSlice); ok { 316 return o.data == other.data 317 } 318 return false 319 } 320 321 func (o *objectGoSlice) esValue() Value { 322 return o.val 323 } 324 325 func (o *objectGoSlice) reflectValue() reflect.Value { 326 return reflect.ValueOf(o.data).Elem() 327 } 328 329 func (o *objectGoSlice) setReflectValue(value reflect.Value) { 330 o.data = value.Addr().Interface().(*[]interface{}) 331 } 332 333 func (o *objectGoSlice) sortLen() int { 334 return len(*o.data) 335 } 336 337 func (o *objectGoSlice) sortGet(i int) Value { 338 return o.getIdx(valueInt(i), nil) 339 } 340 341 func (o *objectGoSlice) swap(i int, j int) { 342 (*o.data)[i], (*o.data)[j] = (*o.data)[j], (*o.data)[i] 343 }