github.com/jxskiss/gopkg@v0.17.3/forceexport/type.go (about) 1 package forceexport 2 3 import ( 4 "fmt" 5 "reflect" 6 "strings" 7 8 "github.com/jxskiss/gopkg/internal/linkname" 9 "github.com/jxskiss/gopkg/reflectx" 10 ) 11 12 // GetType gets the type defined by the given fully-qualified name. 13 // If the specified type does not exist, or inactive (haven't been 14 // compiled into the binary), it panics. 15 func GetType(name string) *reflectx.RType { 16 sections, offsets := linkname.Reflect_typelinks() 17 for i, base := range sections { 18 for _, offset := range offsets[i] { 19 typ := (*reflectx.RType)(linkname.Reflect_resolveTypeOff(base, offset)) 20 for typ.Name() == "" && typ.Kind() == reflect.Ptr { 21 typ = typ.Elem() 22 } 23 typName := typ.Name() 24 if typName == "" || !strings.HasSuffix(name, typName) { 25 continue 26 } 27 pkgPath := removeVendorPrefix(typ.PkgPath()) 28 if name == pkgPath+"."+typName { 29 return typ 30 } 31 } 32 } 33 panic(fmt.Sprintf("forceexport: cannot find type %s, maybe inactive", name)) 34 } 35 36 // ScanType scans type information which are available from reflect.typelinks. 37 // For each type, it calls f with the type's fully-qualified name and type. 38 func ScanType(f func(name string, typ *reflectx.RType)) { 39 sections, offsets := linkname.Reflect_typelinks() 40 for i, base := range sections { 41 for _, offset := range offsets[i] { 42 typ := (*reflectx.RType)(linkname.Reflect_resolveTypeOff(base, offset)) 43 for typ.Name() == "" && typ.Kind() == reflect.Ptr { 44 typ = typ.Elem() 45 } 46 typName := typ.Name() 47 if typName == "" { 48 continue 49 } 50 pkgPath := removeVendorPrefix(typ.PkgPath()) 51 if pkgPath == "" { 52 continue 53 } 54 fullName := fmt.Sprintf("%s.%s", pkgPath, typName) 55 f(fullName, typ) 56 } 57 } 58 } 59 60 func removeVendorPrefix(path string) string { 61 const prefix = "/vendor/" 62 const prefixLen = 8 63 idx := strings.LastIndex(path, prefix) 64 if idx >= 0 { 65 path = path[idx+prefixLen:] 66 } 67 return path 68 }