123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103 |
- package reflect2
- import (
- "reflect"
- "runtime"
- "strings"
- "unsafe"
- )
- // typelinks1 for 1.5 ~ 1.6
- //go:linkname typelinks1 reflect.typelinks
- func typelinks1() [][]unsafe.Pointer
- // typelinks2 for 1.7 ~
- //go:linkname typelinks2 reflect.typelinks
- func typelinks2() (sections []unsafe.Pointer, offset [][]int32)
- var types = map[string]reflect.Type{}
- var packages = map[string]map[string]reflect.Type{}
- func init() {
- ver := runtime.Version()
- if ver == "go1.5" || strings.HasPrefix(ver, "go1.5.") {
- loadGo15Types()
- } else if ver == "go1.6" || strings.HasPrefix(ver, "go1.6.") {
- loadGo15Types()
- } else {
- loadGo17Types()
- }
- }
- func loadGo15Types() {
- var obj interface{} = reflect.TypeOf(0)
- typePtrss := typelinks1()
- for _, typePtrs := range typePtrss {
- for _, typePtr := range typePtrs {
- (*emptyInterface)(unsafe.Pointer(&obj)).word = typePtr
- typ := obj.(reflect.Type)
- if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
- loadedType := typ.Elem()
- pkgTypes := packages[loadedType.PkgPath()]
- if pkgTypes == nil {
- pkgTypes = map[string]reflect.Type{}
- packages[loadedType.PkgPath()] = pkgTypes
- }
- types[loadedType.String()] = loadedType
- pkgTypes[loadedType.Name()] = loadedType
- }
- if typ.Kind() == reflect.Slice && typ.Elem().Kind() == reflect.Ptr &&
- typ.Elem().Elem().Kind() == reflect.Struct {
- loadedType := typ.Elem().Elem()
- pkgTypes := packages[loadedType.PkgPath()]
- if pkgTypes == nil {
- pkgTypes = map[string]reflect.Type{}
- packages[loadedType.PkgPath()] = pkgTypes
- }
- types[loadedType.String()] = loadedType
- pkgTypes[loadedType.Name()] = loadedType
- }
- }
- }
- }
- func loadGo17Types() {
- var obj interface{} = reflect.TypeOf(0)
- sections, offset := typelinks2()
- for i, offs := range offset {
- rodata := sections[i]
- for _, off := range offs {
- (*emptyInterface)(unsafe.Pointer(&obj)).word = resolveTypeOff(unsafe.Pointer(rodata), off)
- typ := obj.(reflect.Type)
- if typ.Kind() == reflect.Ptr && typ.Elem().Kind() == reflect.Struct {
- loadedType := typ.Elem()
- pkgTypes := packages[loadedType.PkgPath()]
- if pkgTypes == nil {
- pkgTypes = map[string]reflect.Type{}
- packages[loadedType.PkgPath()] = pkgTypes
- }
- types[loadedType.String()] = loadedType
- pkgTypes[loadedType.Name()] = loadedType
- }
- }
- }
- }
- type emptyInterface struct {
- typ unsafe.Pointer
- word unsafe.Pointer
- }
- // TypeByName return the type by its name, just like Class.forName in java
- func TypeByName(typeName string) Type {
- return Type2(types[typeName])
- }
- // TypeByPackageName return the type by its package and name
- func TypeByPackageName(pkgPath string, name string) Type {
- pkgTypes := packages[pkgPath]
- if pkgTypes == nil {
- return nil
- }
- return Type2(pkgTypes[name])
- }
|