github.com/modern-go/Reflect2@v1.0.1/type_map.go (about) 1 package reflect2 2 3 import ( 4 "reflect" 5 "runtime" 6 "strings" 7 "sync" 8 "unsafe" 9 ) 10 11 // typelinks1 for 1.5 ~ 1.6 12 //go:linkname typelinks1 reflect.typelinks 13 func typelinks1() [][]unsafe.Pointer 14 15 // typelinks2 for 1.7 ~ 16 //go:linkname typelinks2 reflect.typelinks 17 func typelinks2() (sections []unsafe.Pointer, offset [][]int32) 18 19 // initOnce guards initialization of types and packages 20 var initOnce sync.Once 21 22 var types map[string]reflect.Type 23 var packages map[string]map[string]reflect.Type 24 25 // discoverTypes initializes types and packages 26 func discoverTypes() { 27 types = make(map[string]reflect.Type) 28 packages = make(map[string]map[string]reflect.Type) 29 30 ver := runtime.Version() 31 if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") { 32 loadGo15Types() 33 } else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") { 34 loadGo15Types() 35 } else { 36 loadGo17Types() 37 } 38 } 39 40 func loadGo15Types() { 41 var obj interface{} = reflect.TypeOf(0) 42 typePtrss := typelinks1() 43 for _, typePtrs := range typePtrss { 44 for _, typePtr := range typePtrs { 45 (*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr 46 typ := obj.(reflect.Type) 47 if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 48 loadedType := typ.Elem() 49 pkgTypes := packages[loadedType.PkgPath()] 50 if pkgTypes == nil { 51 pkgTypes = map[string]reflect.Type{} 52 packages[loadedType.PkgPath()] = pkgTypes 53 } 54 types[loadedType.String()] = loadedType 55 pkgTypes[loadedType.Name()] = loadedType 56 } 57 if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr && 58 typ.Elem().Elem().Kind() == reflect.Struct { 59 loadedType := typ.Elem().Elem() 60 pkgTypes := packages[loadedType.PkgPath()] 61 if pkgTypes == nil { 62 pkgTypes = map[string]reflect.Type{} 63 packages[loadedType.PkgPath()] = pkgTypes 64 } 65 types[loadedType.String()] = loadedType 66 pkgTypes[loadedType.Name()] = loadedType 67 } 68 } 69 } 70 } 71 72 func loadGo17Types() { 73 var obj interface{} = reflect.TypeOf(0) 74 sections, offset := typelinks2() 75 for i, offs := range offset { 76 rodata := sections[i] 77 for _, off := range offs { 78 (*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off) 79 typ := obj.(reflect.Type) 80 if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 81 loadedType := typ.Elem() 82 pkgTypes := packages[loadedType.PkgPath()] 83 if pkgTypes == nil { 84 pkgTypes = map[string]reflect.Type{} 85 packages[loadedType.PkgPath()] = pkgTypes 86 } 87 types[loadedType.String()] = loadedType 88 pkgTypes[loadedType.Name()] = loadedType 89 } 90 } 91 } 92 } 93 94 type emptyInterface struct { 95 typ unsafe.Pointer 96 word unsafe.Pointer 97 } 98 99 // TypeByName return the type by its name, just like Class.forName in java 100 func TypeByName(typeName string) Type { 101 initOnce.Do(discoverTypes) 102 return Type2(types[typeName]) 103 } 104 105 // TypeByPackageName return the type by its package and name 106 func TypeByPackageName(pkgPath string, name string) Type { 107 initOnce.Do(discoverTypes) 108 pkgTypes := packages[pkgPath] 109 if pkgTypes == nil { 110 return nil 111 } 112 return Type2(pkgTypes[name]) 113 }