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  }