summaryrefslogtreecommitdiff
path: root/vendor/github.com/modern-go/reflect2/type_map.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/modern-go/reflect2/type_map.go')
-rw-r--r--vendor/github.com/modern-go/reflect2/type_map.go103
1 files changed, 103 insertions, 0 deletions
diff --git a/vendor/github.com/modern-go/reflect2/type_map.go b/vendor/github.com/modern-go/reflect2/type_map.go
new file mode 100644
index 000000000..6d489112f
--- /dev/null
+++ b/vendor/github.com/modern-go/reflect2/type_map.go
@@ -0,0 +1,103 @@
+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])
+}