github.com/goplus/reflectx@v1.2.2/rtype_js.go (about) 1 //go:build js && !wasm 2 // +build js,!wasm 3 4 package reflectx 5 6 import ( 7 "reflect" 8 "unsafe" 9 10 "github.com/gopherjs/gopherjs/js" 11 ) 12 13 //go:linkname reflectType reflect.reflectType 14 func reflectType(typ *js.Object) *rtype 15 16 //go:linkname setKindType reflect.setKindType 17 func setKindType(rt *rtype, kindType interface{}) 18 19 //go:linkname newNameOff reflect.newNameOff 20 func newNameOff(n name) nameOff 21 22 //go:linkname newTypeOff reflect.newTypeOff 23 func newTypeOff(rt *rtype) typeOff 24 25 //go:linkname makeValue reflect.makeValue 26 func makeValue(t *rtype, v *js.Object, fl flag) reflect.Value 27 28 func toStructType(t *rtype) *structType { 29 kind := js.InternalObject(t).Get("kindType") 30 return (*structType)(unsafe.Pointer(kind.Unsafe())) 31 } 32 33 func toKindType(t *rtype) unsafe.Pointer { 34 return unsafe.Pointer(js.InternalObject(t).Get("kindType").Unsafe()) 35 } 36 37 func toUncommonType(t *rtype) *uncommonType { 38 kind := js.InternalObject(t).Get("uncommonType") 39 if kind == js.Undefined { 40 return nil 41 } 42 return (*uncommonType)(unsafe.Pointer(kind.Unsafe())) 43 } 44 45 type uncommonType struct { 46 pkgPath nameOff 47 mcount uint16 48 xcount uint16 49 moff uint32 50 51 _methods []method 52 } 53 54 func (t *uncommonType) exportedMethods() []method { 55 if t.xcount == 0 { 56 return nil 57 } 58 return t._methods[:t.xcount:t.xcount] 59 } 60 61 func (t *uncommonType) methods() []method { 62 if t.mcount == 0 { 63 return nil 64 } 65 return t._methods 66 } 67 68 func (t *rtype) ptrTo() *rtype { 69 return reflectType(js.Global.Call("$ptrType", jsType(t))) 70 } 71 72 //go:linkename rtype_uncommon reflect.(*rtype).uncommon 73 func rtype_uncommon(*rtype) *uncommonType 74 75 //go:linkename rtype_methods reflect.(*rtype).methods 76 func rtype_methods(*rtype) []method 77 78 func (t *rtype) uncommon() *uncommonType { 79 return rtype_uncommon(t) 80 } 81 82 func (t *rtype) exportedMethods() []method { 83 ut := t.uncommon() 84 if ut == nil { 85 return nil 86 } 87 return ut.exportedMethods() 88 } 89 90 func (t *rtype) methods() []method { 91 ut := t.uncommon() 92 if ut == nil { 93 return nil 94 } 95 return ut._methods 96 } 97 98 func (t *rtype) IsVariadic() bool { 99 if t.Kind() != reflect.Func { 100 panic("reflect: IsVariadic of non-func type " + toType(t).String()) 101 } 102 tt := (*funcType)(unsafe.Pointer(t)) 103 return tt.outCount&(1<<15) != 0 104 } 105 106 /* 107 var $kindBool = 1; 108 var $kindInt = 2; 109 var $kindInt8 = 3; 110 var $kindInt16 = 4; 111 var $kindInt32 = 5; 112 var $kindInt64 = 6; 113 var $kindUint = 7; 114 var $kindUint8 = 8; 115 var $kindUint16 = 9; 116 var $kindUint32 = 10; 117 var $kindUint64 = 11; 118 var $kindUintptr = 12; 119 var $kindFloat32 = 13; 120 var $kindFloat64 = 14; 121 var $kindComplex64 = 15; 122 var $kindComplex128 = 16; 123 var $kindArray = 17; 124 var $kindChan = 18; 125 var $kindFunc = 19; 126 var $kindInterface = 20; 127 var $kindMap = 21; 128 var $kindPtr = 22; 129 var $kindSlice = 23; 130 var $kindString = 24; 131 var $kindStruct = 25; 132 var $kindUnsafePointer = 26; 133 134 var $Bool = $newType( 1, $kindBool, "bool", true, "", false, null); 135 var $Int = $newType( 4, $kindInt, "int", true, "", false, null); 136 var $Int8 = $newType( 1, $kindInt8, "int8", true, "", false, null); 137 var $Int16 = $newType( 2, $kindInt16, "int16", true, "", false, null); 138 var $Int32 = $newType( 4, $kindInt32, "int32", true, "", false, null); 139 var $Int64 = $newType( 8, $kindInt64, "int64", true, "", false, null); 140 var $Uint = $newType( 4, $kindUint, "uint", true, "", false, null); 141 var $Uint8 = $newType( 1, $kindUint8, "uint8", true, "", false, null); 142 var $Uint16 = $newType( 2, $kindUint16, "uint16", true, "", false, null); 143 var $Uint32 = $newType( 4, $kindUint32, "uint32", true, "", false, null); 144 var $Uint64 = $newType( 8, $kindUint64, "uint64", true, "", false, null); 145 var $Uintptr = $newType( 4, $kindUintptr, "uintptr", true, "", false, null); 146 var $Float32 = $newType( 4, $kindFloat32, "float32", true, "", false, null); 147 var $Float64 = $newType( 8, $kindFloat64, "float64", true, "", false, null); 148 var $Complex64 = $newType( 8, $kindComplex64, "complex64", true, "", false, null); 149 var $Complex128 = $newType(16, $kindComplex128, "complex128", true, "", false, null); 150 var $String = $newType( 8, $kindString, "string", true, "", false, null); 151 var $UnsafePointer = $newType( 4, $kindUnsafePointer, "unsafe.Pointer", true, "", false, null); 152 */ 153 //var $newType = function(size, kind, string, named, pkg, exported, constructor) { 154 155 var ( 156 fnNewType = js.Global.Get("$newType") 157 ) 158 159 /* 160 Invalid Kind = iota 161 Bool 162 Int 163 Int8 164 Int16 165 Int32 166 Int64 167 Uint 168 Uint8 169 Uint16 170 Uint32 171 Uint64 172 Uintptr 173 Float32 174 Float64 175 Complex64 176 Complex128 177 Array 178 Chan 179 Func 180 Interface 181 Map 182 Ptr 183 Slice 184 String 185 Struct 186 UnsafePointer 187 */ 188 189 func tovalue(v *reflect.Value) *Value { 190 return (*Value)(unsafe.Pointer(v)) 191 } 192 193 func toValue(v Value) reflect.Value { 194 return *(*reflect.Value)(unsafe.Pointer(&v)) 195 } 196 197 func NamedTypeOf(pkg string, name string, from reflect.Type) (typ reflect.Type) { 198 rt, _ := newType(pkg, name, from, 0, 0) 199 setTypeName(rt, pkg, name) 200 return toType(rt) 201 } 202 203 var ( 204 jsUncommonTyp = js.InternalObject(reflect.TypeOf((*rtype)(nil))).Get("uncommonType").Get("constructor") 205 ) 206 207 func resetUncommonType(rt *rtype, mcount int, xcount int) *uncommonType { 208 ut := jsUncommonTyp.New() 209 v := js.InternalObject(ut).Get("_methods").Get("constructor") 210 ut.Set("xcount", xcount) 211 ut.Set("mcount", mcount) 212 ut.Set("_methods", js.Global.Call("$makeSlice", v, mcount, mcount)) 213 ut.Set("jsType", jsType(rt)) 214 js.InternalObject(rt).Set("uncommonType", ut) 215 return (*uncommonType)(unsafe.Pointer(ut.Unsafe())) 216 } 217 218 func newType(pkg string, name string, styp reflect.Type, xcount int, mcount int) (*rtype, []method) { 219 kind := styp.Kind() 220 var obj *js.Object 221 switch kind { 222 default: 223 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 224 case reflect.Array: 225 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 226 obj.Call("init", jsType(styp.Elem()), styp.Len()) 227 case reflect.Slice: 228 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 229 obj.Call("init", jsType(styp.Elem())) 230 case reflect.Map: 231 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 232 obj.Call("init", jsType(styp.Key()), jsType(styp.Elem())) 233 case reflect.Ptr: 234 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 235 obj.Call("init", jsType(styp.Elem())) 236 case reflect.Chan: 237 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 238 obj.Call("init", jsType(styp.Elem())) 239 case reflect.Func: 240 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 241 obj.Call("init", jsType(styp).Get("params"), jsType(styp).Get("results"), styp.IsVariadic()) 242 case reflect.Interface: 243 obj = fnNewType.Invoke(styp.Size(), kind, name, true, pkg, false, nil) 244 obj.Call("init", jsType(styp).Get("methods")) 245 case reflect.Struct: 246 n := styp.NumField() 247 fields := js.Global.Get("Array").New(n) 248 for i := 0; i < n; i++ { 249 sf := styp.Field(i) 250 jsf := js.Global.Get("Object").New() 251 jsf.Set("prop", sf.Name) 252 jsf.Set("name", sf.Name) 253 jsf.Set("exported", true) 254 jsf.Set("typ", jsType(sf.Type)) 255 jsf.Set("tag", sf.Tag) 256 jsf.Set("embedded", sf.Anonymous) 257 fields.SetIndex(i, jsf) 258 } 259 fn := js.MakeFunc(func(this *js.Object, args []*js.Object) interface{} { 260 this.Set("$val", this) 261 for i := 0; i < fields.Length(); i++ { 262 f := fields.Index(i) 263 if len(args) > i && args[i] != js.Undefined { 264 this.Set(f.Get("prop").String(), args[i]) 265 } else { 266 this.Set(f.Get("prop").String(), f.Get("typ").Call("zero")) 267 } 268 } 269 return nil 270 }) 271 obj = fnNewType.Invoke(styp.Size(), kind, styp.Name(), false, pkg, false, fn) 272 obj.Call("init", pkg, fields) 273 } 274 rt := reflectType(obj) 275 if kind == reflect.Func || kind == reflect.Interface { 276 return rt, nil 277 } 278 rt.tflag |= tflagUncommon 279 ut := resetUncommonType(rt, xcount, mcount) 280 return rt, ut._methods 281 } 282 283 func totype(typ reflect.Type) *rtype { 284 v := reflect.Zero(typ) 285 rt := (*Value)(unsafe.Pointer(&v)).typ 286 return rt 287 } 288 289 type funcType struct { 290 rtype `reflect:"func"` 291 inCount uint16 292 outCount uint16 293 294 _in []*rtype 295 _out []*rtype 296 } 297 298 func (t *funcType) in() []*rtype { 299 return t._in 300 } 301 302 func (t *funcType) out() []*rtype { 303 return t._out 304 } 305 306 func jsType(typ interface{}) *js.Object { 307 return js.InternalObject(typ).Get("jsType") 308 } 309 310 func NumMethodX(typ reflect.Type) int { 311 t := totype(typ) 312 if t.tflag == 0 { 313 return 0 314 } 315 ut := t.uncommon() 316 if ut == nil { 317 return 0 318 } 319 return len(ut.methods()) 320 } 321 322 func MethodX(typ reflect.Type, i int) (m reflect.Method) { 323 if typ.Kind() == reflect.Interface { 324 return typ.Method(i) 325 } 326 t := totype(typ) 327 ut := t.uncommon() 328 methods := ut.methods() 329 if i < 0 || i >= len(methods) { 330 panic("reflect: Method index out of range") 331 } 332 p := methods[i] 333 pname := t.nameOff(p.name) 334 m.Name = pname.name() 335 fl := flag(reflect.Func) 336 mtyp := t.typeOff(p.mtyp) 337 ft := (*funcType)(toKindType(mtyp)) 338 in := make([]reflect.Type, 0, 1+len(ft.in())) 339 in = append(in, toType(t)) 340 for _, arg := range ft.in() { 341 in = append(in, toType(arg)) 342 } 343 out := make([]reflect.Type, 0, len(ft.out())) 344 for _, ret := range ft.out() { 345 out = append(out, toType(ret)) 346 } 347 mt := reflect.FuncOf(in, out, ft.IsVariadic()) 348 m.Type = mt 349 prop := js.Global.Call("$methodSet", js.InternalObject(t).Get("jsType")).Index(i).Get("prop").String() 350 fn := js.MakeFunc(func(this *js.Object, arguments []*js.Object) interface{} { 351 rcvr := arguments[0] 352 return rcvr.Get(prop).Call("apply", rcvr, arguments[1:]) 353 }) 354 m.Func = toValue(Value{totype(mt), unsafe.Pointer(fn.Unsafe()), fl}) 355 m.Index = i 356 return m 357 } 358 359 func MethodByNameX(typ reflect.Type, name string) (m reflect.Method, ok bool) { 360 if typ.Kind() == reflect.Interface { 361 return typ.MethodByName(name) 362 } 363 t := totype(typ) 364 ut := t.uncommon() 365 if ut == nil { 366 return reflect.Method{}, false 367 } 368 for i, p := range ut.methods() { 369 if t.nameOff(p.name).name() == name { 370 return MethodX(typ, i), true 371 } 372 } 373 return reflect.Method{}, false 374 } 375 376 // Field returns the i'th field of the struct v. 377 // It panics if v's Kind is not Struct or i is out of range. 378 func FieldX(v reflect.Value, i int) reflect.Value { 379 field := v.Field(i) 380 canSet(&field) 381 return field 382 } 383 384 func SetUnderlying(typ reflect.Type, styp reflect.Type) { 385 rt := totype(typ) 386 ort := totype(styp) 387 switch styp.Kind() { 388 case reflect.Struct: 389 st := (*structType)(toKindType(rt)) 390 ost := (*structType)(toKindType(ort)) 391 st.fields = ost.fields 392 obj := jsType(rt) 393 fields := obj.Get("fields") 394 n := styp.NumField() 395 for i := 0; i < n; i++ { 396 sf := styp.Field(i) 397 jsf := fields.Index(i) 398 jsf.Set("prop", sf.Name) 399 jsf.Set("name", sf.Name) 400 jsf.Set("typ", jsType(sf.Type)) 401 } 402 case reflect.Ptr: 403 st := (*ptrType)(toKindType(rt)) 404 ost := (*ptrType)(toKindType(ort)) 405 st.elem = ost.elem 406 case reflect.Slice: 407 st := (*sliceType)(toKindType(rt)) 408 ost := (*sliceType)(toKindType(ort)) 409 st.elem = ost.elem 410 case reflect.Array: 411 st := (*arrayType)(toKindType(rt)) 412 ost := (*arrayType)(toKindType(ort)) 413 st.elem = ost.elem 414 st.slice = ost.slice 415 st.len = ost.len 416 case reflect.Chan: 417 st := (*chanType)(toKindType(rt)) 418 ost := (*chanType)(toKindType(ort)) 419 st.elem = ost.elem 420 st.dir = ost.dir 421 case reflect.Interface: 422 st := (*interfaceType)(toKindType(rt)) 423 ost := (*interfaceType)(toKindType(ort)) 424 st.methods = ost.methods 425 case reflect.Map: 426 st := (*mapType)(toKindType(rt)) 427 ost := (*mapType)(toKindType(ort)) 428 st.key = ost.key 429 st.elem = ost.elem 430 st.bucket = ost.bucket 431 st.hasher = ost.hasher 432 st.keysize = ost.keysize 433 st.valuesize = ost.valuesize 434 st.bucketsize = ost.bucketsize 435 st.flags = ost.flags 436 case reflect.Func: 437 st := (*funcType)(toKindType(rt)) 438 ost := (*funcType)(toKindType(ort)) 439 st.inCount = ost.inCount 440 st.outCount = ost.outCount 441 st._in = ost._in 442 st._out = ost._out 443 } 444 rt.size = ort.size 445 rt.tflag |= tflagUncommon | tflagExtraStar | tflagNamed 446 rt.kind = ort.kind 447 rt.align = ort.align 448 rt.fieldAlign = ort.fieldAlign 449 rt.gcdata = ort.gcdata 450 rt.ptrdata = ort.ptrdata 451 rt.equal = ort.equal 452 //rt.str = resolveReflectName(ort.nameOff(ort.str)) 453 if isRegularMemory(typ) { 454 rt.tflag |= tflagRegularMemory 455 } 456 }