github.com/goplusjs/reflectx@v0.5.4/reflectx.go (about)

     1  /*
     2   Copyright 2020 The GoPlus Authors (goplus.org)
     3  
     4   Licensed under the Apache License, Version 2.0 (the "License");
     5   you may not use this file except in compliance with the License.
     6   You may obtain a copy of the License at
     7  
     8       http://www.apache.org/licenses/LICENSE-2.0
     9  
    10   Unless required by applicable law or agreed to in writing, software
    11   distributed under the License is distributed on an "AS IS" BASIS,
    12   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   See the License for the specific language governing permissions and
    14   limitations under the License.
    15  */
    16  
    17  package reflectx
    18  
    19  import (
    20  	"path"
    21  	"reflect"
    22  	"strconv"
    23  	"unicode"
    24  	"unicode/utf8"
    25  	"unsafe"
    26  )
    27  
    28  func Field(s reflect.Value, i int) reflect.Value {
    29  	v := s.Field(i)
    30  	canSet(&v)
    31  	return v
    32  }
    33  
    34  func FieldByIndex(s reflect.Value, index []int) reflect.Value {
    35  	v := s.FieldByIndex(index)
    36  	canSet(&v)
    37  	return v
    38  }
    39  
    40  func FieldByName(s reflect.Value, name string) reflect.Value {
    41  	v := s.FieldByName(name)
    42  	canSet(&v)
    43  	return v
    44  }
    45  
    46  func FieldByNameFunc(s reflect.Value, match func(name string) bool) reflect.Value {
    47  	v := s.FieldByNameFunc(match)
    48  	canSet(&v)
    49  	return v
    50  }
    51  
    52  func canSet(v *reflect.Value) {
    53  	(*Value)(unsafe.Pointer(v)).flag &= ^flagRO
    54  }
    55  
    56  func CanSet(v reflect.Value) reflect.Value {
    57  	if !v.CanSet() {
    58  		(*Value)(unsafe.Pointer(&v)).flag &= ^flagRO
    59  	}
    60  	return v
    61  }
    62  
    63  func typeName(typ reflect.Type) string {
    64  	for typ.Kind() == reflect.Ptr {
    65  		typ = typ.Elem()
    66  	}
    67  	return typ.Name()
    68  }
    69  
    70  var (
    71  	ntypeMap = make(map[reflect.Type]*Named)
    72  )
    73  
    74  type TypeKind int
    75  
    76  const (
    77  	TkInvalid TypeKind = 1 << iota
    78  	TkType
    79  	TkMethod
    80  )
    81  
    82  type Named struct {
    83  	Name    string
    84  	PkgPath string
    85  	Type    reflect.Type
    86  	From    reflect.Type
    87  	Kind    TypeKind
    88  }
    89  
    90  func IsNamed(typ reflect.Type) bool {
    91  	_, ok := ntypeMap[typ]
    92  	return ok
    93  }
    94  
    95  func ToNamed(typ reflect.Type) (t *Named, ok bool) {
    96  	t, ok = ntypeMap[typ]
    97  	return
    98  }
    99  
   100  func NamedStructOf(pkgpath string, name string, fields []reflect.StructField) reflect.Type {
   101  	return NamedTypeOf(pkgpath, name, StructOf(fields))
   102  }
   103  
   104  func setTypeName(t *rtype, pkgpath string, name string) {
   105  	if pkgpath == "" && name == "" {
   106  		return
   107  	}
   108  	exported := isExported(name)
   109  	if pkgpath != "" {
   110  		_, f := path.Split(pkgpath)
   111  		name = f + "." + name
   112  	}
   113  	t.tflag |= tflagNamed | tflagExtraStar
   114  	t.str = resolveReflectName(newName("*"+name, "", exported))
   115  	if t.tflag&tflagUncommon == tflagUncommon {
   116  		toUncommonType(t).pkgPath = resolveReflectName(newName(pkgpath, "", false))
   117  	}
   118  	switch t.Kind() {
   119  	case reflect.Struct:
   120  		st := (*structType)(toKindType(t))
   121  		st.pkgPath = newName(pkgpath, "", false)
   122  	case reflect.Interface:
   123  		st := (*interfaceType)(toKindType(t))
   124  		st.pkgPath = newName(pkgpath, "", false)
   125  	}
   126  }
   127  
   128  func copyType(dst *rtype, src *rtype) {
   129  	dst.size = src.size
   130  	dst.kind = src.kind
   131  	dst.equal = src.equal
   132  	dst.align = src.align
   133  	dst.fieldAlign = src.fieldAlign
   134  	dst.tflag = src.tflag
   135  	dst.gcdata = src.gcdata
   136  	dst.ptrdata = src.ptrdata
   137  }
   138  
   139  func isExported(name string) bool {
   140  	ch, _ := utf8.DecodeRuneInString(name)
   141  	return unicode.IsUpper(ch)
   142  }
   143  
   144  var (
   145  	EnableStructOfExportAllField bool
   146  )
   147  
   148  var (
   149  	structLookupCache = make(map[string][]reflect.Type)
   150  )
   151  
   152  func checkFields(t1, t2 reflect.Type) bool {
   153  	n1 := t1.NumField()
   154  	n2 := t2.NumField()
   155  	if n1 != n2 {
   156  		return false
   157  	}
   158  	for i := 0; i < n1; i++ {
   159  		f1 := t1.Field(i)
   160  		f2 := t2.Field(i)
   161  		if f1.Name != f2.Name ||
   162  			f1.PkgPath != f2.PkgPath ||
   163  			f1.Anonymous != f2.Anonymous ||
   164  			f1.Type != f2.Type ||
   165  			f1.Offset != f2.Offset {
   166  			return false
   167  		}
   168  	}
   169  	return true
   170  }
   171  
   172  //go:linkname haveIdenticalType reflect.haveIdenticalType
   173  func haveIdenticalType(T, V reflect.Type, cmpTags bool) bool
   174  
   175  func StructOf(fields []reflect.StructField) reflect.Type {
   176  	var anonymous []int
   177  	underscore := make(map[int]name)
   178  	var underscoreCount int
   179  	fs := make([]reflect.StructField, len(fields))
   180  	for i := 0; i < len(fields); i++ {
   181  		f := fields[i]
   182  		if f.Anonymous {
   183  			anonymous = append(anonymous, i)
   184  			f.Anonymous = false
   185  			if f.Name == "" {
   186  				f.Name = typeName(f.Type)
   187  			}
   188  		} else if f.Name == "_" {
   189  			if underscoreCount > 0 {
   190  				underscore[i] = newName("_", string(f.Tag), false)
   191  				f.Name = "_gop_underscore_" + strconv.Itoa(i)
   192  			}
   193  			underscoreCount++
   194  		}
   195  		fs[i] = f
   196  	}
   197  	typ := reflect.StructOf(fs)
   198  	rt := totype(typ)
   199  	st := toStructType(rt)
   200  	for _, i := range anonymous {
   201  		st.fields[i].offsetEmbed |= 1
   202  	}
   203  	for i, n := range underscore {
   204  		st.fields[i].name = n
   205  	}
   206  	if EnableStructOfExportAllField {
   207  		for i := 0; i < len(fs); i++ {
   208  			f := fs[i]
   209  			st.fields[i].name = newName(f.Name, string(f.Tag), true)
   210  		}
   211  	}
   212  	str := typ.String()
   213  	if ts, ok := structLookupCache[str]; ok {
   214  		for _, t := range ts {
   215  			if haveIdenticalType(t, typ, true) {
   216  				return t
   217  			}
   218  		}
   219  		ts = append(ts, typ)
   220  	} else {
   221  		structLookupCache[str] = []reflect.Type{typ}
   222  	}
   223  	if isRegularMemory(typ) {
   224  		rt.tflag |= tflagRegularMemory
   225  	}
   226  	return typ
   227  }
   228  
   229  // fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
   230  func fnv1(x uint32, list string) uint32 {
   231  	for _, b := range list {
   232  		x = x*16777619 ^ uint32(b)
   233  	}
   234  	return x
   235  }
   236  
   237  func SetValue(v reflect.Value, x reflect.Value) {
   238  	switch v.Kind() {
   239  	case reflect.Bool:
   240  		v.SetBool(x.Bool())
   241  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   242  		v.SetInt(x.Int())
   243  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   244  		v.SetUint(x.Uint())
   245  	case reflect.Uintptr:
   246  		v.SetUint(x.Uint())
   247  	case reflect.Float32, reflect.Float64:
   248  		v.SetFloat(x.Float())
   249  	case reflect.Complex64, reflect.Complex128:
   250  		v.SetComplex(x.Complex())
   251  	case reflect.String:
   252  		v.SetString(x.String())
   253  	case reflect.UnsafePointer:
   254  		v.SetPointer(unsafe.Pointer(x.Pointer()))
   255  	default:
   256  		v.Set(x)
   257  	}
   258  }
   259  
   260  var (
   261  	tyEmptyInterface    = reflect.TypeOf((*interface{})(nil)).Elem()
   262  	tyEmptyInterfacePtr = reflect.TypeOf((*interface{})(nil))
   263  	tyEmptyStruct       = reflect.TypeOf((*struct{})(nil)).Elem()
   264  	tyErrorInterface    = reflect.TypeOf((*error)(nil)).Elem()
   265  )
   266  
   267  func SetElem(typ reflect.Type, elem reflect.Type) {
   268  	rt := totype(typ)
   269  	switch typ.Kind() {
   270  	case reflect.Ptr:
   271  		st := (*ptrType)(toKindType(rt))
   272  		st.elem = totype(elem)
   273  	case reflect.Slice:
   274  		st := (*sliceType)(toKindType(rt))
   275  		st.elem = totype(elem)
   276  	case reflect.Array:
   277  		st := (*arrayType)(toKindType(rt))
   278  		st.elem = totype(elem)
   279  	case reflect.Map:
   280  		st := (*mapType)(toKindType(rt))
   281  		st.elem = totype(elem)
   282  	case reflect.Chan:
   283  		st := (*chanType)(toKindType(rt))
   284  		st.elem = totype(elem)
   285  	default:
   286  		panic("reflect: Elem of invalid type " + typ.String())
   287  	}
   288  }
   289  
   290  func typeId(typ reflect.Type) string {
   291  	var id string
   292  	if path := typ.PkgPath(); path != "" {
   293  		id = path + "."
   294  	}
   295  	return id + typ.Name()
   296  }
   297  
   298  type replaceTypeContext struct {
   299  	checking map[reflect.Type]bool
   300  }
   301  
   302  func ReplaceType(pkg string, typ reflect.Type, m map[string]reflect.Type) (rtyp reflect.Type, changed bool) {
   303  	ctx := &replaceTypeContext{make(map[reflect.Type]bool)}
   304  	return ctx.replace(pkg, typ, m)
   305  }
   306  
   307  func (ctx *replaceTypeContext) replace(pkg string, typ reflect.Type, m map[string]reflect.Type) (rtyp reflect.Type, changed bool) {
   308  	if ctx.checking[typ] {
   309  		return
   310  	}
   311  	ctx.checking[typ] = true
   312  	rt := totype(typ)
   313  	switch typ.Kind() {
   314  	case reflect.Struct:
   315  		if typ.PkgPath() != pkg {
   316  			return
   317  		}
   318  		st := (*structType)(toKindType(rt))
   319  		for i := 0; i < len(st.fields); i++ {
   320  			et := toType(st.fields[i].typ)
   321  			if t, ok := m[typeId(et)]; ok {
   322  				st.fields[i].typ = totype(t)
   323  				changed = true
   324  			} else {
   325  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   326  					changed = true
   327  					st.fields[i].typ = totype(rtyp)
   328  				}
   329  			}
   330  		}
   331  		if changed {
   332  			return toType(rt), true
   333  		}
   334  	case reflect.Ptr:
   335  		st := (*ptrType)(toKindType(rt))
   336  		et := toType(st.elem)
   337  		if t, ok := m[typeId(et)]; ok {
   338  			st.elem = totype(t)
   339  			return reflect.PtrTo(t), true
   340  		} else {
   341  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   342  				return reflect.PtrTo(rtyp), true
   343  			}
   344  		}
   345  	case reflect.Slice:
   346  		st := (*sliceType)(toKindType(rt))
   347  		et := toType(st.elem)
   348  		if t, ok := m[typeId(et)]; ok {
   349  			st.elem = totype(t)
   350  			return reflect.SliceOf(t), true
   351  		} else {
   352  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   353  				return reflect.SliceOf(rtyp), true
   354  			}
   355  		}
   356  	case reflect.Array:
   357  		st := (*arrayType)(toKindType(rt))
   358  		et := toType(st.elem)
   359  		if t, ok := m[typeId(et)]; ok {
   360  			st.elem = totype(t)
   361  			return reflect.ArrayOf(int(st.len), t), true
   362  		} else {
   363  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   364  				return reflect.ArrayOf(int(st.len), rtyp), true
   365  			}
   366  		}
   367  	case reflect.Map:
   368  		st := (*mapType)(toKindType(rt))
   369  		kt := toType(st.key)
   370  		et := toType(st.elem)
   371  		if t, ok := m[typeId(kt)]; ok {
   372  			kt = t
   373  			changed = true
   374  		} else {
   375  			if rtyp, ok := ctx.replace(pkg, kt, m); ok {
   376  				kt = rtyp
   377  				changed = true
   378  			}
   379  		}
   380  		if t, ok := m[typeId(et)]; ok {
   381  			et = t
   382  			changed = true
   383  		} else {
   384  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   385  				et = rtyp
   386  				changed = true
   387  			}
   388  		}
   389  		if changed {
   390  			return reflect.MapOf(kt, et), true
   391  		}
   392  	case reflect.Chan:
   393  		st := (*chanType)(toKindType(rt))
   394  		et := toType(st.elem)
   395  		if t, ok := m[typeId(et)]; ok {
   396  			st.elem = totype(t)
   397  			return reflect.ChanOf(typ.ChanDir(), t), true
   398  		} else {
   399  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   400  				return reflect.ChanOf(typ.ChanDir(), rtyp), true
   401  			}
   402  		}
   403  	case reflect.Func:
   404  		st := (*funcType)(toKindType(rt))
   405  		in := st.in()
   406  		out := st.out()
   407  		for i := 0; i < len(in); i++ {
   408  			et := toType(in[i])
   409  			if t, ok := m[typeId(et)]; ok {
   410  				in[i] = totype(t)
   411  				changed = true
   412  			} else {
   413  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   414  					in[i] = totype(rtyp)
   415  					changed = true
   416  				}
   417  			}
   418  		}
   419  		for i := 0; i < len(out); i++ {
   420  			et := toType(out[i])
   421  			if t, ok := m[typeId(et)]; ok {
   422  				out[i] = totype(t)
   423  				changed = true
   424  			} else {
   425  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   426  					out[i] = totype(rtyp)
   427  					changed = true
   428  				}
   429  			}
   430  		}
   431  		if changed {
   432  			ins := make([]reflect.Type, len(in))
   433  			for i := 0; i < len(in); i++ {
   434  				ins[i] = toType(in[i])
   435  			}
   436  			outs := make([]reflect.Type, len(out))
   437  			for i := 0; i < len(out); i++ {
   438  				outs[i] = toType(out[i])
   439  			}
   440  			return reflect.FuncOf(ins, outs, typ.IsVariadic()), true
   441  		}
   442  	case reflect.Interface:
   443  		if typ.PkgPath() != pkg {
   444  			return
   445  		}
   446  		if typ == tyErrorInterface {
   447  			return
   448  		}
   449  		st := (*interfaceType)(toKindType(rt))
   450  		for i := 0; i < len(st.methods); i++ {
   451  			tt := typ.Method(i).Type
   452  			if t, ok := m[typeId(tt)]; ok {
   453  				st.methods[i].typ = resolveReflectType(totype(t))
   454  				changed = true
   455  			} else if rtyp, ok := ctx.replace(pkg, tt, m); ok {
   456  				st.methods[i].typ = resolveReflectType(totype(rtyp))
   457  				changed = true
   458  			}
   459  		}
   460  		if changed {
   461  			return toType(rt), true
   462  		}
   463  	}
   464  	return nil, false
   465  }
   466  
   467  // go/src/cmd/compile/internal/gc/alg.go#algtype1
   468  // IsRegularMemory reports whether t can be compared/hashed as regular memory.
   469  func isRegularMemory(t reflect.Type) bool {
   470  	switch t.Kind() {
   471  	case reflect.Func, reflect.Map, reflect.Slice, reflect.String, reflect.Interface:
   472  		return false
   473  	case reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128:
   474  		return false
   475  	case reflect.Array:
   476  		b := isRegularMemory(t.Elem())
   477  		if b {
   478  			return true
   479  		}
   480  		if t.Len() == 0 {
   481  			return true
   482  		}
   483  		return b
   484  	case reflect.Struct:
   485  		n := t.NumField()
   486  		switch n {
   487  		case 0:
   488  			return true
   489  		case 1:
   490  			f := t.Field(0)
   491  			if f.Name == "_" {
   492  				return false
   493  			}
   494  			return isRegularMemory(f.Type)
   495  		default:
   496  			for i := 0; i < n; i++ {
   497  				f := t.Field(i)
   498  				if f.Name == "_" || !isRegularMemory(f.Type) || ispaddedfield(t, i) {
   499  					return false
   500  				}
   501  			}
   502  		}
   503  	}
   504  	return true
   505  }
   506  
   507  // ispaddedfield reports whether the i'th field of struct type t is followed
   508  // by padding.
   509  func ispaddedfield(t reflect.Type, i int) bool {
   510  	end := t.Size()
   511  	if i+1 < t.NumField() {
   512  		end = t.Field(i + 1).Offset
   513  	}
   514  	fd := t.Field(i)
   515  	return fd.Offset+fd.Type.Size() != end
   516  }