github.com/modern-go/reflect2@v1.0.2/type_map.go (about) 1 // +build !gccgo 2 3 package reflect2 4 5 import ( 6 "reflect" 7 "sync" 8 "unsafe" 9 ) 10 11 // typelinks2 for 1.7 ~ 12 //go:linkname typelinks2 reflect.typelinks 13 func typelinks2() (sections []unsafe.Pointer, offset [][]int32) 14 15 // initOnce guards initialization of types and packages 16 var initOnce sync.Once 17 18 var types map[string]reflect.Type 19 var packages map[string]map[string]reflect.Type 20 21 // discoverTypes initializes types and packages 22 func discoverTypes() { 23 types = make(map[string]reflect.Type) 24 packages = make(map[string]map[string]reflect.Type) 25 26 loadGoTypes() 27 } 28 29 func loadGoTypes() { 30 var obj interface{} = reflect.TypeOf(0) 31 sections, offset := typelinks2() 32 for i, offs := range offset { 33 rodata := sections[i] 34 for _, off := range offs { 35 (*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off) 36 typ := obj.(reflect.Type) 37 if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct { 38 loadedType := typ.Elem() 39 pkgTypes := packages[loadedType.PkgPath()] 40 if pkgTypes == nil { 41 pkgTypes = map[string]reflect.Type{} 42 packages[loadedType.PkgPath()] = pkgTypes 43 } 44 types[loadedType.String()] = loadedType 45 pkgTypes[loadedType.Name()] = loadedType 46 } 47 } 48 } 49 } 50 51 type emptyInterface struct { 52 typ unsafe.Pointer 53 word unsafe.Pointer 54 } 55 56 // TypeByName return the type by its name, just like Class.forName in java 57 func TypeByName(typeName string) Type { 58 initOnce.Do(discoverTypes) 59 return Type2(types[typeName]) 60 } 61 62 // TypeByPackageName return the type by its package and name 63 func TypeByPackageName(pkgPath string, name string) Type { 64 initOnce.Do(discoverTypes) 65 pkgTypes := packages[pkgPath] 66 if pkgTypes == nil { 67 return nil 68 } 69 return Type2(pkgTypes[name]) 70 }