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 }