github.com/goplus/reflectx@v1.2.2/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  func NamedStructOf(pkgpath string, name string, fields []reflect.StructField) reflect.Type {
    71  	return Default.NamedStructOf(pkgpath, name, fields)
    72  }
    73  
    74  func (ctx *Context) NamedStructOf(pkgpath string, name string, fields []reflect.StructField) reflect.Type {
    75  	return NamedTypeOf(pkgpath, name, ctx.StructOf(fields))
    76  }
    77  
    78  func SetTypeName(typ reflect.Type, pkgpath string, name string) {
    79  	setTypeName(totype(typ), pkgpath, name)
    80  }
    81  
    82  func setTypeName(t *rtype, pkgpath string, name string) {
    83  	if pkgpath == "" && name == "" {
    84  		return
    85  	}
    86  	exported := isExported(name)
    87  	if pkgpath != "" {
    88  		_, f := path.Split(pkgpath)
    89  		name = f + "." + name
    90  	}
    91  	t.tflag |= tflagNamed | tflagExtraStar
    92  	t.str = resolveReflectName(newName("*"+name, "", exported))
    93  	if t.tflag&tflagUncommon == tflagUncommon {
    94  		toUncommonType(t).pkgPath = resolveReflectName(newName(pkgpath, "", false))
    95  	}
    96  	switch t.Kind() {
    97  	case reflect.Struct:
    98  		st := (*structType)(toKindType(t))
    99  		st.pkgPath = newName(pkgpath, "", false)
   100  	case reflect.Interface:
   101  		st := (*interfaceType)(toKindType(t))
   102  		st.pkgPath = newName(pkgpath, "", false)
   103  	}
   104  }
   105  
   106  func copyType(dst *rtype, src *rtype) {
   107  	dst.size = src.size
   108  	dst.kind = src.kind
   109  	dst.equal = src.equal
   110  	dst.align = src.align
   111  	dst.fieldAlign = src.fieldAlign
   112  	dst.tflag = src.tflag
   113  	dst.gcdata = src.gcdata
   114  	dst.ptrdata = src.ptrdata
   115  }
   116  
   117  func isExported(name string) bool {
   118  	ch, _ := utf8.DecodeRuneInString(name)
   119  	return unicode.IsUpper(ch)
   120  }
   121  
   122  func checkFields(t1, t2 reflect.Type) bool {
   123  	n1 := t1.NumField()
   124  	n2 := t2.NumField()
   125  	if n1 != n2 {
   126  		return false
   127  	}
   128  	for i := 0; i < n1; i++ {
   129  		f1 := t1.Field(i)
   130  		f2 := t2.Field(i)
   131  		if f1.Name != f2.Name ||
   132  			f1.PkgPath != f2.PkgPath ||
   133  			f1.Anonymous != f2.Anonymous ||
   134  			f1.Type != f2.Type ||
   135  			f1.Offset != f2.Offset {
   136  			return false
   137  		}
   138  	}
   139  	return true
   140  }
   141  
   142  func StructOf(fields []reflect.StructField) reflect.Type {
   143  	return Default.StructOf(fields)
   144  }
   145  
   146  func (ctx *Context) StructOf(fields []reflect.StructField) reflect.Type {
   147  	var anonymous []int
   148  	underscore := make(map[int]name)
   149  	var underscoreCount int
   150  	fs := make([]reflect.StructField, len(fields))
   151  	for i := 0; i < len(fields); i++ {
   152  		f := fields[i]
   153  		if f.Anonymous {
   154  			anonymous = append(anonymous, i)
   155  			f.Anonymous = false
   156  			if f.Name == "" {
   157  				f.Name = typeName(f.Type)
   158  			}
   159  		} else if f.Name == "_" {
   160  			if underscoreCount > 0 {
   161  				underscore[i] = newName("_", string(f.Tag), false)
   162  				f.Name = "_gop_underscore_" + strconv.Itoa(i)
   163  			}
   164  			underscoreCount++
   165  		}
   166  		fs[i] = f
   167  	}
   168  	typ := reflect.StructOf(fs)
   169  	rt := totype(typ)
   170  	st := toStructType(rt)
   171  	for _, i := range anonymous {
   172  		setEmbedded(&st.fields[i])
   173  	}
   174  	for i, n := range underscore {
   175  		st.fields[i].name = n
   176  	}
   177  	str := typ.String()
   178  	if ts, ok := ctx.structLookupCache[str]; ok {
   179  		for _, t := range ts {
   180  			if haveIdenticalType(t, typ, true) {
   181  				return t
   182  			}
   183  		}
   184  		ts = append(ts, typ)
   185  	} else {
   186  		ctx.structLookupCache[str] = []reflect.Type{typ}
   187  	}
   188  	// fix equal for blank fields and uncomparable type
   189  	if rt.equal != nil && underscoreCount > 0 {
   190  		rt.equal = func(p, q unsafe.Pointer) bool {
   191  			for i, ft := range st.fields {
   192  				if fields[i].Name == "_" {
   193  					continue
   194  				}
   195  				pi := add(p, ft.offset(), "&x.field safe")
   196  				qi := add(q, ft.offset(), "&x.field safe")
   197  				if !ft.typ.equal(pi, qi) {
   198  					return false
   199  				}
   200  			}
   201  			return true
   202  		}
   203  	}
   204  
   205  	if rt.tflag == 0 && isRegularMemory(typ) {
   206  		rt.tflag |= tflagRegularMemory
   207  	}
   208  	return typ
   209  }
   210  
   211  // fnv1 incorporates the list of bytes into the hash x using the FNV-1 hash function.
   212  func fnv1(x uint32, list string) uint32 {
   213  	for _, b := range list {
   214  		x = x*16777619 ^ uint32(b)
   215  	}
   216  	return x
   217  }
   218  
   219  func SetValue(v reflect.Value, x reflect.Value) {
   220  	switch v.Kind() {
   221  	case reflect.Bool:
   222  		v.SetBool(x.Bool())
   223  	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
   224  		v.SetInt(x.Int())
   225  	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
   226  		v.SetUint(x.Uint())
   227  	case reflect.Uintptr:
   228  		v.SetUint(x.Uint())
   229  	case reflect.Float32, reflect.Float64:
   230  		v.SetFloat(x.Float())
   231  	case reflect.Complex64, reflect.Complex128:
   232  		v.SetComplex(x.Complex())
   233  	case reflect.String:
   234  		v.SetString(x.String())
   235  	case reflect.UnsafePointer:
   236  		v.SetPointer(unsafe.Pointer(x.Pointer()))
   237  	default:
   238  		v.Set(x)
   239  	}
   240  }
   241  
   242  var (
   243  	tyEmptyInterface    = reflect.TypeOf((*interface{})(nil)).Elem()
   244  	tyEmptyInterfacePtr = reflect.TypeOf((*interface{})(nil))
   245  	tyEmptyStruct       = reflect.TypeOf((*struct{})(nil)).Elem()
   246  	tyErrorInterface    = reflect.TypeOf((*error)(nil)).Elem()
   247  )
   248  
   249  func SetElem(typ reflect.Type, elem reflect.Type) {
   250  	rt := totype(typ)
   251  	switch typ.Kind() {
   252  	case reflect.Ptr:
   253  		st := (*ptrType)(toKindType(rt))
   254  		st.elem = totype(elem)
   255  	case reflect.Slice:
   256  		st := (*sliceType)(toKindType(rt))
   257  		st.elem = totype(elem)
   258  	case reflect.Array:
   259  		st := (*arrayType)(toKindType(rt))
   260  		st.elem = totype(elem)
   261  	case reflect.Map:
   262  		st := (*mapType)(toKindType(rt))
   263  		st.elem = totype(elem)
   264  	case reflect.Chan:
   265  		st := (*chanType)(toKindType(rt))
   266  		st.elem = totype(elem)
   267  	default:
   268  		panic("reflect: Elem of invalid type " + typ.String())
   269  	}
   270  }
   271  
   272  func typeId(typ reflect.Type) string {
   273  	var id string
   274  	if path := typ.PkgPath(); path != "" {
   275  		id = path + "."
   276  	}
   277  	return id + typ.Name()
   278  }
   279  
   280  type replaceTypeContext struct {
   281  	checking map[reflect.Type]bool
   282  }
   283  
   284  func ReplaceType(pkg string, typ reflect.Type, m map[string]reflect.Type) (rtyp reflect.Type, changed bool) {
   285  	ctx := &replaceTypeContext{make(map[reflect.Type]bool)}
   286  	return ctx.replace(pkg, typ, m)
   287  }
   288  
   289  func (ctx *replaceTypeContext) replace(pkg string, typ reflect.Type, m map[string]reflect.Type) (rtyp reflect.Type, changed bool) {
   290  	if ctx.checking[typ] {
   291  		return
   292  	}
   293  	ctx.checking[typ] = true
   294  	rt := totype(typ)
   295  	switch typ.Kind() {
   296  	case reflect.Struct:
   297  		if typ.PkgPath() != pkg {
   298  			return
   299  		}
   300  		st := (*structType)(toKindType(rt))
   301  		for i := 0; i < len(st.fields); i++ {
   302  			et := toType(st.fields[i].typ)
   303  			if t, ok := m[typeId(et)]; ok {
   304  				st.fields[i].typ = totype(t)
   305  				changed = true
   306  			} else {
   307  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   308  					changed = true
   309  					st.fields[i].typ = totype(rtyp)
   310  				}
   311  			}
   312  		}
   313  		if changed {
   314  			return toType(rt), true
   315  		}
   316  	case reflect.Ptr:
   317  		st := (*ptrType)(toKindType(rt))
   318  		et := toType(st.elem)
   319  		if t, ok := m[typeId(et)]; ok {
   320  			st.elem = totype(t)
   321  			return reflect.PtrTo(t), true
   322  		} else {
   323  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   324  				return reflect.PtrTo(rtyp), true
   325  			}
   326  		}
   327  	case reflect.Slice:
   328  		st := (*sliceType)(toKindType(rt))
   329  		et := toType(st.elem)
   330  		if t, ok := m[typeId(et)]; ok {
   331  			st.elem = totype(t)
   332  			return reflect.SliceOf(t), true
   333  		} else {
   334  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   335  				return reflect.SliceOf(rtyp), true
   336  			}
   337  		}
   338  	case reflect.Array:
   339  		st := (*arrayType)(toKindType(rt))
   340  		et := toType(st.elem)
   341  		if t, ok := m[typeId(et)]; ok {
   342  			st.elem = totype(t)
   343  			return reflect.ArrayOf(int(st.len), t), true
   344  		} else {
   345  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   346  				return reflect.ArrayOf(int(st.len), rtyp), true
   347  			}
   348  		}
   349  	case reflect.Map:
   350  		st := (*mapType)(toKindType(rt))
   351  		kt := toType(st.key)
   352  		et := toType(st.elem)
   353  		if t, ok := m[typeId(kt)]; ok {
   354  			kt = t
   355  			changed = true
   356  		} else {
   357  			if rtyp, ok := ctx.replace(pkg, kt, m); ok {
   358  				kt = rtyp
   359  				changed = true
   360  			}
   361  		}
   362  		if t, ok := m[typeId(et)]; ok {
   363  			et = t
   364  			changed = true
   365  		} else {
   366  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   367  				et = rtyp
   368  				changed = true
   369  			}
   370  		}
   371  		if changed {
   372  			return reflect.MapOf(kt, et), true
   373  		}
   374  	case reflect.Chan:
   375  		st := (*chanType)(toKindType(rt))
   376  		et := toType(st.elem)
   377  		if t, ok := m[typeId(et)]; ok {
   378  			st.elem = totype(t)
   379  			return reflect.ChanOf(typ.ChanDir(), t), true
   380  		} else {
   381  			if rtyp, ok := ctx.replace(pkg, et, m); ok {
   382  				return reflect.ChanOf(typ.ChanDir(), rtyp), true
   383  			}
   384  		}
   385  	case reflect.Func:
   386  		st := (*funcType)(toKindType(rt))
   387  		in := st.in()
   388  		out := st.out()
   389  		for i := 0; i < len(in); i++ {
   390  			et := toType(in[i])
   391  			if t, ok := m[typeId(et)]; ok {
   392  				in[i] = totype(t)
   393  				changed = true
   394  			} else {
   395  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   396  					in[i] = totype(rtyp)
   397  					changed = true
   398  				}
   399  			}
   400  		}
   401  		for i := 0; i < len(out); i++ {
   402  			et := toType(out[i])
   403  			if t, ok := m[typeId(et)]; ok {
   404  				out[i] = totype(t)
   405  				changed = true
   406  			} else {
   407  				if rtyp, ok := ctx.replace(pkg, et, m); ok {
   408  					out[i] = totype(rtyp)
   409  					changed = true
   410  				}
   411  			}
   412  		}
   413  		if changed {
   414  			ins := make([]reflect.Type, len(in))
   415  			for i := 0; i < len(in); i++ {
   416  				ins[i] = toType(in[i])
   417  			}
   418  			outs := make([]reflect.Type, len(out))
   419  			for i := 0; i < len(out); i++ {
   420  				outs[i] = toType(out[i])
   421  			}
   422  			return reflect.FuncOf(ins, outs, typ.IsVariadic()), true
   423  		}
   424  	case reflect.Interface:
   425  		if typ.PkgPath() != pkg {
   426  			return
   427  		}
   428  		if typ == tyErrorInterface {
   429  			return
   430  		}
   431  		st := (*interfaceType)(toKindType(rt))
   432  		for i := 0; i < len(st.methods); i++ {
   433  			tt := typ.Method(i).Type
   434  			if t, ok := m[typeId(tt)]; ok {
   435  				st.methods[i].typ = resolveReflectType(totype(t))
   436  				changed = true
   437  			} else if rtyp, ok := ctx.replace(pkg, tt, m); ok {
   438  				st.methods[i].typ = resolveReflectType(totype(rtyp))
   439  				changed = true
   440  			}
   441  		}
   442  		if changed {
   443  			return toType(rt), true
   444  		}
   445  	}
   446  	return nil, false
   447  }