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