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  }