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