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  }