summaryrefslogtreecommitdiff
path: root/libgo/go/reflect/type.go
diff options
context:
space:
mode:
Diffstat (limited to 'libgo/go/reflect/type.go')
-rw-r--r--libgo/go/reflect/type.go743
1 files changed, 743 insertions, 0 deletions
diff --git a/libgo/go/reflect/type.go b/libgo/go/reflect/type.go
new file mode 100644
index 000000000..4ad4c5f2b
--- /dev/null
+++ b/libgo/go/reflect/type.go
@@ -0,0 +1,743 @@
+// 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
+}
+
+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
+}
+
+// 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
+
+ // 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
+}
+
+// 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 *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), 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 runtimeToType(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 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 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 = runtimeToType(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 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
+}
+
+// Typeof returns the reflection Type of the value in the interface{}.
+func Typeof(i interface{}) Type { return canonicalize(toType(unsafe.Typeof(i))) }