// 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

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() string;

	// Name returns the type's name within its package.
	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 *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));
}
