github.com/leromarinvit/typist@v0.0.0-20170209001249-15cee4975bef/from_string.go (about)

     1  // Package typist gets a reflect.Type for a type specified by a string.
     2  package typist
     3  
     4  import (
     5  	"fmt"
     6  	"reflect"
     7  	"unsafe"
     8  )
     9  
    10  //go:linkname typesByString reflect.typesByString
    11  func typesByString(s string) []unsafe.Pointer
    12  
    13  /*
    14  TypeByString tries to find a reflect.Type corresponding to the type specified by
    15  s.
    16  
    17  It calls the unexported `reflect.typesByString` to do so. It will fail if
    18  the type can't be found or if more than one type with the given name exist.
    19  
    20  This relies on the following assumptions:
    21      * The signature of `reflect.typesByString` must not change
    22      * The value returned by `reflect.TypeOf(0)` is a `*reflect.rtype`
    23      * The `reflect.Value` struct contains a `ptr` field of type `unsafe.Pointer`
    24  */
    25  func TypeByString(s string) (reflect.Type, error) {
    26  	types := typesByString(s)
    27  
    28  	if len(types) == 0 {
    29  		return nil, fmt.Errorf("Type '%s' not found", s)
    30  	}
    31  	if len(types) > 1 {
    32  		return nil, fmt.Errorf("Type '%s' is ambiguous", s)
    33  	}
    34  
    35  	t := types[0]
    36  
    37  	pRtypeType := reflect.ValueOf(reflect.TypeOf(0)).Type()
    38  	rtype := reflect.New(pRtypeType).Elem()
    39  
    40  	ptr := unsafe.Pointer(reflect.ValueOf(rtype).FieldByName("ptr").Pointer())
    41  	*(*unsafe.Pointer)(ptr) = t
    42  
    43  	typ := rtype.Interface().(reflect.Type)
    44  	return typ, nil
    45  }