842 lines
20 KiB
Go
842 lines
20 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// The reflect package implements run-time reflection, allowing a program to
|
|
// manipulate objects with arbitrary types. The typical use is to take a
|
|
// value with static type interface{} and extract its dynamic type
|
|
// information by calling Typeof, which returns an object with interface
|
|
// type Type. That contains a pointer to a struct of type *StructType,
|
|
// *IntType, etc. representing the details of the underlying type. A type
|
|
// switch or type assertion can reveal which.
|
|
//
|
|
// A call to NewValue creates a Value representing the run-time data; it
|
|
// contains a *StructValue, *IntValue, etc. MakeZero takes a Type and
|
|
// returns a Value representing a zero value for that type.
|
|
package reflect
|
|
|
|
import (
|
|
"runtime"
|
|
"strconv"
|
|
"sync"
|
|
"unsafe"
|
|
)
|
|
|
|
/*
|
|
* Copy of data structures from ../runtime/type.go.
|
|
* For comments, see the ones in that file.
|
|
*
|
|
* These data structures are known to the compiler and the runtime.
|
|
*
|
|
* Putting these types in runtime instead of reflect means that
|
|
* reflect doesn't need to be autolinked into every binary, which
|
|
* simplifies bootstrapping and package dependencies.
|
|
* Unfortunately, it also means that reflect needs its own
|
|
* copy in order to access the private fields.
|
|
*/
|
|
|
|
// commonType is the common implementation of most values.
|
|
// It is embedded in other, public struct types, but always
|
|
// with a unique tag like "uint" or "float" so that the client cannot
|
|
// convert from, say, *UintType to *FloatType.
|
|
|
|
type commonType struct {
|
|
kind uint8
|
|
align int8
|
|
fieldAlign uint8
|
|
size uintptr
|
|
hash uint32
|
|
hashfn func(unsafe.Pointer, uintptr)
|
|
equalfn func(unsafe.Pointer, unsafe.Pointer, uintptr)
|
|
string *string
|
|
*uncommonType
|
|
ptrToThis *runtime.Type
|
|
}
|
|
|
|
type method struct {
|
|
name *string
|
|
pkgPath *string
|
|
mtyp *runtime.Type
|
|
typ *runtime.Type
|
|
tfn unsafe.Pointer
|
|
}
|
|
|
|
type uncommonType struct {
|
|
name *string
|
|
pkgPath *string
|
|
methods []method
|
|
}
|
|
|
|
// BoolType represents a boolean type.
|
|
type BoolType struct {
|
|
commonType "bool"
|
|
}
|
|
|
|
// FloatType represents a float type.
|
|
type FloatType struct {
|
|
commonType "float"
|
|
}
|
|
|
|
// ComplexType represents a complex type.
|
|
type ComplexType struct {
|
|
commonType "complex"
|
|
}
|
|
|
|
// IntType represents a signed integer type.
|
|
type IntType struct {
|
|
commonType "int"
|
|
}
|
|
|
|
// UintType represents a uint type.
|
|
type UintType struct {
|
|
commonType "uint"
|
|
}
|
|
|
|
// StringType represents a string type.
|
|
type StringType struct {
|
|
commonType "string"
|
|
}
|
|
|
|
// UnsafePointerType represents an unsafe.Pointer type.
|
|
type UnsafePointerType struct {
|
|
commonType "unsafe.Pointer"
|
|
}
|
|
|
|
// ArrayType represents a fixed array type.
|
|
type ArrayType struct {
|
|
commonType "array"
|
|
elem *runtime.Type
|
|
len uintptr
|
|
}
|
|
|
|
// ChanDir represents a channel type's direction.
|
|
type ChanDir int
|
|
|
|
const (
|
|
RecvDir ChanDir = 1 << iota
|
|
SendDir
|
|
BothDir = RecvDir | SendDir
|
|
)
|
|
|
|
// ChanType represents a channel type.
|
|
type ChanType struct {
|
|
commonType "chan"
|
|
elem *runtime.Type
|
|
dir uintptr
|
|
}
|
|
|
|
// FuncType represents a function type.
|
|
type FuncType struct {
|
|
commonType "func"
|
|
dotdotdot bool
|
|
in []*runtime.Type
|
|
out []*runtime.Type
|
|
}
|
|
|
|
// Method on interface type
|
|
type imethod struct {
|
|
name *string
|
|
pkgPath *string
|
|
typ *runtime.Type
|
|
}
|
|
|
|
// InterfaceType represents an interface type.
|
|
type InterfaceType struct {
|
|
commonType "interface"
|
|
methods []imethod
|
|
}
|
|
|
|
// MapType represents a map type.
|
|
type MapType struct {
|
|
commonType "map"
|
|
key *runtime.Type
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// PtrType represents a pointer type.
|
|
type PtrType struct {
|
|
commonType "ptr"
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// SliceType represents a slice type.
|
|
type SliceType struct {
|
|
commonType "slice"
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// arrayOrSliceType is an unexported method that guarantees only
|
|
// arrays and slices implement ArrayOrSliceType.
|
|
func (*SliceType) arrayOrSliceType() {}
|
|
|
|
// Struct field
|
|
type structField struct {
|
|
name *string
|
|
pkgPath *string
|
|
typ *runtime.Type
|
|
tag *string
|
|
offset uintptr
|
|
}
|
|
|
|
// StructType represents a struct type.
|
|
type StructType struct {
|
|
commonType "struct"
|
|
fields []structField
|
|
}
|
|
|
|
|
|
/*
|
|
* The compiler knows the exact layout of all the data structures above.
|
|
* The compiler does not know about the data structures and methods below.
|
|
*/
|
|
|
|
// Method represents a single method.
|
|
type Method struct {
|
|
PkgPath string // empty for uppercase Name
|
|
Name string
|
|
Type *FuncType
|
|
Func *FuncValue
|
|
}
|
|
|
|
// Type is the runtime representation of a Go type.
|
|
// Every type implements the methods listed here.
|
|
// Some types implement additional interfaces;
|
|
// use a type switch to find out what kind of type a Type is.
|
|
// Each type in a program has a unique Type, so == on Types
|
|
// corresponds to Go's type equality.
|
|
type Type interface {
|
|
// PkgPath returns the type's package path.
|
|
// The package path is a full package import path like "container/vector".
|
|
// PkgPath returns an empty string for unnamed types.
|
|
PkgPath() string
|
|
|
|
// Name returns the type's name within its package.
|
|
// Name returns an empty string for unnamed types.
|
|
Name() string
|
|
|
|
// String returns a string representation of the type.
|
|
// The string representation may use shortened package names
|
|
// (e.g., vector instead of "container/vector") and is not
|
|
// guaranteed to be unique among types. To test for equality,
|
|
// compare the Types directly.
|
|
String() string
|
|
|
|
// Size returns the number of bytes needed to store
|
|
// a value of the given type; it is analogous to unsafe.Sizeof.
|
|
Size() uintptr
|
|
|
|
// Bits returns the size of the type in bits.
|
|
// It is intended for use with numeric types and may overflow
|
|
// when used for composite types.
|
|
Bits() int
|
|
|
|
// Align returns the alignment of a value of this type
|
|
// when allocated in memory.
|
|
Align() int
|
|
|
|
// FieldAlign returns the alignment of a value of this type
|
|
// when used as a field in a struct.
|
|
FieldAlign() int
|
|
|
|
// Kind returns the specific kind of this type.
|
|
Kind() Kind
|
|
|
|
// Method returns the i'th method in the type's method set.
|
|
//
|
|
// For a non-interface type T or *T, the returned Method's Type and Func
|
|
// fields describe a function whose first argument is the receiver.
|
|
//
|
|
// For an interface type, the returned Method's Type field gives the
|
|
// method signature, without a receiver, and the Func field is nil.
|
|
Method(int) Method
|
|
|
|
// NumMethods returns the number of methods in the type's method set.
|
|
NumMethod() int
|
|
|
|
common() *commonType
|
|
uncommon() *uncommonType
|
|
}
|
|
|
|
// A Kind represents the specific kind of type that a Type represents.
|
|
// For numeric types, the Kind gives more information than the Type's
|
|
// dynamic type. For example, the Type of a float32 is FloatType, but
|
|
// the Kind is Float32.
|
|
//
|
|
// The zero Kind is not a valid kind.
|
|
type Kind uint8
|
|
|
|
const (
|
|
Bool Kind = 1 + iota
|
|
Int
|
|
Int8
|
|
Int16
|
|
Int32
|
|
Int64
|
|
Uint
|
|
Uint8
|
|
Uint16
|
|
Uint32
|
|
Uint64
|
|
Uintptr
|
|
Float32
|
|
Float64
|
|
Complex64
|
|
Complex128
|
|
Array
|
|
Chan
|
|
Func
|
|
Interface
|
|
Map
|
|
Ptr
|
|
Slice
|
|
String
|
|
Struct
|
|
UnsafePointer
|
|
)
|
|
|
|
// High bit says whether type has
|
|
// embedded pointers,to help garbage collector.
|
|
const kindMask = 0x7f
|
|
|
|
func (k Kind) String() string {
|
|
if int(k) < len(kindNames) {
|
|
return kindNames[k]
|
|
}
|
|
return "kind" + strconv.Itoa(int(k))
|
|
}
|
|
|
|
var kindNames = []string{
|
|
Bool: "bool",
|
|
Int: "int",
|
|
Int8: "int8",
|
|
Int16: "int16",
|
|
Int32: "int32",
|
|
Int64: "int64",
|
|
Uint: "uint",
|
|
Uint8: "uint8",
|
|
Uint16: "uint16",
|
|
Uint32: "uint32",
|
|
Uint64: "uint64",
|
|
Uintptr: "uintptr",
|
|
Float32: "float32",
|
|
Float64: "float64",
|
|
Complex64: "complex64",
|
|
Complex128: "complex128",
|
|
Array: "array",
|
|
Chan: "chan",
|
|
Func: "func",
|
|
Interface: "interface",
|
|
Map: "map",
|
|
Ptr: "ptr",
|
|
Slice: "slice",
|
|
String: "string",
|
|
Struct: "struct",
|
|
UnsafePointer: "unsafe.Pointer",
|
|
}
|
|
|
|
func (t *uncommonType) uncommon() *uncommonType {
|
|
return t
|
|
}
|
|
|
|
func (t *uncommonType) PkgPath() string {
|
|
if t == nil || t.pkgPath == nil {
|
|
return ""
|
|
}
|
|
return *t.pkgPath
|
|
}
|
|
|
|
func (t *uncommonType) Name() string {
|
|
if t == nil || t.name == nil {
|
|
return ""
|
|
}
|
|
return *t.name
|
|
}
|
|
|
|
func (t *commonType) String() string { return *t.string }
|
|
|
|
func (t *commonType) Size() uintptr { return t.size }
|
|
|
|
func (t *commonType) Bits() int { return int(t.size * 8) }
|
|
|
|
func (t *commonType) Align() int { return int(t.align) }
|
|
|
|
func (t *commonType) FieldAlign() int { return int(t.fieldAlign) }
|
|
|
|
func (t *commonType) Kind() Kind { return Kind(t.kind & kindMask) }
|
|
|
|
func (t *commonType) common() *commonType { return t }
|
|
|
|
func (t *uncommonType) Method(i int) (m Method) {
|
|
if t == nil || i < 0 || i >= len(t.methods) {
|
|
return
|
|
}
|
|
p := &t.methods[i]
|
|
if p.name != nil {
|
|
m.Name = *p.name
|
|
}
|
|
if p.pkgPath != nil {
|
|
m.PkgPath = *p.pkgPath
|
|
}
|
|
m.Type = runtimeToType(p.typ).(*FuncType)
|
|
fn := p.tfn
|
|
m.Func = &FuncValue{value: value{m.Type, addr(&fn), canSet}}
|
|
return
|
|
}
|
|
|
|
func (t *uncommonType) NumMethod() int {
|
|
if t == nil {
|
|
return 0
|
|
}
|
|
return len(t.methods)
|
|
}
|
|
|
|
// TODO(rsc): 6g supplies these, but they are not
|
|
// as efficient as they could be: they have commonType
|
|
// as the receiver instead of *commonType.
|
|
func (t *commonType) NumMethod() int { return t.uncommonType.NumMethod() }
|
|
|
|
func (t *commonType) Method(i int) (m Method) { return t.uncommonType.Method(i) }
|
|
|
|
func (t *commonType) PkgPath() string { return t.uncommonType.PkgPath() }
|
|
|
|
func (t *commonType) Name() string { return t.uncommonType.Name() }
|
|
|
|
// Len returns the number of elements in the array.
|
|
func (t *ArrayType) Len() int { return int(t.len) }
|
|
|
|
// Elem returns the type of the array's elements.
|
|
func (t *ArrayType) Elem() Type { return runtimeToType(t.elem) }
|
|
|
|
// arrayOrSliceType is an unexported method that guarantees only
|
|
// arrays and slices implement ArrayOrSliceType.
|
|
func (*ArrayType) arrayOrSliceType() {}
|
|
|
|
// Dir returns the channel direction.
|
|
func (t *ChanType) Dir() ChanDir { return ChanDir(t.dir) }
|
|
|
|
// Elem returns the channel's element type.
|
|
func (t *ChanType) Elem() Type { return runtimeToType(t.elem) }
|
|
|
|
func (d ChanDir) String() string {
|
|
switch d {
|
|
case SendDir:
|
|
return "chan<-"
|
|
case RecvDir:
|
|
return "<-chan"
|
|
case BothDir:
|
|
return "chan"
|
|
}
|
|
return "ChanDir" + strconv.Itoa(int(d))
|
|
}
|
|
|
|
// In returns the type of the i'th function input parameter.
|
|
func (t *FuncType) In(i int) Type {
|
|
if i < 0 || i >= len(t.in) {
|
|
return nil
|
|
}
|
|
return runtimeToType(t.in[i])
|
|
}
|
|
|
|
// DotDotDot returns true if the final function input parameter
|
|
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the
|
|
// parameter's underlying static type []T.
|
|
//
|
|
// For concreteness, if t is func(x int, y ... float), then
|
|
//
|
|
// t.NumIn() == 2
|
|
// t.In(0) is the reflect.Type for "int"
|
|
// t.In(1) is the reflect.Type for "[]float"
|
|
// t.DotDotDot() == true
|
|
//
|
|
func (t *FuncType) DotDotDot() bool { return t.dotdotdot }
|
|
|
|
// NumIn returns the number of input parameters.
|
|
func (t *FuncType) NumIn() int { return len(t.in) }
|
|
|
|
// Out returns the type of the i'th function output parameter.
|
|
func (t *FuncType) Out(i int) Type {
|
|
if i < 0 || i >= len(t.out) {
|
|
return nil
|
|
}
|
|
return runtimeToType(t.out[i])
|
|
}
|
|
|
|
// NumOut returns the number of function output parameters.
|
|
func (t *FuncType) NumOut() int { return len(t.out) }
|
|
|
|
// Method returns the i'th method in the type's method set.
|
|
func (t *InterfaceType) Method(i int) (m Method) {
|
|
if i < 0 || i >= len(t.methods) {
|
|
return
|
|
}
|
|
p := &t.methods[i]
|
|
m.Name = *p.name
|
|
if p.pkgPath != nil {
|
|
m.PkgPath = *p.pkgPath
|
|
}
|
|
m.Type = runtimeToType(p.typ).(*FuncType)
|
|
return
|
|
}
|
|
|
|
// NumMethod returns the number of interface methods in the type's method set.
|
|
func (t *InterfaceType) NumMethod() int { return len(t.methods) }
|
|
|
|
// Key returns the map key type.
|
|
func (t *MapType) Key() Type { return runtimeToType(t.key) }
|
|
|
|
// Elem returns the map element type.
|
|
func (t *MapType) Elem() Type { return runtimeToType(t.elem) }
|
|
|
|
// Elem returns the pointer element type.
|
|
func (t *PtrType) Elem() Type { return runtimeToType(t.elem) }
|
|
|
|
// Elem returns the type of the slice's elements.
|
|
func (t *SliceType) Elem() Type { return runtimeToType(t.elem) }
|
|
|
|
type StructField struct {
|
|
PkgPath string // empty for uppercase Name
|
|
Name string
|
|
Type Type
|
|
Tag string
|
|
Offset uintptr
|
|
Index []int
|
|
Anonymous bool
|
|
}
|
|
|
|
// Field returns the i'th struct field.
|
|
func (t *StructType) Field(i int) (f StructField) {
|
|
if i < 0 || i >= len(t.fields) {
|
|
return
|
|
}
|
|
p := t.fields[i]
|
|
f.Type = runtimeToType(p.typ)
|
|
if p.name != nil {
|
|
f.Name = *p.name
|
|
} else {
|
|
t := f.Type
|
|
if pt, ok := t.(*PtrType); ok {
|
|
t = pt.Elem()
|
|
}
|
|
f.Name = t.Name()
|
|
f.Anonymous = true
|
|
}
|
|
if p.pkgPath != nil {
|
|
f.PkgPath = *p.pkgPath
|
|
}
|
|
if p.tag != nil {
|
|
f.Tag = *p.tag
|
|
}
|
|
f.Offset = p.offset
|
|
f.Index = []int{i}
|
|
return
|
|
}
|
|
|
|
// TODO(gri): Should there be an error/bool indicator if the index
|
|
// is wrong for FieldByIndex?
|
|
|
|
// FieldByIndex returns the nested field corresponding to index.
|
|
func (t *StructType) FieldByIndex(index []int) (f StructField) {
|
|
for i, x := range index {
|
|
if i > 0 {
|
|
ft := f.Type
|
|
if pt, ok := ft.(*PtrType); ok {
|
|
ft = pt.Elem()
|
|
}
|
|
if st, ok := ft.(*StructType); ok {
|
|
t = st
|
|
} else {
|
|
var f0 StructField
|
|
f = f0
|
|
return
|
|
}
|
|
}
|
|
f = t.Field(x)
|
|
}
|
|
return
|
|
}
|
|
|
|
const inf = 1 << 30 // infinity - no struct has that many nesting levels
|
|
|
|
func (t *StructType) fieldByNameFunc(match func(string) bool, mark map[*StructType]bool, depth int) (ff StructField, fd int) {
|
|
fd = inf // field depth
|
|
|
|
if mark[t] {
|
|
// Struct already seen.
|
|
return
|
|
}
|
|
mark[t] = true
|
|
|
|
var fi int // field index
|
|
n := 0 // number of matching fields at depth fd
|
|
L:
|
|
for i := range t.fields {
|
|
f := t.Field(i)
|
|
d := inf
|
|
switch {
|
|
case match(f.Name):
|
|
// Matching top-level field.
|
|
d = depth
|
|
case f.Anonymous:
|
|
ft := f.Type
|
|
if pt, ok := ft.(*PtrType); ok {
|
|
ft = pt.Elem()
|
|
}
|
|
switch {
|
|
case match(ft.Name()):
|
|
// Matching anonymous top-level field.
|
|
d = depth
|
|
case fd > depth:
|
|
// No top-level field yet; look inside nested structs.
|
|
if st, ok := ft.(*StructType); ok {
|
|
f, d = st.fieldByNameFunc(match, mark, depth+1)
|
|
}
|
|
}
|
|
}
|
|
|
|
switch {
|
|
case d < fd:
|
|
// Found field at shallower depth.
|
|
ff, fi, fd = f, i, d
|
|
n = 1
|
|
case d == fd:
|
|
// More than one matching field at the same depth (or d, fd == inf).
|
|
// Same as no field found at this depth.
|
|
n++
|
|
if d == depth {
|
|
// Impossible to find a field at lower depth.
|
|
break L
|
|
}
|
|
}
|
|
}
|
|
|
|
if n == 1 {
|
|
// Found matching field.
|
|
if len(ff.Index) <= depth {
|
|
ff.Index = make([]int, depth+1)
|
|
}
|
|
ff.Index[depth] = fi
|
|
} else {
|
|
// None or more than one matching field found.
|
|
fd = inf
|
|
}
|
|
|
|
mark[t] = false, false
|
|
return
|
|
}
|
|
|
|
// FieldByName returns the struct field with the given name
|
|
// and a boolean to indicate if the field was found.
|
|
func (t *StructType) FieldByName(name string) (f StructField, present bool) {
|
|
return t.FieldByNameFunc(func(s string) bool { return s == name })
|
|
}
|
|
|
|
// FieldByNameFunc returns the struct field with a name that satisfies the
|
|
// match function and a boolean to indicate if the field was found.
|
|
func (t *StructType) FieldByNameFunc(match func(string) bool) (f StructField, present bool) {
|
|
if ff, fd := t.fieldByNameFunc(match, make(map[*StructType]bool), 0); fd < inf {
|
|
ff.Index = ff.Index[0 : fd+1]
|
|
f, present = ff, true
|
|
}
|
|
return
|
|
}
|
|
|
|
// NumField returns the number of struct fields.
|
|
func (t *StructType) NumField() int { return len(t.fields) }
|
|
|
|
// Canonicalize a Type.
|
|
var canonicalType = make(map[string]Type)
|
|
|
|
var canonicalTypeLock sync.Mutex
|
|
|
|
func canonicalize(t Type) Type {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
u := t.uncommon()
|
|
var s string
|
|
if u == nil || u.PkgPath() == "" {
|
|
s = t.String()
|
|
} else {
|
|
s = u.PkgPath() + "." + u.Name()
|
|
}
|
|
canonicalTypeLock.Lock()
|
|
if r, ok := canonicalType[s]; ok {
|
|
canonicalTypeLock.Unlock()
|
|
return r
|
|
}
|
|
canonicalType[s] = t
|
|
canonicalTypeLock.Unlock()
|
|
return t
|
|
}
|
|
|
|
// Convert runtime type to reflect type.
|
|
// Same memory layouts, different method sets.
|
|
func toType(i interface{}) Type {
|
|
switch v := i.(type) {
|
|
case nil:
|
|
return nil
|
|
case *runtime.BoolType:
|
|
return (*BoolType)(unsafe.Pointer(v))
|
|
case *runtime.FloatType:
|
|
return (*FloatType)(unsafe.Pointer(v))
|
|
case *runtime.ComplexType:
|
|
return (*ComplexType)(unsafe.Pointer(v))
|
|
case *runtime.IntType:
|
|
return (*IntType)(unsafe.Pointer(v))
|
|
case *runtime.StringType:
|
|
return (*StringType)(unsafe.Pointer(v))
|
|
case *runtime.UintType:
|
|
return (*UintType)(unsafe.Pointer(v))
|
|
case *runtime.UnsafePointerType:
|
|
return (*UnsafePointerType)(unsafe.Pointer(v))
|
|
case *runtime.ArrayType:
|
|
return (*ArrayType)(unsafe.Pointer(v))
|
|
case *runtime.ChanType:
|
|
return (*ChanType)(unsafe.Pointer(v))
|
|
case *runtime.FuncType:
|
|
return (*FuncType)(unsafe.Pointer(v))
|
|
case *runtime.InterfaceType:
|
|
return (*InterfaceType)(unsafe.Pointer(v))
|
|
case *runtime.MapType:
|
|
return (*MapType)(unsafe.Pointer(v))
|
|
case *runtime.PtrType:
|
|
return (*PtrType)(unsafe.Pointer(v))
|
|
case *runtime.SliceType:
|
|
return (*SliceType)(unsafe.Pointer(v))
|
|
case *runtime.StructType:
|
|
return (*StructType)(unsafe.Pointer(v))
|
|
}
|
|
println(i)
|
|
panic("toType")
|
|
}
|
|
|
|
// Convert pointer to runtime Type structure to our Type structure.
|
|
func runtimeToType(v *runtime.Type) Type {
|
|
var r Type
|
|
switch Kind(v.Kind) {
|
|
case Bool:
|
|
r = (*BoolType)(unsafe.Pointer(v))
|
|
case Int, Int8, Int16, Int32, Int64:
|
|
r = (*IntType)(unsafe.Pointer(v))
|
|
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
|
r = (*UintType)(unsafe.Pointer(v))
|
|
case Float32, Float64:
|
|
r = (*FloatType)(unsafe.Pointer(v))
|
|
case Complex64, Complex128:
|
|
r = (*ComplexType)(unsafe.Pointer(v))
|
|
case Array:
|
|
r = (*ArrayType)(unsafe.Pointer(v))
|
|
case Chan:
|
|
r = (*ChanType)(unsafe.Pointer(v))
|
|
case Func:
|
|
r = (*FuncType)(unsafe.Pointer(v))
|
|
case Interface:
|
|
r = (*InterfaceType)(unsafe.Pointer(v))
|
|
case Map:
|
|
r = (*MapType)(unsafe.Pointer(v))
|
|
case Ptr:
|
|
r = (*PtrType)(unsafe.Pointer(v))
|
|
case Slice:
|
|
r = (*SliceType)(unsafe.Pointer(v))
|
|
case String:
|
|
r = (*StringType)(unsafe.Pointer(v))
|
|
case Struct:
|
|
r = (*StructType)(unsafe.Pointer(v))
|
|
case UnsafePointer:
|
|
r = (*UnsafePointerType)(unsafe.Pointer(v))
|
|
default:
|
|
panic("runtimeToType")
|
|
}
|
|
return canonicalize(r)
|
|
panic("runtimeToType")
|
|
}
|
|
|
|
// ArrayOrSliceType is the common interface implemented
|
|
// by both ArrayType and SliceType.
|
|
type ArrayOrSliceType interface {
|
|
Type
|
|
Elem() Type
|
|
arrayOrSliceType() // Guarantees only Array and Slice implement this interface.
|
|
}
|
|
|
|
// Typeof returns the reflection Type of the value in the interface{}.
|
|
func Typeof(i interface{}) Type { return canonicalize(toType(unsafe.Typeof(i))) }
|
|
|
|
// ptrMap is the cache for PtrTo.
|
|
var ptrMap struct {
|
|
sync.RWMutex
|
|
m map[Type]*PtrType
|
|
}
|
|
|
|
// runtimePtrType is the runtime layout for a *PtrType.
|
|
// The memory immediately before the *PtrType is always
|
|
// the canonical runtime.Type to be used for a *runtime.Type
|
|
// describing this PtrType.
|
|
type runtimePtrType struct {
|
|
runtime.Type
|
|
runtime.PtrType
|
|
}
|
|
|
|
// PtrTo returns the pointer type with element t.
|
|
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
|
|
func PtrTo(t Type) *PtrType {
|
|
// If t records its pointer-to type, use it.
|
|
ct := t.common()
|
|
if p := ct.ptrToThis; p != nil {
|
|
return runtimeToType(p).(*PtrType)
|
|
}
|
|
|
|
// Otherwise, synthesize one.
|
|
// This only happens for pointers with no methods.
|
|
// We keep the mapping in a map on the side, because
|
|
// this operation is rare and a separate map lets us keep
|
|
// the type structures in read-only memory.
|
|
ptrMap.RLock()
|
|
if m := ptrMap.m; m != nil {
|
|
if p := m[t]; p != nil {
|
|
ptrMap.RUnlock()
|
|
return p
|
|
}
|
|
}
|
|
ptrMap.RUnlock()
|
|
ptrMap.Lock()
|
|
if ptrMap.m == nil {
|
|
ptrMap.m = make(map[Type]*PtrType)
|
|
}
|
|
p := ptrMap.m[t]
|
|
if p != nil {
|
|
// some other goroutine won the race and created it
|
|
ptrMap.Unlock()
|
|
return p
|
|
}
|
|
|
|
rt := (*runtime.Type)(unsafe.Pointer(ct))
|
|
|
|
rp := new(runtime.PtrType)
|
|
|
|
// initialize rp used *byte's PtrType as a prototype.
|
|
// have to do assignment as PtrType, not runtime.PtrType,
|
|
// in order to write to unexported fields.
|
|
p = (*PtrType)(unsafe.Pointer(rp))
|
|
bp := (*PtrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
|
|
*p = *bp
|
|
|
|
s := "*" + *ct.string
|
|
p.string = &s
|
|
|
|
// For the type structures linked into the binary, the
|
|
// compiler provides a good hash of the string.
|
|
// Create a good hash for the new string by using
|
|
// the FNV-1 hash's mixing function to combine the
|
|
// old hash and the new "*".
|
|
p.hash = ct.hash*16777619 ^ '*'
|
|
|
|
p.uncommonType = nil
|
|
p.ptrToThis = nil
|
|
p.elem = rt
|
|
|
|
ptrMap.m[t] = (*PtrType)(unsafe.Pointer(rp))
|
|
ptrMap.Unlock()
|
|
return p
|
|
}
|