Go Home Page
The Go Programming Language

Source file src/pkg/reflect/type.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"
    "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 {
    name    *string
    pkgPath *string
    mtyp    *runtime.Type
    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
}

// Complex64Type represents a complex64 type.
type Complex64Type struct {
    commonType
}

// Complex128Type represents acomplex128 type.
type Complex128Type struct {
    commonType
}

// ComplexType represents a complex type.
type ComplexType 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
}

// 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
    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
    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])
}

// DotDotDot returns true if the final function input parameter
// is a "..." parameter.  If so, the parameter's underlying static
// type - either interface{} or []T - is returned by t.In(t.NumIn() - 1).
//
// 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 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.FloatType:
        return (*FloatType)(unsafe.Pointer(v))
    case *runtime.Float32Type:
        return (*Float32Type)(unsafe.Pointer(v))
    case *runtime.Float64Type:
        return (*Float64Type)(unsafe.Pointer(v))
    case *runtime.ComplexType:
        return (*ComplexType)(unsafe.Pointer(v))
    case *runtime.Complex64Type:
        return (*Complex64Type)(unsafe.Pointer(v))
    case *runtime.Complex128Type:
        return (*Complex128Type)(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)) }