1192 lines
29 KiB
Go
1192 lines
29 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.
|
|
|
|
// Package reflect 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 a Type.
|
|
//
|
|
// A call to ValueOf returns a Value representing the run-time data.
|
|
// Zero takes a Type and returns a Value representing a zero value
|
|
// for that type.
|
|
//
|
|
// See "The Laws of Reflection" for an introduction to reflection in Go:
|
|
// http://blog.golang.org/2011/09/laws-of-reflection.html
|
|
package reflect
|
|
|
|
import (
|
|
"runtime"
|
|
"strconv"
|
|
"sync"
|
|
"unsafe"
|
|
)
|
|
|
|
// Type is the representation of a Go type.
|
|
//
|
|
// Not all methods apply to all kinds of types. Restrictions,
|
|
// if any, are noted in the documentation for each method.
|
|
// Use the Kind method to find out the kind of type before
|
|
// calling kind-specific methods. Calling a method
|
|
// inappropriate to the kind of type causes a run-time panic.
|
|
type Type interface {
|
|
// Methods applicable to all types.
|
|
|
|
// Align returns the alignment in bytes of a value of
|
|
// this type when allocated in memory.
|
|
Align() int
|
|
|
|
// FieldAlign returns the alignment in bytes of a value of
|
|
// this type when used as a field in a struct.
|
|
FieldAlign() int
|
|
|
|
// Method returns the i'th method in the type's method set.
|
|
// It panics if i is not in the range [0, NumMethod()).
|
|
//
|
|
// 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
|
|
|
|
// MethodByName returns the method with that name in the type's
|
|
// method set and a boolean indicating if the method was found.
|
|
//
|
|
// 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.
|
|
MethodByName(string) (Method, bool)
|
|
|
|
// NumMethod returns the number of methods in the type's method set.
|
|
NumMethod() int
|
|
|
|
// Name returns the type's name within its package.
|
|
// It returns an empty string for unnamed types.
|
|
Name() string
|
|
|
|
// PkgPath returns the type's package path.
|
|
// The package path is a full package import path like "encoding/base64".
|
|
// PkgPath returns an empty string for unnamed types.
|
|
PkgPath() string
|
|
|
|
// Size returns the number of bytes needed to store
|
|
// a value of the given type; it is analogous to unsafe.Sizeof.
|
|
Size() uintptr
|
|
|
|
// String returns a string representation of the type.
|
|
// The string representation may use shortened package names
|
|
// (e.g., base64 instead of "encoding/base64") and is not
|
|
// guaranteed to be unique among types. To test for equality,
|
|
// compare the Types directly.
|
|
String() string
|
|
|
|
// Kind returns the specific kind of this type.
|
|
Kind() Kind
|
|
|
|
// Implements returns true if the type implements the interface type u.
|
|
Implements(u Type) bool
|
|
|
|
// AssignableTo returns true if a value of the type is assignable to type u.
|
|
AssignableTo(u Type) bool
|
|
|
|
// Methods applicable only to some types, depending on Kind.
|
|
// The methods allowed for each kind are:
|
|
//
|
|
// Int*, Uint*, Float*, Complex*: Bits
|
|
// Array: Elem, Len
|
|
// Chan: ChanDir, Elem
|
|
// Func: In, NumIn, Out, NumOut, IsVariadic.
|
|
// Map: Key, Elem
|
|
// Ptr: Elem
|
|
// Slice: Elem
|
|
// Struct: Field, FieldByIndex, FieldByName, FieldByNameFunc, NumField
|
|
|
|
// Bits returns the size of the type in bits.
|
|
// It panics if the type's Kind is not one of the
|
|
// sized or unsized Int, Uint, Float, or Complex kinds.
|
|
Bits() int
|
|
|
|
// ChanDir returns a channel type's direction.
|
|
// It panics if the type's Kind is not Chan.
|
|
ChanDir() ChanDir
|
|
|
|
// IsVariadic returns true if a function type's final input parameter
|
|
// is a "..." parameter. If so, t.In(t.NumIn() - 1) returns the parameter's
|
|
// implicit actual type []T.
|
|
//
|
|
// For concreteness, if t represents func(x int, y ... float64), then
|
|
//
|
|
// t.NumIn() == 2
|
|
// t.In(0) is the reflect.Type for "int"
|
|
// t.In(1) is the reflect.Type for "[]float64"
|
|
// t.IsVariadic() == true
|
|
//
|
|
// IsVariadic panics if the type's Kind is not Func.
|
|
IsVariadic() bool
|
|
|
|
// Elem returns a type's element type.
|
|
// It panics if the type's Kind is not Array, Chan, Map, Ptr, or Slice.
|
|
Elem() Type
|
|
|
|
// Field returns a struct type's i'th field.
|
|
// It panics if the type's Kind is not Struct.
|
|
// It panics if i is not in the range [0, NumField()).
|
|
Field(i int) StructField
|
|
|
|
// FieldByIndex returns the nested field corresponding
|
|
// to the index sequence. It is equivalent to calling Field
|
|
// successively for each index i.
|
|
// It panics if the type's Kind is not Struct.
|
|
FieldByIndex(index []int) StructField
|
|
|
|
// FieldByName returns the struct field with the given name
|
|
// and a boolean indicating if the field was found.
|
|
FieldByName(name string) (StructField, bool)
|
|
|
|
// FieldByNameFunc returns the first struct field with a name
|
|
// that satisfies the match function and a boolean indicating if
|
|
// the field was found.
|
|
FieldByNameFunc(match func(string) bool) (StructField, bool)
|
|
|
|
// In returns the type of a function type's i'th input parameter.
|
|
// It panics if the type's Kind is not Func.
|
|
// It panics if i is not in the range [0, NumIn()).
|
|
In(i int) Type
|
|
|
|
// Key returns a map type's key type.
|
|
// It panics if the type's Kind is not Map.
|
|
Key() Type
|
|
|
|
// Len returns an array type's length.
|
|
// It panics if the type's Kind is not Array.
|
|
Len() int
|
|
|
|
// NumField returns a struct type's field count.
|
|
// It panics if the type's Kind is not Struct.
|
|
NumField() int
|
|
|
|
// NumIn returns a function type's input parameter count.
|
|
// It panics if the type's Kind is not Func.
|
|
NumIn() int
|
|
|
|
// NumOut returns a function type's output parameter count.
|
|
// It panics if the type's Kind is not Func.
|
|
NumOut() int
|
|
|
|
// Out returns the type of a function type's i'th output parameter.
|
|
// It panics if the type's Kind is not Func.
|
|
// It panics if i is not in the range [0, NumOut()).
|
|
Out(i int) Type
|
|
|
|
runtimeType() *runtime.Type
|
|
common() *commonType
|
|
uncommon() *uncommonType
|
|
}
|
|
|
|
// A Kind represents the specific kind of type that a Type represents.
|
|
// The zero Kind is not a valid kind.
|
|
type Kind uint
|
|
|
|
const (
|
|
Invalid Kind = iota
|
|
Bool
|
|
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
|
|
)
|
|
|
|
/*
|
|
* 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 `reflect:"array"` or `reflect:"ptr"`
|
|
// so that code cannot convert from, say, *arrayType to *ptrType.
|
|
|
|
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
|
|
}
|
|
|
|
// ChanDir represents a channel type's direction.
|
|
type ChanDir int
|
|
|
|
const (
|
|
RecvDir ChanDir = 1 << iota
|
|
SendDir
|
|
BothDir = RecvDir | SendDir
|
|
)
|
|
|
|
// arrayType represents a fixed array type.
|
|
type arrayType struct {
|
|
commonType `reflect:"array"`
|
|
elem *runtime.Type
|
|
slice *runtime.Type
|
|
len uintptr
|
|
}
|
|
|
|
// chanType represents a channel type.
|
|
type chanType struct {
|
|
commonType `reflect:"chan"`
|
|
elem *runtime.Type
|
|
dir uintptr
|
|
}
|
|
|
|
// funcType represents a function type.
|
|
type funcType struct {
|
|
commonType `reflect:"func"`
|
|
dotdotdot bool
|
|
in []*runtime.Type
|
|
out []*runtime.Type
|
|
}
|
|
|
|
// imethod represents a method on an interface type
|
|
type imethod struct {
|
|
name *string
|
|
pkgPath *string
|
|
typ *runtime.Type
|
|
}
|
|
|
|
// interfaceType represents an interface type.
|
|
type interfaceType struct {
|
|
commonType `reflect:"interface"`
|
|
methods []imethod
|
|
}
|
|
|
|
// mapType represents a map type.
|
|
type mapType struct {
|
|
commonType `reflect:"map"`
|
|
key *runtime.Type
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// ptrType represents a pointer type.
|
|
type ptrType struct {
|
|
commonType `reflect:"ptr"`
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// sliceType represents a slice type.
|
|
type sliceType struct {
|
|
commonType `reflect:"slice"`
|
|
elem *runtime.Type
|
|
}
|
|
|
|
// 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 `reflect:"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 Type
|
|
Func Value
|
|
Index int
|
|
}
|
|
|
|
// 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{
|
|
Invalid: "invalid",
|
|
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) toType() Type {
|
|
if t == nil {
|
|
return nil
|
|
}
|
|
return canonicalize(t)
|
|
}
|
|
|
|
func (t *commonType) String() string { return *t.string }
|
|
|
|
func (t *commonType) Size() uintptr { return t.size }
|
|
|
|
func (t *commonType) Bits() int {
|
|
if t == nil {
|
|
panic("reflect: Bits of nil Type")
|
|
}
|
|
k := t.Kind()
|
|
if k < Int || k > Complex128 {
|
|
panic("reflect: Bits of non-arithmetic Type " + t.String())
|
|
}
|
|
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) {
|
|
panic("reflect: Method index out of range")
|
|
}
|
|
p := &t.methods[i]
|
|
if p.name != nil {
|
|
m.Name = *p.name
|
|
}
|
|
fl := flag(Func) << flagKindShift
|
|
if p.pkgPath != nil {
|
|
m.PkgPath = *p.pkgPath
|
|
fl |= flagRO
|
|
}
|
|
mt := toCommonType(p.typ)
|
|
m.Type = mt.toType()
|
|
x := new(unsafe.Pointer)
|
|
*x = p.tfn
|
|
m.Func = Value{mt, unsafe.Pointer(x), fl|flagIndir}
|
|
m.Index = i
|
|
return
|
|
}
|
|
|
|
func (t *uncommonType) NumMethod() int {
|
|
if t == nil {
|
|
return 0
|
|
}
|
|
return len(t.methods)
|
|
}
|
|
|
|
func (t *uncommonType) MethodByName(name string) (m Method, ok bool) {
|
|
if t == nil {
|
|
return
|
|
}
|
|
var p *method
|
|
for i := range t.methods {
|
|
p = &t.methods[i]
|
|
if p.name != nil && *p.name == name {
|
|
return t.Method(i), true
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// 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 {
|
|
if t.Kind() == Interface {
|
|
tt := (*interfaceType)(unsafe.Pointer(t))
|
|
return tt.NumMethod()
|
|
}
|
|
return t.uncommonType.NumMethod()
|
|
}
|
|
|
|
func (t *commonType) Method(i int) (m Method) {
|
|
if t.Kind() == Interface {
|
|
tt := (*interfaceType)(unsafe.Pointer(t))
|
|
return tt.Method(i)
|
|
}
|
|
return t.uncommonType.Method(i)
|
|
}
|
|
|
|
func (t *commonType) MethodByName(name string) (m Method, ok bool) {
|
|
if t.Kind() == Interface {
|
|
tt := (*interfaceType)(unsafe.Pointer(t))
|
|
return tt.MethodByName(name)
|
|
}
|
|
return t.uncommonType.MethodByName(name)
|
|
}
|
|
|
|
func (t *commonType) PkgPath() string {
|
|
return t.uncommonType.PkgPath()
|
|
}
|
|
|
|
func (t *commonType) Name() string {
|
|
return t.uncommonType.Name()
|
|
}
|
|
|
|
func (t *commonType) ChanDir() ChanDir {
|
|
if t.Kind() != Chan {
|
|
panic("reflect: ChanDir of non-chan type")
|
|
}
|
|
tt := (*chanType)(unsafe.Pointer(t))
|
|
return ChanDir(tt.dir)
|
|
}
|
|
|
|
func (t *commonType) IsVariadic() bool {
|
|
if t.Kind() != Func {
|
|
panic("reflect: IsVariadic of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return tt.dotdotdot
|
|
}
|
|
|
|
func (t *commonType) Elem() Type {
|
|
switch t.Kind() {
|
|
case Array:
|
|
tt := (*arrayType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Chan:
|
|
tt := (*chanType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Map:
|
|
tt := (*mapType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Ptr:
|
|
tt := (*ptrType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
case Slice:
|
|
tt := (*sliceType)(unsafe.Pointer(t))
|
|
return toType(tt.elem)
|
|
}
|
|
panic("reflect; Elem of invalid type")
|
|
}
|
|
|
|
func (t *commonType) Field(i int) StructField {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: Field of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return tt.Field(i)
|
|
}
|
|
|
|
func (t *commonType) FieldByIndex(index []int) StructField {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: FieldByIndex of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return tt.FieldByIndex(index)
|
|
}
|
|
|
|
func (t *commonType) FieldByName(name string) (StructField, bool) {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: FieldByName of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return tt.FieldByName(name)
|
|
}
|
|
|
|
func (t *commonType) FieldByNameFunc(match func(string) bool) (StructField, bool) {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: FieldByNameFunc of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return tt.FieldByNameFunc(match)
|
|
}
|
|
|
|
func (t *commonType) In(i int) Type {
|
|
if t.Kind() != Func {
|
|
panic("reflect: In of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return toType(tt.in[i])
|
|
}
|
|
|
|
func (t *commonType) Key() Type {
|
|
if t.Kind() != Map {
|
|
panic("reflect: Key of non-map type")
|
|
}
|
|
tt := (*mapType)(unsafe.Pointer(t))
|
|
return toType(tt.key)
|
|
}
|
|
|
|
func (t *commonType) Len() int {
|
|
if t.Kind() != Array {
|
|
panic("reflect: Len of non-array type")
|
|
}
|
|
tt := (*arrayType)(unsafe.Pointer(t))
|
|
return int(tt.len)
|
|
}
|
|
|
|
func (t *commonType) NumField() int {
|
|
if t.Kind() != Struct {
|
|
panic("reflect: NumField of non-struct type")
|
|
}
|
|
tt := (*structType)(unsafe.Pointer(t))
|
|
return len(tt.fields)
|
|
}
|
|
|
|
func (t *commonType) NumIn() int {
|
|
if t.Kind() != Func {
|
|
panic("reflect; NumIn of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return len(tt.in)
|
|
}
|
|
|
|
func (t *commonType) NumOut() int {
|
|
if t.Kind() != Func {
|
|
panic("reflect; NumOut of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return len(tt.out)
|
|
}
|
|
|
|
func (t *commonType) Out(i int) Type {
|
|
if t.Kind() != Func {
|
|
panic("reflect: Out of non-func type")
|
|
}
|
|
tt := (*funcType)(unsafe.Pointer(t))
|
|
return toType(tt.out[i])
|
|
}
|
|
|
|
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))
|
|
}
|
|
|
|
// 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 = toType(p.typ)
|
|
m.Index = i
|
|
return
|
|
}
|
|
|
|
// NumMethod returns the number of interface methods in the type's method set.
|
|
func (t *interfaceType) NumMethod() int { return len(t.methods) }
|
|
|
|
// MethodByName method with the given name in the type's method set.
|
|
func (t *interfaceType) MethodByName(name string) (m Method, ok bool) {
|
|
if t == nil {
|
|
return
|
|
}
|
|
var p *imethod
|
|
for i := range t.methods {
|
|
p = &t.methods[i]
|
|
if *p.name == name {
|
|
return t.Method(i), true
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
type StructField struct {
|
|
PkgPath string // empty for uppercase Name
|
|
Name string
|
|
Type Type
|
|
Tag StructTag
|
|
Offset uintptr
|
|
Index []int
|
|
Anonymous bool
|
|
}
|
|
|
|
// A StructTag is the tag string in a struct field.
|
|
//
|
|
// By convention, tag strings are a concatenation of
|
|
// optionally space-separated key:"value" pairs.
|
|
// Each key is a non-empty string consisting of non-control
|
|
// characters other than space (U+0020 ' '), quote (U+0022 '"'),
|
|
// and colon (U+003A ':'). Each value is quoted using U+0022 '"'
|
|
// characters and Go string literal syntax.
|
|
type StructTag string
|
|
|
|
// Get returns the value associated with key in the tag string.
|
|
// If there is no such key in the tag, Get returns the empty string.
|
|
// If the tag does not have the conventional format, the value
|
|
// returned by Get is unspecified.
|
|
func (tag StructTag) Get(key string) string {
|
|
for tag != "" {
|
|
// skip leading space
|
|
i := 0
|
|
for i < len(tag) && tag[i] == ' ' {
|
|
i++
|
|
}
|
|
tag = tag[i:]
|
|
if tag == "" {
|
|
break
|
|
}
|
|
|
|
// scan to colon.
|
|
// a space or a quote is a syntax error
|
|
i = 0
|
|
for i < len(tag) && tag[i] != ' ' && tag[i] != ':' && tag[i] != '"' {
|
|
i++
|
|
}
|
|
if i+1 >= len(tag) || tag[i] != ':' || tag[i+1] != '"' {
|
|
break
|
|
}
|
|
name := string(tag[:i])
|
|
tag = tag[i+1:]
|
|
|
|
// scan quoted string to find value
|
|
i = 1
|
|
for i < len(tag) && tag[i] != '"' {
|
|
if tag[i] == '\\' {
|
|
i++
|
|
}
|
|
i++
|
|
}
|
|
if i >= len(tag) {
|
|
break
|
|
}
|
|
qvalue := string(tag[:i+1])
|
|
tag = tag[i+1:]
|
|
|
|
if key == name {
|
|
value, _ := strconv.Unquote(qvalue)
|
|
return value
|
|
}
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// 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 = toType(p.typ)
|
|
if p.name != nil {
|
|
f.Name = *p.name
|
|
} else {
|
|
t := f.Type
|
|
if t.Kind() == Ptr {
|
|
t = t.Elem()
|
|
}
|
|
f.Name = t.Name()
|
|
f.Anonymous = true
|
|
}
|
|
if p.pkgPath != nil {
|
|
f.PkgPath = *p.pkgPath
|
|
}
|
|
if p.tag != nil {
|
|
f.Tag = StructTag(*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) {
|
|
f.Type = Type(t.toType())
|
|
for i, x := range index {
|
|
if i > 0 {
|
|
ft := f.Type
|
|
if ft.Kind() == Ptr && ft.Elem().Kind() == Struct {
|
|
ft = ft.Elem()
|
|
}
|
|
f.Type = ft
|
|
}
|
|
f = f.Type.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 ft.Kind() == Ptr {
|
|
ft = ft.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 ft.Kind() == Struct {
|
|
st := (*structType)(unsafe.Pointer(ft.(*commonType)))
|
|
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 depth >= len(ff.Index) {
|
|
ff.Index = make([]int, depth+1)
|
|
}
|
|
if len(ff.Index) > 1 {
|
|
ff.Index[depth] = fi
|
|
}
|
|
} else {
|
|
// None or more than one matching field found.
|
|
fd = inf
|
|
}
|
|
|
|
delete(mark, t)
|
|
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
|
|
}
|
|
|
|
// Convert runtime type to reflect type.
|
|
func toCommonType(p *runtime.Type) *commonType {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
x := unsafe.Pointer(p)
|
|
return (*commonType)(x)
|
|
}
|
|
|
|
// Canonicalize a Type.
|
|
var canonicalType = make(map[string]Type)
|
|
|
|
var canonicalTypeLock sync.RWMutex
|
|
|
|
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.RLock()
|
|
if r, ok := canonicalType[s]; ok {
|
|
canonicalTypeLock.RUnlock()
|
|
return r
|
|
}
|
|
canonicalTypeLock.RUnlock()
|
|
canonicalTypeLock.Lock()
|
|
if r, ok := canonicalType[s]; ok {
|
|
canonicalTypeLock.Unlock()
|
|
return r
|
|
}
|
|
canonicalType[s] = t
|
|
canonicalTypeLock.Unlock()
|
|
return t
|
|
}
|
|
|
|
func toType(p *runtime.Type) Type {
|
|
if p == nil {
|
|
return nil
|
|
}
|
|
return toCommonType(p).toType()
|
|
}
|
|
|
|
// TypeOf returns the reflection Type of the value in the interface{}.
|
|
func TypeOf(i interface{}) Type {
|
|
eface := *(*emptyInterface)(unsafe.Pointer(&i))
|
|
return toType(eface.typ)
|
|
}
|
|
|
|
// ptrMap is the cache for PtrTo.
|
|
var ptrMap struct {
|
|
sync.RWMutex
|
|
m map[*commonType]*ptrType
|
|
}
|
|
|
|
func (t *commonType) runtimeType() *runtime.Type {
|
|
return (*runtime.Type)(unsafe.Pointer(t))
|
|
}
|
|
|
|
// PtrTo returns the pointer type with element t.
|
|
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
|
|
func PtrTo(t Type) Type {
|
|
return t.(*commonType).ptrTo()
|
|
}
|
|
|
|
func (ct *commonType) ptrTo() *commonType {
|
|
if p := ct.ptrToThis; p != nil {
|
|
return toCommonType(p)
|
|
}
|
|
|
|
// 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[ct]; p != nil {
|
|
ptrMap.RUnlock()
|
|
return &p.commonType
|
|
}
|
|
}
|
|
ptrMap.RUnlock()
|
|
ptrMap.Lock()
|
|
if ptrMap.m == nil {
|
|
ptrMap.m = make(map[*commonType]*ptrType)
|
|
}
|
|
p := ptrMap.m[ct]
|
|
if p != nil {
|
|
// some other goroutine won the race and created it
|
|
ptrMap.Unlock()
|
|
return &p.commonType
|
|
}
|
|
|
|
rt := (*runtime.Type)(unsafe.Pointer(ct))
|
|
|
|
rp := new(runtime.PtrType)
|
|
|
|
// initialize p using *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 = (*runtime.Type)(unsafe.Pointer(ct))
|
|
|
|
ptrMap.m[ct] = p
|
|
ptrMap.Unlock()
|
|
return &p.commonType
|
|
}
|
|
|
|
func (t *commonType) Implements(u Type) bool {
|
|
if u == nil {
|
|
panic("reflect: nil type passed to Type.Implements")
|
|
}
|
|
if u.Kind() != Interface {
|
|
panic("reflect: non-interface type passed to Type.Implements")
|
|
}
|
|
return implements(u.(*commonType), t)
|
|
}
|
|
|
|
func (t *commonType) AssignableTo(u Type) bool {
|
|
if u == nil {
|
|
panic("reflect: nil type passed to Type.AssignableTo")
|
|
}
|
|
uu := u.(*commonType)
|
|
return directlyAssignable(uu, t) || implements(uu, t)
|
|
}
|
|
|
|
// implements returns true if the type V implements the interface type T.
|
|
func implements(T, V *commonType) bool {
|
|
if T.Kind() != Interface {
|
|
return false
|
|
}
|
|
t := (*interfaceType)(unsafe.Pointer(T))
|
|
if len(t.methods) == 0 {
|
|
return true
|
|
}
|
|
|
|
// The same algorithm applies in both cases, but the
|
|
// method tables for an interface type and a concrete type
|
|
// are different, so the code is duplicated.
|
|
// In both cases the algorithm is a linear scan over the two
|
|
// lists - T's methods and V's methods - simultaneously.
|
|
// Since method tables are stored in a unique sorted order
|
|
// (alphabetical, with no duplicate method names), the scan
|
|
// through V's methods must hit a match for each of T's
|
|
// methods along the way, or else V does not implement T.
|
|
// This lets us run the scan in overall linear time instead of
|
|
// the quadratic time a naive search would require.
|
|
// See also ../runtime/iface.c.
|
|
if V.Kind() == Interface {
|
|
v := (*interfaceType)(unsafe.Pointer(V))
|
|
i := 0
|
|
for j := 0; j < len(v.methods); j++ {
|
|
tm := &t.methods[i]
|
|
vm := &v.methods[j]
|
|
if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.typ).common() == toType(tm.typ).common() {
|
|
if i++; i >= len(t.methods) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
v := V.uncommon()
|
|
if v == nil {
|
|
return false
|
|
}
|
|
i := 0
|
|
for j := 0; j < len(v.methods); j++ {
|
|
tm := &t.methods[i]
|
|
vm := &v.methods[j]
|
|
if *vm.name == *tm.name && (vm.pkgPath == tm.pkgPath || (vm.pkgPath != nil && tm.pkgPath != nil && *vm.pkgPath == *tm.pkgPath)) && toType(vm.mtyp).common() == toType(tm.typ).common() {
|
|
if i++; i >= len(t.methods) {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// directlyAssignable returns true if a value x of type V can be directly
|
|
// assigned (using memmove) to a value of type T.
|
|
// http://golang.org/doc/go_spec.html#Assignability
|
|
// Ignoring the interface rules (implemented elsewhere)
|
|
// and the ideal constant rules (no ideal constants at run time).
|
|
func directlyAssignable(T, V *commonType) bool {
|
|
// x's type V is identical to T?
|
|
if T == V {
|
|
return true
|
|
}
|
|
|
|
// Otherwise at least one of T and V must be unnamed
|
|
// and they must have the same kind.
|
|
if T.Name() != "" && V.Name() != "" || T.Kind() != V.Kind() {
|
|
return false
|
|
}
|
|
|
|
// x's type T and V have identical underlying types.
|
|
// Since at least one is unnamed, only the composite types
|
|
// need to be considered.
|
|
switch T.Kind() {
|
|
case Array:
|
|
return T.Elem() == V.Elem() && T.Len() == V.Len()
|
|
|
|
case Chan:
|
|
// Special case:
|
|
// x is a bidirectional channel value, T is a channel type,
|
|
// and x's type V and T have identical element types.
|
|
if V.ChanDir() == BothDir && T.Elem() == V.Elem() {
|
|
return true
|
|
}
|
|
|
|
// Otherwise continue test for identical underlying type.
|
|
return V.ChanDir() == T.ChanDir() && T.Elem() == V.Elem()
|
|
|
|
case Func:
|
|
t := (*funcType)(unsafe.Pointer(T))
|
|
v := (*funcType)(unsafe.Pointer(V))
|
|
if t.dotdotdot != v.dotdotdot || len(t.in) != len(v.in) || len(t.out) != len(v.out) {
|
|
return false
|
|
}
|
|
for i, typ := range t.in {
|
|
if typ != v.in[i] {
|
|
return false
|
|
}
|
|
}
|
|
for i, typ := range t.out {
|
|
if typ != v.out[i] {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
|
|
case Interface:
|
|
t := (*interfaceType)(unsafe.Pointer(T))
|
|
v := (*interfaceType)(unsafe.Pointer(V))
|
|
if len(t.methods) == 0 && len(v.methods) == 0 {
|
|
return true
|
|
}
|
|
// Might have the same methods but still
|
|
// need a run time conversion.
|
|
return false
|
|
|
|
case Map:
|
|
return T.Key() == V.Key() && T.Elem() == V.Elem()
|
|
|
|
case Ptr, Slice:
|
|
return T.Elem() == V.Elem()
|
|
|
|
case Struct:
|
|
t := (*structType)(unsafe.Pointer(T))
|
|
v := (*structType)(unsafe.Pointer(V))
|
|
if len(t.fields) != len(v.fields) {
|
|
return false
|
|
}
|
|
for i := range t.fields {
|
|
tf := &t.fields[i]
|
|
vf := &v.fields[i]
|
|
if tf.name != vf.name || tf.pkgPath != vf.pkgPath ||
|
|
tf.typ != vf.typ || tf.tag != vf.tag || tf.offset != vf.offset {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
return false
|
|
}
|