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  }