// 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";
"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.
*/
type commonType struct {
size uintptr;
hash uint32;
alg uint8;
align uint8;
fieldAlign uint8;
string *string;
*uncommonType;
}
type method struct {
hash uint32;
name *string;
pkgPath *string;
typ *runtime.Type;
ifn unsafe.Pointer;
tfn unsafe.Pointer;
}
type uncommonType struct {
name *string;
pkgPath *string;
methods []method;
}
// BoolType represents a boolean type.
type BoolType struct {
commonType;
}
// Float32Type represents a float32 type.
type Float32Type struct {
commonType;
}
// Float64Type represents a float64 type.
type Float64Type struct {
commonType;
}
// FloatType represents a float type.
type FloatType struct {
commonType;
}
// Int16Type represents an int16 type.
type Int16Type struct {
commonType;
}
// Int32Type represents an int32 type.
type Int32Type struct {
commonType;
}
// Int64Type represents an int64 type.
type Int64Type struct {
commonType;
}
// Int8Type represents an int8 type.
type Int8Type struct {
commonType;
}
// IntType represents an int type.
type IntType struct {
commonType;
}
// Uint16Type represents a uint16 type.
type Uint16Type struct {
commonType;
}
// Uint32Type represents a uint32 type.
type Uint32Type struct {
commonType;
}
// Uint64Type represents a uint64 type.
type Uint64Type struct {
commonType;
}
// Uint8Type represents a uint8 type.
type Uint8Type struct {
commonType;
}
// UintType represents a uint type.
type UintType struct {
commonType;
}
// StringType represents a string type.
type StringType struct {
commonType;
}
// UintptrType represents a uintptr type.
type UintptrType struct {
commonType;
}
// DotDotDotType represents the ... that can
// be used as the type of the final function parameter.
type DotDotDotType struct {
commonType;
}
// UnsafePointerType represents an unsafe.Pointer type.
type UnsafePointerType struct {
commonType;
}
// ArrayType represents a fixed array type.
type ArrayType struct {
commonType;
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;
elem *runtime.Type;
dir uintptr;
}
// FuncType represents a function type.
type FuncType struct {
commonType;
in []*runtime.Type;
out []*runtime.Type;
}
// Method on interface type
type imethod struct {
hash uint32;
perm uint32;
name *string;
pkgPath *string;
typ *runtime.Type;
}
// InterfaceType represents an interface type.
type InterfaceType struct {
commonType;
methods []imethod;
}
// MapType represents a map type.
type MapType struct {
commonType;
key *runtime.Type;
elem *runtime.Type;
}
// PtrType represents a pointer type.
type PtrType struct {
commonType;
elem *runtime.Type;
}
// SliceType represents a slice type.
type SliceType struct {
commonType;
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;
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;
// 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;
// For non-interface types, Method returns the i'th method with receiver T.
// For interface types, Method returns the i'th method in the interface.
// NumMethod returns the number of such methods.
Method(int) Method;
NumMethod() int;
uncommon() *uncommonType;
}
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) Align() int { return int(t.align) }
func (t *commonType) FieldAlign() int { return int(t.fieldAlign) }
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 = toType(*p.typ).(*FuncType);
fn := p.tfn;
m.Func = newFuncValue(m.Type, addr(&fn), true);
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 toType(*t.elem) }
// 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 toType(*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 toType(*t.in[i]);
}
// 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 toType(*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 interface method.
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).(*FuncType);
return;
}
// NumMethod returns the number of interface methods.
func (t *InterfaceType) NumMethod() int { return len(t.methods) }
// Key returns the map key type.
func (t *MapType) Key() Type { return toType(*t.key) }
// Elem returns the map element type.
func (t *MapType) Elem() Type { return toType(*t.elem) }
// Elem returns the pointer element type.
func (t *PtrType) Elem() Type { return toType(*t.elem) }
// Elem returns the type of the slice's elements.
func (t *SliceType) Elem() Type { return toType(*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 = toType(*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) fieldByName(name string, mark map[*StructType]bool, depth int) (ff StructField, fd int) {
fd = inf; // field depth
if _, marked := mark[t]; marked {
// 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 f.Name == name:
// Matching top-level field.
d = depth
case f.Anonymous:
ft := f.Type;
if pt, ok := ft.(*PtrType); ok {
ft = pt.Elem()
}
switch {
case ft.Name() == 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.fieldByName(name, 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) {
if ff, fd := t.fieldByName(name, 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) }
// 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.DotDotDotType:
return (*DotDotDotType)(unsafe.Pointer(v))
case *runtime.FloatType:
return (*FloatType)(unsafe.Pointer(v))
case *runtime.Float32Type:
return (*Float32Type)(unsafe.Pointer(v))
case *runtime.Float64Type:
return (*Float64Type)(unsafe.Pointer(v))
case *runtime.IntType:
return (*IntType)(unsafe.Pointer(v))
case *runtime.Int8Type:
return (*Int8Type)(unsafe.Pointer(v))
case *runtime.Int16Type:
return (*Int16Type)(unsafe.Pointer(v))
case *runtime.Int32Type:
return (*Int32Type)(unsafe.Pointer(v))
case *runtime.Int64Type:
return (*Int64Type)(unsafe.Pointer(v))
case *runtime.StringType:
return (*StringType)(unsafe.Pointer(v))
case *runtime.UintType:
return (*UintType)(unsafe.Pointer(v))
case *runtime.Uint8Type:
return (*Uint8Type)(unsafe.Pointer(v))
case *runtime.Uint16Type:
return (*Uint16Type)(unsafe.Pointer(v))
case *runtime.Uint32Type:
return (*Uint32Type)(unsafe.Pointer(v))
case *runtime.Uint64Type:
return (*Uint64Type)(unsafe.Pointer(v))
case *runtime.UintptrType:
return (*UintptrType)(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))
}
panicln("toType", i);
}
// ArrayOrSliceType is the common interface implemented
// by both ArrayType and SliceType.
type ArrayOrSliceType interface {
Type;
Elem() Type;
}
// Typeof returns the reflection Type of the value in the interface{}.
func Typeof(i interface{}) Type { return toType(unsafe.Typeof(i)) }
|