1package goja 2 3import ( 4 "reflect" 5 "strconv" 6 7 "github.com/dop251/goja/unistring" 8) 9 10type objectGoSliceReflect struct { 11 objectGoReflect 12 lengthProp valueProperty 13} 14 15func (o *objectGoSliceReflect) init() { 16 o.objectGoReflect.init() 17 o.class = classArray 18 o.prototype = o.val.runtime.global.ArrayPrototype 19 if !o.value.CanSet() { 20 value := reflect.Indirect(reflect.New(o.value.Type())) 21 value.Set(o.value) 22 o.value = value 23 } 24 o.lengthProp.writable = true 25 o.updateLen() 26 o.baseObject._put("length", &o.lengthProp) 27} 28 29func (o *objectGoSliceReflect) updateLen() { 30 o.lengthProp.value = intToValue(int64(o.value.Len())) 31} 32 33func (o *objectGoSliceReflect) _hasIdx(idx valueInt) bool { 34 if idx := int64(idx); idx >= 0 && idx < int64(o.value.Len()) { 35 return true 36 } 37 return false 38} 39 40func (o *objectGoSliceReflect) _hasStr(name unistring.String) bool { 41 if idx := strToIdx64(name); idx >= 0 && idx < int64(o.value.Len()) { 42 return true 43 } 44 return false 45} 46 47func (o *objectGoSliceReflect) _getIdx(idx int) Value { 48 v := o.value.Index(idx) 49 if (v.Kind() == reflect.Ptr || v.Kind() == reflect.Interface) && v.IsNil() { 50 return _null 51 } 52 return o.val.runtime.ToValue(v.Interface()) 53} 54 55func (o *objectGoSliceReflect) getIdx(idx valueInt, receiver Value) Value { 56 if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.value.Len() { 57 return o._getIdx(idx) 58 } 59 return o.objectGoReflect.getStr(idx.string(), receiver) 60} 61 62func (o *objectGoSliceReflect) getStr(name unistring.String, receiver Value) Value { 63 var ownProp Value 64 if idx := strToGoIdx(name); idx >= 0 && idx < o.value.Len() { 65 ownProp = o._getIdx(idx) 66 } else if name == "length" { 67 ownProp = &o.lengthProp 68 } else { 69 ownProp = o.objectGoReflect.getOwnPropStr(name) 70 } 71 return o.getStrWithOwnProp(ownProp, name, receiver) 72} 73 74func (o *objectGoSliceReflect) getOwnPropStr(name unistring.String) Value { 75 if idx := strToGoIdx(name); idx >= 0 { 76 if idx < o.value.Len() { 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 o.objectGoReflect.getOwnPropStr(name) 89} 90 91func (o *objectGoSliceReflect) getOwnPropIdx(idx valueInt) Value { 92 if idx := toIntStrict(int64(idx)); idx >= 0 && idx < o.value.Len() { 93 return &valueProperty{ 94 value: o._getIdx(idx), 95 writable: true, 96 enumerable: true, 97 } 98 } 99 return nil 100} 101 102func (o *objectGoSliceReflect) putIdx(idx int, v Value, throw bool) bool { 103 if idx >= o.value.Len() { 104 o.grow(idx + 1) 105 } 106 err := o.val.runtime.toReflectValue(v, o.value.Index(idx), &objectExportCtx{}) 107 if err != nil { 108 o.val.runtime.typeErrorResult(throw, "Go type conversion error: %v", err) 109 return false 110 } 111 return true 112} 113 114func (o *objectGoSliceReflect) grow(size int) { 115 oldcap := o.value.Cap() 116 if oldcap < size { 117 n := reflect.MakeSlice(o.value.Type(), size, growCap(size, o.value.Len(), oldcap)) 118 reflect.Copy(n, o.value) 119 o.value.Set(n) 120 } else { 121 tail := o.value.Slice(o.value.Len(), size) 122 zero := reflect.Zero(o.value.Type().Elem()) 123 for i := 0; i < tail.Len(); i++ { 124 tail.Index(i).Set(zero) 125 } 126 o.value.SetLen(size) 127 } 128 o.updateLen() 129} 130 131func (o *objectGoSliceReflect) shrink(size int) { 132 tail := o.value.Slice(size, o.value.Len()) 133 zero := reflect.Zero(o.value.Type().Elem()) 134 for i := 0; i < tail.Len(); i++ { 135 tail.Index(i).Set(zero) 136 } 137 o.value.SetLen(size) 138 o.updateLen() 139} 140 141func (o *objectGoSliceReflect) putLength(v Value, throw bool) bool { 142 newLen := toIntStrict(toLength(v)) 143 curLen := o.value.Len() 144 if newLen > curLen { 145 o.grow(newLen) 146 } else if newLen < curLen { 147 o.shrink(newLen) 148 } 149 return true 150} 151 152func (o *objectGoSliceReflect) setOwnIdx(idx valueInt, val Value, throw bool) bool { 153 if i := toIntStrict(int64(idx)); i >= 0 { 154 if i >= o.value.Len() { 155 if res, ok := o._setForeignIdx(idx, nil, val, o.val, throw); ok { 156 return res 157 } 158 } 159 o.putIdx(i, val, throw) 160 } else { 161 name := idx.string() 162 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok { 163 o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name) 164 return false 165 } else { 166 return res 167 } 168 } 169 return true 170} 171 172func (o *objectGoSliceReflect) setOwnStr(name unistring.String, val Value, throw bool) bool { 173 if idx := strToGoIdx(name); idx >= 0 { 174 if idx >= o.value.Len() { 175 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); ok { 176 return res 177 } 178 } 179 o.putIdx(idx, val, throw) 180 } else { 181 if name == "length" { 182 return o.putLength(val, throw) 183 } 184 if res, ok := o._setForeignStr(name, nil, val, o.val, throw); !ok { 185 o.val.runtime.typeErrorResult(throw, "Can't set property '%s' on Go slice", name) 186 return false 187 } else { 188 return res 189 } 190 } 191 return true 192} 193 194func (o *objectGoSliceReflect) setForeignIdx(idx valueInt, val, receiver Value, throw bool) (bool, bool) { 195 return o._setForeignIdx(idx, trueValIfPresent(o._hasIdx(idx)), val, receiver, throw) 196} 197 198func (o *objectGoSliceReflect) setForeignStr(name unistring.String, val, receiver Value, throw bool) (bool, bool) { 199 return o._setForeignStr(name, trueValIfPresent(o.hasOwnPropertyStr(name)), val, receiver, throw) 200} 201 202func (o *objectGoSliceReflect) hasOwnPropertyIdx(idx valueInt) bool { 203 return o._hasIdx(idx) 204} 205 206func (o *objectGoSliceReflect) hasOwnPropertyStr(name unistring.String) bool { 207 if o._hasStr(name) || name == "length" { 208 return true 209 } 210 return o.objectGoReflect._has(name.String()) 211} 212 213func (o *objectGoSliceReflect) 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 229func (o *objectGoSliceReflect) 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 o.val.runtime.typeErrorResult(throw, "Cannot define property '%s' on a Go slice", name) 242 return false 243} 244 245func (o *objectGoSliceReflect) toPrimitiveNumber() Value { 246 return o.toPrimitiveString() 247} 248 249func (o *objectGoSliceReflect) toPrimitiveString() Value { 250 return o.val.runtime.arrayproto_join(FunctionCall{ 251 This: o.val, 252 }) 253} 254 255func (o *objectGoSliceReflect) toPrimitive() Value { 256 return o.toPrimitiveString() 257} 258 259func (o *objectGoSliceReflect) _deleteIdx(idx int) { 260 if idx < o.value.Len() { 261 o.value.Index(idx).Set(reflect.Zero(o.value.Type().Elem())) 262 } 263} 264 265func (o *objectGoSliceReflect) deleteStr(name unistring.String, throw bool) bool { 266 if idx := strToGoIdx(name); idx >= 0 { 267 o._deleteIdx(idx) 268 return true 269 } 270 271 return o.objectGoReflect.deleteStr(name, throw) 272} 273 274func (o *objectGoSliceReflect) deleteIdx(i valueInt, throw bool) bool { 275 idx := toIntStrict(int64(i)) 276 if idx >= 0 { 277 o._deleteIdx(idx) 278 } 279 return true 280} 281 282type gosliceReflectPropIter struct { 283 o *objectGoSliceReflect 284 idx, limit int 285} 286 287func (i *gosliceReflectPropIter) next() (propIterItem, iterNextFunc) { 288 if i.idx < i.limit && i.idx < i.o.value.Len() { 289 name := strconv.Itoa(i.idx) 290 i.idx++ 291 return propIterItem{name: unistring.String(name), enumerable: _ENUM_TRUE}, i.next 292 } 293 294 return i.o.objectGoReflect.enumerateOwnKeys()() 295} 296 297func (o *objectGoSliceReflect) ownKeys(all bool, accum []Value) []Value { 298 for i := 0; i < o.value.Len(); i++ { 299 accum = append(accum, asciiString(strconv.Itoa(i))) 300 } 301 302 return o.objectGoReflect.ownKeys(all, accum) 303} 304 305func (o *objectGoSliceReflect) enumerateOwnKeys() iterNextFunc { 306 return (&gosliceReflectPropIter{ 307 o: o, 308 limit: o.value.Len(), 309 }).next 310} 311 312func (o *objectGoSliceReflect) equal(other objectImpl) bool { 313 if other, ok := other.(*objectGoSliceReflect); ok { 314 return o.value.Interface() == other.value.Interface() 315 } 316 return false 317} 318 319func (o *objectGoSliceReflect) sortLen() int64 { 320 return int64(o.value.Len()) 321} 322 323func (o *objectGoSliceReflect) sortGet(i int64) Value { 324 return o.getIdx(valueInt(i), nil) 325} 326 327func (o *objectGoSliceReflect) swap(i, j int64) { 328 ii := valueInt(i) 329 jj := valueInt(j) 330 x := o.getIdx(ii, nil) 331 y := o.getIdx(jj, nil) 332 333 o.setOwnIdx(ii, y, false) 334 o.setOwnIdx(jj, x, false) 335} 336