mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
reflect: new Type and Value definitions
Type is now an interface that implements all the possible type methods.
Instead of a type switch on a reflect.Type t, switch on t.Kind().
If a method is invoked on the wrong kind of type (for example,
calling t.Field(0) when t.Kind() != Struct), the call panics.
There is one method renaming: t.(*ChanType).Dir() is now t.ChanDir().
Value is now a struct value that implements all the possible value methods.
Instead of a type switch on a reflect.Value v, switch on v.Kind().
If a method is invoked on the wrong kind of value (for example,
calling t.Recv() when t.Kind() != Chan), the call panics.
Since Value is now a struct, not an interface, its zero value
cannot be compared to nil. Instead of v != nil, use v.IsValid().
Instead of other uses of nil as a Value, use Value{}, the zero value.
Many methods have been renamed, most due to signature conflicts:
OLD NEW
v.(*ArrayValue).Elem v.Index
v.(*BoolValue).Get v.Bool
v.(*BoolValue).Set v.SetBool
v.(*ChanType).Dir v.ChanDir
v.(*ChanValue).Get v.Pointer
v.(*ComplexValue).Get v.Complex
v.(*ComplexValue).Overflow v.OverflowComplex
v.(*ComplexValue).Set v.SetComplex
v.(*FloatValue).Get v.Float
v.(*FloatValue).Overflow v.OverflowFloat
v.(*FloatValue).Set v.SetFloat
v.(*FuncValue).Get v.Pointer
v.(*InterfaceValue).Get v.InterfaceData
v.(*IntValue).Get v.Int
v.(*IntValue).Overflow v.OverflowInt
v.(*IntValue).Set v.SetInt
v.(*MapValue).Elem v.MapIndex
v.(*MapValue).Get v.Pointer
v.(*MapValue).Keys v.MapKeys
v.(*MapValue).SetElem v.SetMapIndex
v.(*PtrValue).Get v.Pointer
v.(*SliceValue).Elem v.Index
v.(*SliceValue).Get v.Pointer
v.(*StringValue).Get v.String
v.(*StringValue).Set v.SetString
v.(*UintValue).Get v.Uint
v.(*UintValue).Overflow v.OverflowUint
v.(*UintValue).Set v.SetUint
v.(*UnsafePointerValue).Get v.Pointer
v.(*UnsafePointerValue).Set v.SetPointer
Part of the motivation for this change is to enable a more
efficient implementation of Value, one that does not allocate
memory during most operations. To reduce the size of the CL,
this CL's implementation is a wrapper around the old API.
Later CLs will make the implementation more efficient without
changing the API.
Other CLs to be submitted at the same time as this one
add support for this change to gofix (4343047) and update
the Go source tree (4353043).
R=gri, iant, niemeyer, r, rog, gustavo, r2
CC=golang-dev
https://golang.org/cl/4281055
This commit is contained in:
parent
846a368b88
commit
fb175cf77e
5 changed files with 1437 additions and 888 deletions
|
|
@ -207,58 +207,46 @@ func testType(t *testing.T, i int, typ Type, want string) {
|
||||||
|
|
||||||
func TestTypes(t *testing.T) {
|
func TestTypes(t *testing.T) {
|
||||||
for i, tt := range typeTests {
|
for i, tt := range typeTests {
|
||||||
testType(t, i, NewValue(tt.i).(*StructValue).Field(0).Type(), tt.s)
|
testType(t, i, NewValue(tt.i).Field(0).Type(), tt.s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSet(t *testing.T) {
|
func TestSet(t *testing.T) {
|
||||||
for i, tt := range valueTests {
|
for i, tt := range valueTests {
|
||||||
v := NewValue(tt.i)
|
v := NewValue(tt.i)
|
||||||
switch v := v.(type) {
|
switch v.Kind() {
|
||||||
case *IntValue:
|
case Int:
|
||||||
switch v.Type().Kind() {
|
v.SetInt(132)
|
||||||
case Int:
|
case Int8:
|
||||||
v.Set(132)
|
v.SetInt(8)
|
||||||
case Int8:
|
case Int16:
|
||||||
v.Set(8)
|
v.SetInt(16)
|
||||||
case Int16:
|
case Int32:
|
||||||
v.Set(16)
|
v.SetInt(32)
|
||||||
case Int32:
|
case Int64:
|
||||||
v.Set(32)
|
v.SetInt(64)
|
||||||
case Int64:
|
case Uint:
|
||||||
v.Set(64)
|
v.SetUint(132)
|
||||||
}
|
case Uint8:
|
||||||
case *UintValue:
|
v.SetUint(8)
|
||||||
switch v.Type().Kind() {
|
case Uint16:
|
||||||
case Uint:
|
v.SetUint(16)
|
||||||
v.Set(132)
|
case Uint32:
|
||||||
case Uint8:
|
v.SetUint(32)
|
||||||
v.Set(8)
|
case Uint64:
|
||||||
case Uint16:
|
v.SetUint(64)
|
||||||
v.Set(16)
|
case Float32:
|
||||||
case Uint32:
|
v.SetFloat(256.25)
|
||||||
v.Set(32)
|
case Float64:
|
||||||
case Uint64:
|
v.SetFloat(512.125)
|
||||||
v.Set(64)
|
case Complex64:
|
||||||
}
|
v.SetComplex(532.125 + 10i)
|
||||||
case *FloatValue:
|
case Complex128:
|
||||||
switch v.Type().Kind() {
|
v.SetComplex(564.25 + 1i)
|
||||||
case Float32:
|
case String:
|
||||||
v.Set(256.25)
|
v.SetString("stringy cheese")
|
||||||
case Float64:
|
case Bool:
|
||||||
v.Set(512.125)
|
v.SetBool(true)
|
||||||
}
|
|
||||||
case *ComplexValue:
|
|
||||||
switch v.Type().Kind() {
|
|
||||||
case Complex64:
|
|
||||||
v.Set(532.125 + 10i)
|
|
||||||
case Complex128:
|
|
||||||
v.Set(564.25 + 1i)
|
|
||||||
}
|
|
||||||
case *StringValue:
|
|
||||||
v.Set("stringy cheese")
|
|
||||||
case *BoolValue:
|
|
||||||
v.Set(true)
|
|
||||||
}
|
}
|
||||||
s := valueToString(v)
|
s := valueToString(v)
|
||||||
if s != tt.s {
|
if s != tt.s {
|
||||||
|
|
@ -270,52 +258,39 @@ func TestSet(t *testing.T) {
|
||||||
func TestSetValue(t *testing.T) {
|
func TestSetValue(t *testing.T) {
|
||||||
for i, tt := range valueTests {
|
for i, tt := range valueTests {
|
||||||
v := NewValue(tt.i)
|
v := NewValue(tt.i)
|
||||||
switch v := v.(type) {
|
switch v.Kind() {
|
||||||
case *IntValue:
|
case Int:
|
||||||
switch v.Type().Kind() {
|
v.Set(NewValue(int(132)))
|
||||||
case Int:
|
case Int8:
|
||||||
v.SetValue(NewValue(int(132)))
|
v.Set(NewValue(int8(8)))
|
||||||
case Int8:
|
case Int16:
|
||||||
v.SetValue(NewValue(int8(8)))
|
v.Set(NewValue(int16(16)))
|
||||||
case Int16:
|
case Int32:
|
||||||
v.SetValue(NewValue(int16(16)))
|
v.Set(NewValue(int32(32)))
|
||||||
case Int32:
|
case Int64:
|
||||||
v.SetValue(NewValue(int32(32)))
|
v.Set(NewValue(int64(64)))
|
||||||
case Int64:
|
case Uint:
|
||||||
v.SetValue(NewValue(int64(64)))
|
v.Set(NewValue(uint(132)))
|
||||||
}
|
case Uint8:
|
||||||
case *UintValue:
|
v.Set(NewValue(uint8(8)))
|
||||||
switch v.Type().Kind() {
|
case Uint16:
|
||||||
case Uint:
|
v.Set(NewValue(uint16(16)))
|
||||||
v.SetValue(NewValue(uint(132)))
|
case Uint32:
|
||||||
case Uint8:
|
v.Set(NewValue(uint32(32)))
|
||||||
v.SetValue(NewValue(uint8(8)))
|
case Uint64:
|
||||||
case Uint16:
|
v.Set(NewValue(uint64(64)))
|
||||||
v.SetValue(NewValue(uint16(16)))
|
case Float32:
|
||||||
case Uint32:
|
v.Set(NewValue(float32(256.25)))
|
||||||
v.SetValue(NewValue(uint32(32)))
|
case Float64:
|
||||||
case Uint64:
|
v.Set(NewValue(512.125))
|
||||||
v.SetValue(NewValue(uint64(64)))
|
case Complex64:
|
||||||
}
|
v.Set(NewValue(complex64(532.125 + 10i)))
|
||||||
case *FloatValue:
|
case Complex128:
|
||||||
switch v.Type().Kind() {
|
v.Set(NewValue(complex128(564.25 + 1i)))
|
||||||
case Float32:
|
case String:
|
||||||
v.SetValue(NewValue(float32(256.25)))
|
v.Set(NewValue("stringy cheese"))
|
||||||
case Float64:
|
case Bool:
|
||||||
v.SetValue(NewValue(512.125))
|
v.Set(NewValue(true))
|
||||||
}
|
|
||||||
case *ComplexValue:
|
|
||||||
switch v.Type().Kind() {
|
|
||||||
case Complex64:
|
|
||||||
v.SetValue(NewValue(complex64(532.125 + 10i)))
|
|
||||||
case Complex128:
|
|
||||||
v.SetValue(NewValue(complex128(564.25 + 1i)))
|
|
||||||
}
|
|
||||||
|
|
||||||
case *StringValue:
|
|
||||||
v.SetValue(NewValue("stringy cheese"))
|
|
||||||
case *BoolValue:
|
|
||||||
v.SetValue(NewValue(true))
|
|
||||||
}
|
}
|
||||||
s := valueToString(v)
|
s := valueToString(v)
|
||||||
if s != tt.s {
|
if s != tt.s {
|
||||||
|
|
@ -350,7 +325,7 @@ func TestValueToString(t *testing.T) {
|
||||||
|
|
||||||
func TestArrayElemSet(t *testing.T) {
|
func TestArrayElemSet(t *testing.T) {
|
||||||
v := NewValue([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
v := NewValue([10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||||
v.(*ArrayValue).Elem(4).(*IntValue).Set(123)
|
v.Index(4).SetInt(123)
|
||||||
s := valueToString(v)
|
s := valueToString(v)
|
||||||
const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
|
const want = "[10]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
|
||||||
if s != want {
|
if s != want {
|
||||||
|
|
@ -358,7 +333,7 @@ func TestArrayElemSet(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
v = NewValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
v = NewValue([]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10})
|
||||||
v.(*SliceValue).Elem(4).(*IntValue).Set(123)
|
v.Index(4).SetInt(123)
|
||||||
s = valueToString(v)
|
s = valueToString(v)
|
||||||
const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
|
const want1 = "[]int{1, 2, 3, 4, 123, 6, 7, 8, 9, 10}"
|
||||||
if s != want1 {
|
if s != want1 {
|
||||||
|
|
@ -371,14 +346,14 @@ func TestPtrPointTo(t *testing.T) {
|
||||||
var i int32 = 1234
|
var i int32 = 1234
|
||||||
vip := NewValue(&ip)
|
vip := NewValue(&ip)
|
||||||
vi := NewValue(i)
|
vi := NewValue(i)
|
||||||
vip.(*PtrValue).Elem().(*PtrValue).PointTo(vi)
|
vip.Elem().Set(vi.Addr())
|
||||||
if *ip != 1234 {
|
if *ip != 1234 {
|
||||||
t.Errorf("got %d, want 1234", *ip)
|
t.Errorf("got %d, want 1234", *ip)
|
||||||
}
|
}
|
||||||
|
|
||||||
ip = nil
|
ip = nil
|
||||||
vp := NewValue(ip).(*PtrValue)
|
vp := NewValue(ip)
|
||||||
vp.PointTo(vp.Elem())
|
vp.Set(Zero(vp.Type()))
|
||||||
if ip != nil {
|
if ip != nil {
|
||||||
t.Errorf("got non-nil (%p), want nil", ip)
|
t.Errorf("got non-nil (%p), want nil", ip)
|
||||||
}
|
}
|
||||||
|
|
@ -388,7 +363,7 @@ func TestPtrSetNil(t *testing.T) {
|
||||||
var i int32 = 1234
|
var i int32 = 1234
|
||||||
ip := &i
|
ip := &i
|
||||||
vip := NewValue(&ip)
|
vip := NewValue(&ip)
|
||||||
vip.(*PtrValue).Elem().(*PtrValue).Set(nil)
|
vip.Elem().Set(Zero(vip.Elem().Type()))
|
||||||
if ip != nil {
|
if ip != nil {
|
||||||
t.Errorf("got non-nil (%d), want nil", *ip)
|
t.Errorf("got non-nil (%d), want nil", *ip)
|
||||||
}
|
}
|
||||||
|
|
@ -397,7 +372,7 @@ func TestPtrSetNil(t *testing.T) {
|
||||||
func TestMapSetNil(t *testing.T) {
|
func TestMapSetNil(t *testing.T) {
|
||||||
m := make(map[string]int)
|
m := make(map[string]int)
|
||||||
vm := NewValue(&m)
|
vm := NewValue(&m)
|
||||||
vm.(*PtrValue).Elem().(*MapValue).Set(nil)
|
vm.Elem().Set(Zero(vm.Elem().Type()))
|
||||||
if m != nil {
|
if m != nil {
|
||||||
t.Errorf("got non-nil (%p), want nil", m)
|
t.Errorf("got non-nil (%p), want nil", m)
|
||||||
}
|
}
|
||||||
|
|
@ -406,16 +381,16 @@ func TestMapSetNil(t *testing.T) {
|
||||||
|
|
||||||
func TestAll(t *testing.T) {
|
func TestAll(t *testing.T) {
|
||||||
testType(t, 1, Typeof((int8)(0)), "int8")
|
testType(t, 1, Typeof((int8)(0)), "int8")
|
||||||
testType(t, 2, Typeof((*int8)(nil)).(*PtrType).Elem(), "int8")
|
testType(t, 2, Typeof((*int8)(nil)).Elem(), "int8")
|
||||||
|
|
||||||
typ := Typeof((*struct {
|
typ := Typeof((*struct {
|
||||||
c chan *int32
|
c chan *int32
|
||||||
d float32
|
d float32
|
||||||
})(nil))
|
})(nil))
|
||||||
testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
|
testType(t, 3, typ, "*struct { c chan *int32; d float32 }")
|
||||||
etyp := typ.(*PtrType).Elem()
|
etyp := typ.Elem()
|
||||||
testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
|
testType(t, 4, etyp, "struct { c chan *int32; d float32 }")
|
||||||
styp := etyp.(*StructType)
|
styp := etyp
|
||||||
f := styp.Field(0)
|
f := styp.Field(0)
|
||||||
testType(t, 5, f.Type, "chan *int32")
|
testType(t, 5, f.Type, "chan *int32")
|
||||||
|
|
||||||
|
|
@ -432,22 +407,22 @@ func TestAll(t *testing.T) {
|
||||||
|
|
||||||
typ = Typeof([32]int32{})
|
typ = Typeof([32]int32{})
|
||||||
testType(t, 7, typ, "[32]int32")
|
testType(t, 7, typ, "[32]int32")
|
||||||
testType(t, 8, typ.(*ArrayType).Elem(), "int32")
|
testType(t, 8, typ.Elem(), "int32")
|
||||||
|
|
||||||
typ = Typeof((map[string]*int32)(nil))
|
typ = Typeof((map[string]*int32)(nil))
|
||||||
testType(t, 9, typ, "map[string] *int32")
|
testType(t, 9, typ, "map[string] *int32")
|
||||||
mtyp := typ.(*MapType)
|
mtyp := typ
|
||||||
testType(t, 10, mtyp.Key(), "string")
|
testType(t, 10, mtyp.Key(), "string")
|
||||||
testType(t, 11, mtyp.Elem(), "*int32")
|
testType(t, 11, mtyp.Elem(), "*int32")
|
||||||
|
|
||||||
typ = Typeof((chan<- string)(nil))
|
typ = Typeof((chan<- string)(nil))
|
||||||
testType(t, 12, typ, "chan<- string")
|
testType(t, 12, typ, "chan<- string")
|
||||||
testType(t, 13, typ.(*ChanType).Elem(), "string")
|
testType(t, 13, typ.Elem(), "string")
|
||||||
|
|
||||||
// make sure tag strings are not part of element type
|
// make sure tag strings are not part of element type
|
||||||
typ = Typeof(struct {
|
typ = Typeof(struct {
|
||||||
d []uint32 "TAG"
|
d []uint32 "TAG"
|
||||||
}{}).(*StructType).Field(0).Type
|
}{}).Field(0).Type
|
||||||
testType(t, 14, typ, "[]uint32")
|
testType(t, 14, typ, "[]uint32")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -457,9 +432,9 @@ func TestInterfaceGet(t *testing.T) {
|
||||||
}
|
}
|
||||||
inter.e = 123.456
|
inter.e = 123.456
|
||||||
v1 := NewValue(&inter)
|
v1 := NewValue(&inter)
|
||||||
v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
|
v2 := v1.Elem().Field(0)
|
||||||
assert(t, v2.Type().String(), "interface { }")
|
assert(t, v2.Type().String(), "interface { }")
|
||||||
i2 := v2.(*InterfaceValue).Interface()
|
i2 := v2.Interface()
|
||||||
v3 := NewValue(i2)
|
v3 := NewValue(i2)
|
||||||
assert(t, v3.Type().String(), "float64")
|
assert(t, v3.Type().String(), "float64")
|
||||||
}
|
}
|
||||||
|
|
@ -470,9 +445,9 @@ func TestInterfaceValue(t *testing.T) {
|
||||||
}
|
}
|
||||||
inter.e = 123.456
|
inter.e = 123.456
|
||||||
v1 := NewValue(&inter)
|
v1 := NewValue(&inter)
|
||||||
v2 := v1.(*PtrValue).Elem().(*StructValue).Field(0)
|
v2 := v1.Elem().Field(0)
|
||||||
assert(t, v2.Type().String(), "interface { }")
|
assert(t, v2.Type().String(), "interface { }")
|
||||||
v3 := v2.(*InterfaceValue).Elem()
|
v3 := v2.Elem()
|
||||||
assert(t, v3.Type().String(), "float64")
|
assert(t, v3.Type().String(), "float64")
|
||||||
|
|
||||||
i3 := v2.Interface()
|
i3 := v2.Interface()
|
||||||
|
|
@ -506,9 +481,9 @@ func TestAppend(t *testing.T) {
|
||||||
e0[j] = NewValue(e)
|
e0[j] = NewValue(e)
|
||||||
}
|
}
|
||||||
// Convert extra from []int to *SliceValue.
|
// Convert extra from []int to *SliceValue.
|
||||||
e1 := NewValue(test.extra).(*SliceValue)
|
e1 := NewValue(test.extra)
|
||||||
// Test Append.
|
// Test Append.
|
||||||
a0 := NewValue(test.orig).(*SliceValue)
|
a0 := NewValue(test.orig)
|
||||||
have0 := Append(a0, e0...).Interface().([]int)
|
have0 := Append(a0, e0...).Interface().([]int)
|
||||||
if !DeepEqual(have0, want) {
|
if !DeepEqual(have0, want) {
|
||||||
t.Errorf("Append #%d: have %v, want %v", i, have0, want)
|
t.Errorf("Append #%d: have %v, want %v", i, have0, want)
|
||||||
|
|
@ -521,7 +496,7 @@ func TestAppend(t *testing.T) {
|
||||||
t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
|
t.Errorf("Append #%d extraLen: have %v, want %v", i, len(test.extra), extraLen)
|
||||||
}
|
}
|
||||||
// Test AppendSlice.
|
// Test AppendSlice.
|
||||||
a1 := NewValue(test.orig).(*SliceValue)
|
a1 := NewValue(test.orig)
|
||||||
have1 := AppendSlice(a1, e1).Interface().([]int)
|
have1 := AppendSlice(a1, e1).Interface().([]int)
|
||||||
if !DeepEqual(have1, want) {
|
if !DeepEqual(have1, want) {
|
||||||
t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
|
t.Errorf("AppendSlice #%d: have %v, want %v", i, have1, want)
|
||||||
|
|
@ -545,8 +520,8 @@ func TestCopy(t *testing.T) {
|
||||||
t.Fatalf("b != c before test")
|
t.Fatalf("b != c before test")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
aa := NewValue(a).(*SliceValue)
|
aa := NewValue(a)
|
||||||
ab := NewValue(b).(*SliceValue)
|
ab := NewValue(b)
|
||||||
for tocopy := 1; tocopy <= 7; tocopy++ {
|
for tocopy := 1; tocopy <= 7; tocopy++ {
|
||||||
aa.SetLen(tocopy)
|
aa.SetLen(tocopy)
|
||||||
Copy(ab, aa)
|
Copy(ab, aa)
|
||||||
|
|
@ -660,7 +635,7 @@ func TestDeepEqual(t *testing.T) {
|
||||||
func TestTypeof(t *testing.T) {
|
func TestTypeof(t *testing.T) {
|
||||||
for _, test := range deepEqualTests {
|
for _, test := range deepEqualTests {
|
||||||
v := NewValue(test.a)
|
v := NewValue(test.a)
|
||||||
if v == nil {
|
if !v.IsValid() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
typ := Typeof(test.a)
|
typ := Typeof(test.a)
|
||||||
|
|
@ -715,8 +690,8 @@ func TestDeepEqualComplexStructInequality(t *testing.T) {
|
||||||
|
|
||||||
|
|
||||||
func check2ndField(x interface{}, offs uintptr, t *testing.T) {
|
func check2ndField(x interface{}, offs uintptr, t *testing.T) {
|
||||||
s := NewValue(x).(*StructValue)
|
s := NewValue(x)
|
||||||
f := s.Type().(*StructType).Field(1)
|
f := s.Type().Field(1)
|
||||||
if f.Offset != offs {
|
if f.Offset != offs {
|
||||||
t.Error("mismatched offsets in structure alignment:", f.Offset, offs)
|
t.Error("mismatched offsets in structure alignment:", f.Offset, offs)
|
||||||
}
|
}
|
||||||
|
|
@ -747,36 +722,22 @@ func TestAlignment(t *testing.T) {
|
||||||
check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
|
check2ndField(x1, uintptr(unsafe.Pointer(&x1.f))-uintptr(unsafe.Pointer(&x1)), t)
|
||||||
}
|
}
|
||||||
|
|
||||||
type IsNiller interface {
|
|
||||||
IsNil() bool
|
|
||||||
}
|
|
||||||
|
|
||||||
func Nil(a interface{}, t *testing.T) {
|
func Nil(a interface{}, t *testing.T) {
|
||||||
n := NewValue(a).(*StructValue).Field(0).(IsNiller)
|
n := NewValue(a).Field(0)
|
||||||
if !n.IsNil() {
|
if !n.IsNil() {
|
||||||
t.Errorf("%v should be nil", a)
|
t.Errorf("%v should be nil", a)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NotNil(a interface{}, t *testing.T) {
|
func NotNil(a interface{}, t *testing.T) {
|
||||||
n := NewValue(a).(*StructValue).Field(0).(IsNiller)
|
n := NewValue(a).Field(0)
|
||||||
if n.IsNil() {
|
if n.IsNil() {
|
||||||
t.Errorf("value of type %v should not be nil", NewValue(a).Type().String())
|
t.Errorf("value of type %v should not be nil", NewValue(a).Type().String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestIsNil(t *testing.T) {
|
func TestIsNil(t *testing.T) {
|
||||||
// These do not implement IsNil
|
// These implement IsNil.
|
||||||
doNotNil := []interface{}{int(0), float32(0), struct{ a int }{}}
|
|
||||||
for _, ts := range doNotNil {
|
|
||||||
ty := Typeof(ts)
|
|
||||||
v := MakeZero(ty)
|
|
||||||
if _, ok := v.(IsNiller); ok {
|
|
||||||
t.Errorf("%s is nilable; should not be", ts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// These do implement IsNil.
|
|
||||||
// Wrap in extra struct to hide interface type.
|
// Wrap in extra struct to hide interface type.
|
||||||
doNil := []interface{}{
|
doNil := []interface{}{
|
||||||
struct{ x *int }{},
|
struct{ x *int }{},
|
||||||
|
|
@ -787,11 +748,9 @@ func TestIsNil(t *testing.T) {
|
||||||
struct{ x []string }{},
|
struct{ x []string }{},
|
||||||
}
|
}
|
||||||
for _, ts := range doNil {
|
for _, ts := range doNil {
|
||||||
ty := Typeof(ts).(*StructType).Field(0).Type
|
ty := Typeof(ts).Field(0).Type
|
||||||
v := MakeZero(ty)
|
v := Zero(ty)
|
||||||
if _, ok := v.(IsNiller); !ok {
|
v.IsNil() // panics if not okay to call
|
||||||
t.Errorf("%s %T is not nilable; should be", ts, v)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the implementations
|
// Check the implementations
|
||||||
|
|
@ -844,7 +803,7 @@ func TestInterfaceExtraction(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
s.w = os.Stdout
|
s.w = os.Stdout
|
||||||
v := Indirect(NewValue(&s)).(*StructValue).Field(0).Interface()
|
v := Indirect(NewValue(&s)).Field(0).Interface()
|
||||||
if v != s.w.(interface{}) {
|
if v != s.w.(interface{}) {
|
||||||
t.Error("Interface() on interface: ", v, s.w)
|
t.Error("Interface() on interface: ", v, s.w)
|
||||||
}
|
}
|
||||||
|
|
@ -864,7 +823,7 @@ func TestInterfaceEditing(t *testing.T) {
|
||||||
|
|
||||||
// and setting that copy to "bye" should
|
// and setting that copy to "bye" should
|
||||||
// not change the value stored in i.
|
// not change the value stored in i.
|
||||||
v.(*StringValue).Set("bye")
|
v.SetString("bye")
|
||||||
if i.(string) != "hello" {
|
if i.(string) != "hello" {
|
||||||
t.Errorf(`Set("bye") changed i to %s`, i.(string))
|
t.Errorf(`Set("bye") changed i to %s`, i.(string))
|
||||||
}
|
}
|
||||||
|
|
@ -872,7 +831,7 @@ func TestInterfaceEditing(t *testing.T) {
|
||||||
// the same should be true of smaller items.
|
// the same should be true of smaller items.
|
||||||
i = 123
|
i = 123
|
||||||
v = NewValue(i)
|
v = NewValue(i)
|
||||||
v.(*IntValue).Set(234)
|
v.SetInt(234)
|
||||||
if i.(int) != 123 {
|
if i.(int) != 123 {
|
||||||
t.Errorf("Set(234) changed i to %d", i.(int))
|
t.Errorf("Set(234) changed i to %d", i.(int))
|
||||||
}
|
}
|
||||||
|
|
@ -880,20 +839,20 @@ func TestInterfaceEditing(t *testing.T) {
|
||||||
|
|
||||||
func TestNilPtrValueSub(t *testing.T) {
|
func TestNilPtrValueSub(t *testing.T) {
|
||||||
var pi *int
|
var pi *int
|
||||||
if pv := NewValue(pi).(*PtrValue); pv.Elem() != nil {
|
if pv := NewValue(pi); pv.Elem().IsValid() {
|
||||||
t.Error("NewValue((*int)(nil)).(*PtrValue).Elem() != nil")
|
t.Error("NewValue((*int)(nil)).Elem().IsValid()")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestMap(t *testing.T) {
|
func TestMap(t *testing.T) {
|
||||||
m := map[string]int{"a": 1, "b": 2}
|
m := map[string]int{"a": 1, "b": 2}
|
||||||
mv := NewValue(m).(*MapValue)
|
mv := NewValue(m)
|
||||||
if n := mv.Len(); n != len(m) {
|
if n := mv.Len(); n != len(m) {
|
||||||
t.Errorf("Len = %d, want %d", n, len(m))
|
t.Errorf("Len = %d, want %d", n, len(m))
|
||||||
}
|
}
|
||||||
keys := mv.Keys()
|
keys := mv.MapKeys()
|
||||||
i := 0
|
i := 0
|
||||||
newmap := MakeMap(mv.Type().(*MapType))
|
newmap := MakeMap(mv.Type())
|
||||||
for k, v := range m {
|
for k, v := range m {
|
||||||
// Check that returned Keys match keys in range.
|
// Check that returned Keys match keys in range.
|
||||||
// These aren't required to be in the same order,
|
// These aren't required to be in the same order,
|
||||||
|
|
@ -901,22 +860,22 @@ func TestMap(t *testing.T) {
|
||||||
// the test easier.
|
// the test easier.
|
||||||
if i >= len(keys) {
|
if i >= len(keys) {
|
||||||
t.Errorf("Missing key #%d %q", i, k)
|
t.Errorf("Missing key #%d %q", i, k)
|
||||||
} else if kv := keys[i].(*StringValue); kv.Get() != k {
|
} else if kv := keys[i]; kv.String() != k {
|
||||||
t.Errorf("Keys[%d] = %q, want %q", i, kv.Get(), k)
|
t.Errorf("Keys[%q] = %d, want %d", i, kv.Int(), k)
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
|
|
||||||
// Check that value lookup is correct.
|
// Check that value lookup is correct.
|
||||||
vv := mv.Elem(NewValue(k))
|
vv := mv.MapIndex(NewValue(k))
|
||||||
if vi := vv.(*IntValue).Get(); vi != int64(v) {
|
if vi := vv.Int(); vi != int64(v) {
|
||||||
t.Errorf("Key %q: have value %d, want %d", k, vi, v)
|
t.Errorf("Key %q: have value %d, want %d", k, vi, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy into new map.
|
// Copy into new map.
|
||||||
newmap.SetElem(NewValue(k), NewValue(v))
|
newmap.SetMapIndex(NewValue(k), NewValue(v))
|
||||||
}
|
}
|
||||||
vv := mv.Elem(NewValue("not-present"))
|
vv := mv.MapIndex(NewValue("not-present"))
|
||||||
if vv != nil {
|
if vv.IsValid() {
|
||||||
t.Errorf("Invalid key: got non-nil value %s", valueToString(vv))
|
t.Errorf("Invalid key: got non-nil value %s", valueToString(vv))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -932,14 +891,14 @@ func TestMap(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newmap.SetElem(NewValue("a"), nil)
|
newmap.SetMapIndex(NewValue("a"), Value{})
|
||||||
v, ok := newm["a"]
|
v, ok := newm["a"]
|
||||||
if ok {
|
if ok {
|
||||||
t.Errorf("newm[\"a\"] = %d after delete", v)
|
t.Errorf("newm[\"a\"] = %d after delete", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
mv = NewValue(&m).(*PtrValue).Elem().(*MapValue)
|
mv = NewValue(&m).Elem()
|
||||||
mv.Set(nil)
|
mv.Set(Zero(mv.Type()))
|
||||||
if m != nil {
|
if m != nil {
|
||||||
t.Errorf("mv.Set(nil) failed")
|
t.Errorf("mv.Set(nil) failed")
|
||||||
}
|
}
|
||||||
|
|
@ -948,15 +907,15 @@ func TestMap(t *testing.T) {
|
||||||
func TestChan(t *testing.T) {
|
func TestChan(t *testing.T) {
|
||||||
for loop := 0; loop < 2; loop++ {
|
for loop := 0; loop < 2; loop++ {
|
||||||
var c chan int
|
var c chan int
|
||||||
var cv *ChanValue
|
var cv Value
|
||||||
|
|
||||||
// check both ways to allocate channels
|
// check both ways to allocate channels
|
||||||
switch loop {
|
switch loop {
|
||||||
case 1:
|
case 1:
|
||||||
c = make(chan int, 1)
|
c = make(chan int, 1)
|
||||||
cv = NewValue(c).(*ChanValue)
|
cv = NewValue(c)
|
||||||
case 0:
|
case 0:
|
||||||
cv = MakeChan(Typeof(c).(*ChanType), 1)
|
cv = MakeChan(Typeof(c), 1)
|
||||||
c = cv.Interface().(chan int)
|
c = cv.Interface().(chan int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -968,22 +927,22 @@ func TestChan(t *testing.T) {
|
||||||
|
|
||||||
// Recv
|
// Recv
|
||||||
c <- 3
|
c <- 3
|
||||||
if i, ok := cv.Recv(); i.(*IntValue).Get() != 3 || !ok {
|
if i, ok := cv.Recv(); i.Int() != 3 || !ok {
|
||||||
t.Errorf("native send 3, reflect Recv %d, %t", i.(*IntValue).Get(), ok)
|
t.Errorf("native send 3, reflect Recv %d, %t", i.Int(), ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryRecv fail
|
// TryRecv fail
|
||||||
val, ok := cv.TryRecv()
|
val, ok := cv.TryRecv()
|
||||||
if val != nil || ok {
|
if val.IsValid() || ok {
|
||||||
t.Errorf("TryRecv on empty chan: %s, %t", valueToString(val), ok)
|
t.Errorf("TryRecv on empty chan: %s, %t", valueToString(val), ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TryRecv success
|
// TryRecv success
|
||||||
c <- 4
|
c <- 4
|
||||||
val, ok = cv.TryRecv()
|
val, ok = cv.TryRecv()
|
||||||
if val == nil {
|
if !val.IsValid() {
|
||||||
t.Errorf("TryRecv on ready chan got nil")
|
t.Errorf("TryRecv on ready chan got nil")
|
||||||
} else if i := val.(*IntValue).Get(); i != 4 || !ok {
|
} else if i := val.Int(); i != 4 || !ok {
|
||||||
t.Errorf("native send 4, TryRecv %d, %t", i, ok)
|
t.Errorf("native send 4, TryRecv %d, %t", i, ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1008,27 +967,27 @@ func TestChan(t *testing.T) {
|
||||||
// Close
|
// Close
|
||||||
c <- 123
|
c <- 123
|
||||||
cv.Close()
|
cv.Close()
|
||||||
if i, ok := cv.Recv(); i.(*IntValue).Get() != 123 || !ok {
|
if i, ok := cv.Recv(); i.Int() != 123 || !ok {
|
||||||
t.Errorf("send 123 then close; Recv %d, %t", i.(*IntValue).Get(), ok)
|
t.Errorf("send 123 then close; Recv %d, %t", i.Int(), ok)
|
||||||
}
|
}
|
||||||
if i, ok := cv.Recv(); i.(*IntValue).Get() != 0 || ok {
|
if i, ok := cv.Recv(); i.Int() != 0 || ok {
|
||||||
t.Errorf("after close Recv %d, %t", i.(*IntValue).Get(), ok)
|
t.Errorf("after close Recv %d, %t", i.Int(), ok)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// check creation of unbuffered channel
|
// check creation of unbuffered channel
|
||||||
var c chan int
|
var c chan int
|
||||||
cv := MakeChan(Typeof(c).(*ChanType), 0)
|
cv := MakeChan(Typeof(c), 0)
|
||||||
c = cv.Interface().(chan int)
|
c = cv.Interface().(chan int)
|
||||||
if cv.TrySend(NewValue(7)) {
|
if cv.TrySend(NewValue(7)) {
|
||||||
t.Errorf("TrySend on sync chan succeeded")
|
t.Errorf("TrySend on sync chan succeeded")
|
||||||
}
|
}
|
||||||
if v, ok := cv.TryRecv(); v != nil || ok {
|
if v, ok := cv.TryRecv(); v.IsValid() || ok {
|
||||||
t.Errorf("TryRecv on sync chan succeeded")
|
t.Errorf("TryRecv on sync chan succeeded")
|
||||||
}
|
}
|
||||||
|
|
||||||
// len/cap
|
// len/cap
|
||||||
cv = MakeChan(Typeof(c).(*ChanType), 10)
|
cv = MakeChan(Typeof(c), 10)
|
||||||
c = cv.Interface().(chan int)
|
c = cv.Interface().(chan int)
|
||||||
for i := 0; i < 3; i++ {
|
for i := 0; i < 3; i++ {
|
||||||
c <- i
|
c <- i
|
||||||
|
|
@ -1046,14 +1005,14 @@ func dummy(b byte, c int, d byte) (i byte, j int, k byte) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestFunc(t *testing.T) {
|
func TestFunc(t *testing.T) {
|
||||||
ret := NewValue(dummy).(*FuncValue).Call([]Value{NewValue(byte(10)), NewValue(20), NewValue(byte(30))})
|
ret := NewValue(dummy).Call([]Value{NewValue(byte(10)), NewValue(20), NewValue(byte(30))})
|
||||||
if len(ret) != 3 {
|
if len(ret) != 3 {
|
||||||
t.Fatalf("Call returned %d values, want 3", len(ret))
|
t.Fatalf("Call returned %d values, want 3", len(ret))
|
||||||
}
|
}
|
||||||
|
|
||||||
i := ret[0].(*UintValue).Get()
|
i := byte(ret[0].Uint())
|
||||||
j := ret[1].(*IntValue).Get()
|
j := int(ret[1].Int())
|
||||||
k := ret[2].(*UintValue).Get()
|
k := byte(ret[2].Uint())
|
||||||
if i != 10 || j != 20 || k != 30 {
|
if i != 10 || j != 20 || k != 30 {
|
||||||
t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
|
t.Errorf("Call returned %d, %d, %d; want 10, 20, 30", i, j, k)
|
||||||
}
|
}
|
||||||
|
|
@ -1068,30 +1027,30 @@ func (p Point) Dist(scale int) int { return p.x*p.x*scale + p.y*p.y*scale }
|
||||||
func TestMethod(t *testing.T) {
|
func TestMethod(t *testing.T) {
|
||||||
// Non-curried method of type.
|
// Non-curried method of type.
|
||||||
p := Point{3, 4}
|
p := Point{3, 4}
|
||||||
i := Typeof(p).Method(0).Func.Call([]Value{NewValue(p), NewValue(10)})[0].(*IntValue).Get()
|
i := Typeof(p).Method(0).Func.Call([]Value{NewValue(p), NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Type Method returned %d; want 250", i)
|
t.Errorf("Type Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
i = Typeof(&p).Method(0).Func.Call([]Value{NewValue(&p), NewValue(10)})[0].(*IntValue).Get()
|
i = Typeof(&p).Method(0).Func.Call([]Value{NewValue(&p), NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Pointer Type Method returned %d; want 250", i)
|
t.Errorf("Pointer Type Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Curried method of value.
|
// Curried method of value.
|
||||||
i = NewValue(p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
|
i = NewValue(p).Method(0).Call([]Value{NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Value Method returned %d; want 250", i)
|
t.Errorf("Value Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Curried method of pointer.
|
// Curried method of pointer.
|
||||||
i = NewValue(&p).Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
|
i = NewValue(&p).Method(0).Call([]Value{NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Value Method returned %d; want 250", i)
|
t.Errorf("Value Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Curried method of pointer to value.
|
// Curried method of pointer to value.
|
||||||
i = NewValue(p).Addr().Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
|
i = NewValue(p).Addr().Method(0).Call([]Value{NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Value Method returned %d; want 250", i)
|
t.Errorf("Value Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
@ -1105,8 +1064,8 @@ func TestMethod(t *testing.T) {
|
||||||
Dist(int) int
|
Dist(int) int
|
||||||
}
|
}
|
||||||
}{p}
|
}{p}
|
||||||
pv := NewValue(s).(*StructValue).Field(0)
|
pv := NewValue(s).Field(0)
|
||||||
i = pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
|
i = pv.Method(0).Call([]Value{NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Interface Method returned %d; want 250", i)
|
t.Errorf("Interface Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
@ -1121,19 +1080,19 @@ func TestInterfaceSet(t *testing.T) {
|
||||||
Dist(int) int
|
Dist(int) int
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sv := NewValue(&s).(*PtrValue).Elem().(*StructValue)
|
sv := NewValue(&s).Elem()
|
||||||
sv.Field(0).(*InterfaceValue).Set(NewValue(p))
|
sv.Field(0).Set(NewValue(p))
|
||||||
if q := s.I.(*Point); q != p {
|
if q := s.I.(*Point); q != p {
|
||||||
t.Errorf("i: have %p want %p", q, p)
|
t.Errorf("i: have %p want %p", q, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
pv := sv.Field(1).(*InterfaceValue)
|
pv := sv.Field(1)
|
||||||
pv.Set(NewValue(p))
|
pv.Set(NewValue(p))
|
||||||
if q := s.P.(*Point); q != p {
|
if q := s.P.(*Point); q != p {
|
||||||
t.Errorf("i: have %p want %p", q, p)
|
t.Errorf("i: have %p want %p", q, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
i := pv.Method(0).Call([]Value{NewValue(10)})[0].(*IntValue).Get()
|
i := pv.Method(0).Call([]Value{NewValue(10)})[0].Int()
|
||||||
if i != 250 {
|
if i != 250 {
|
||||||
t.Errorf("Interface Method returned %d; want 250", i)
|
t.Errorf("Interface Method returned %d; want 250", i)
|
||||||
}
|
}
|
||||||
|
|
@ -1148,7 +1107,7 @@ func TestAnonymousFields(t *testing.T) {
|
||||||
var field StructField
|
var field StructField
|
||||||
var ok bool
|
var ok bool
|
||||||
var t1 T1
|
var t1 T1
|
||||||
type1 := Typeof(t1).(*StructType)
|
type1 := Typeof(t1)
|
||||||
if field, ok = type1.FieldByName("int"); !ok {
|
if field, ok = type1.FieldByName("int"); !ok {
|
||||||
t.Error("no field 'int'")
|
t.Error("no field 'int'")
|
||||||
}
|
}
|
||||||
|
|
@ -1232,7 +1191,7 @@ var fieldTests = []FTest{
|
||||||
|
|
||||||
func TestFieldByIndex(t *testing.T) {
|
func TestFieldByIndex(t *testing.T) {
|
||||||
for _, test := range fieldTests {
|
for _, test := range fieldTests {
|
||||||
s := Typeof(test.s).(*StructType)
|
s := Typeof(test.s)
|
||||||
f := s.FieldByIndex(test.index)
|
f := s.FieldByIndex(test.index)
|
||||||
if f.Name != "" {
|
if f.Name != "" {
|
||||||
if test.index != nil {
|
if test.index != nil {
|
||||||
|
|
@ -1247,8 +1206,8 @@ func TestFieldByIndex(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.value != 0 {
|
if test.value != 0 {
|
||||||
v := NewValue(test.s).(*StructValue).FieldByIndex(test.index)
|
v := NewValue(test.s).FieldByIndex(test.index)
|
||||||
if v != nil {
|
if v.IsValid() {
|
||||||
if x, ok := v.Interface().(int); ok {
|
if x, ok := v.Interface().(int); ok {
|
||||||
if x != test.value {
|
if x != test.value {
|
||||||
t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value)
|
t.Errorf("%s%v is %d; want %d", s.Name(), test.index, x, test.value)
|
||||||
|
|
@ -1265,7 +1224,7 @@ func TestFieldByIndex(t *testing.T) {
|
||||||
|
|
||||||
func TestFieldByName(t *testing.T) {
|
func TestFieldByName(t *testing.T) {
|
||||||
for _, test := range fieldTests {
|
for _, test := range fieldTests {
|
||||||
s := Typeof(test.s).(*StructType)
|
s := Typeof(test.s)
|
||||||
f, found := s.FieldByName(test.name)
|
f, found := s.FieldByName(test.name)
|
||||||
if found {
|
if found {
|
||||||
if test.index != nil {
|
if test.index != nil {
|
||||||
|
|
@ -1287,8 +1246,8 @@ func TestFieldByName(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.value != 0 {
|
if test.value != 0 {
|
||||||
v := NewValue(test.s).(*StructValue).FieldByName(test.name)
|
v := NewValue(test.s).FieldByName(test.name)
|
||||||
if v != nil {
|
if v.IsValid() {
|
||||||
if x, ok := v.Interface().(int); ok {
|
if x, ok := v.Interface().(int); ok {
|
||||||
if x != test.value {
|
if x != test.value {
|
||||||
t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value)
|
t.Errorf("%s.%s is %d; want %d", s.Name(), test.name, x, test.value)
|
||||||
|
|
@ -1312,10 +1271,10 @@ func TestImportPath(t *testing.T) {
|
||||||
func TestDotDotDot(t *testing.T) {
|
func TestDotDotDot(t *testing.T) {
|
||||||
// Test example from FuncType.DotDotDot documentation.
|
// Test example from FuncType.DotDotDot documentation.
|
||||||
var f func(x int, y ...float64)
|
var f func(x int, y ...float64)
|
||||||
typ := Typeof(f).(*FuncType)
|
typ := Typeof(f)
|
||||||
if typ.NumIn() == 2 && typ.In(0) == Typeof(int(0)) {
|
if typ.NumIn() == 2 && typ.In(0) == Typeof(int(0)) {
|
||||||
sl, ok := typ.In(1).(*SliceType)
|
sl := typ.In(1)
|
||||||
if ok {
|
if sl.Kind() == Slice {
|
||||||
if sl.Elem() == Typeof(0.0) {
|
if sl.Elem() == Typeof(0.0) {
|
||||||
// ok
|
// ok
|
||||||
return
|
return
|
||||||
|
|
@ -1346,11 +1305,11 @@ func (*outer) m() {}
|
||||||
|
|
||||||
func TestNestedMethods(t *testing.T) {
|
func TestNestedMethods(t *testing.T) {
|
||||||
typ := Typeof((*outer)(nil))
|
typ := Typeof((*outer)(nil))
|
||||||
if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outer).m).(*FuncValue).Get() {
|
if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != NewValue((*outer).m).Pointer() {
|
||||||
t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
|
t.Errorf("Wrong method table for outer: (m=%p)", (*outer).m)
|
||||||
for i := 0; i < typ.NumMethod(); i++ {
|
for i := 0; i < typ.NumMethod(); i++ {
|
||||||
m := typ.Method(i)
|
m := typ.Method(i)
|
||||||
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
|
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1370,21 +1329,21 @@ func (i *innerInt) m() int {
|
||||||
|
|
||||||
func TestEmbeddedMethods(t *testing.T) {
|
func TestEmbeddedMethods(t *testing.T) {
|
||||||
typ := Typeof((*outerInt)(nil))
|
typ := Typeof((*outerInt)(nil))
|
||||||
if typ.NumMethod() != 1 || typ.Method(0).Func.Get() != NewValue((*outerInt).m).(*FuncValue).Get() {
|
if typ.NumMethod() != 1 || typ.Method(0).Func.Pointer() != NewValue((*outerInt).m).Pointer() {
|
||||||
t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m)
|
t.Errorf("Wrong method table for outerInt: (m=%p)", (*outerInt).m)
|
||||||
for i := 0; i < typ.NumMethod(); i++ {
|
for i := 0; i < typ.NumMethod(); i++ {
|
||||||
m := typ.Method(i)
|
m := typ.Method(i)
|
||||||
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Get())
|
t.Errorf("\t%d: %s %#x\n", i, m.Name, m.Func.Pointer())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
i := &innerInt{3}
|
i := &innerInt{3}
|
||||||
if v := NewValue(i).Method(0).Call(nil)[0].(*IntValue).Get(); v != 3 {
|
if v := NewValue(i).Method(0).Call(nil)[0].Int(); v != 3 {
|
||||||
t.Errorf("i.m() = %d, want 3", v)
|
t.Errorf("i.m() = %d, want 3", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
o := &outerInt{1, innerInt{2}}
|
o := &outerInt{1, innerInt{2}}
|
||||||
if v := NewValue(o).Method(0).Call(nil)[0].(*IntValue).Get(); v != 2 {
|
if v := NewValue(o).Method(0).Call(nil)[0].Int(); v != 2 {
|
||||||
t.Errorf("i.m() = %d, want 2", v)
|
t.Errorf("i.m() = %d, want 2", v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1402,7 +1361,7 @@ func TestPtrTo(t *testing.T) {
|
||||||
typ = PtrTo(typ)
|
typ = PtrTo(typ)
|
||||||
}
|
}
|
||||||
for i = 0; i < 100; i++ {
|
for i = 0; i < 100; i++ {
|
||||||
typ = typ.(*PtrType).Elem()
|
typ = typ.Elem()
|
||||||
}
|
}
|
||||||
if typ != Typeof(i) {
|
if typ != Typeof(i) {
|
||||||
t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, Typeof(i))
|
t.Errorf("after 100 PtrTo and Elem, have %s, want %s", typ, Typeof(i))
|
||||||
|
|
@ -1415,11 +1374,11 @@ func TestAddr(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
v := NewValue(&p)
|
v := NewValue(&p)
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.(*StructValue).Field(0)
|
v = v.Field(0)
|
||||||
v.(*IntValue).Set(2)
|
v.SetInt(2)
|
||||||
if p.X != 2 {
|
if p.X != 2 {
|
||||||
t.Errorf("Addr.Elem.Set failed to set value")
|
t.Errorf("Addr.Elem.Set failed to set value")
|
||||||
}
|
}
|
||||||
|
|
@ -1428,12 +1387,12 @@ func TestAddr(t *testing.T) {
|
||||||
// Exercises generation of PtrTypes not present in the binary.
|
// Exercises generation of PtrTypes not present in the binary.
|
||||||
v = NewValue(&p)
|
v = NewValue(&p)
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.(*StructValue).Field(0)
|
v = v.Field(0)
|
||||||
v.(*IntValue).Set(3)
|
v.SetInt(3)
|
||||||
if p.X != 3 {
|
if p.X != 3 {
|
||||||
t.Errorf("Addr.Elem.Set failed to set value")
|
t.Errorf("Addr.Elem.Set failed to set value")
|
||||||
}
|
}
|
||||||
|
|
@ -1443,9 +1402,9 @@ func TestAddr(t *testing.T) {
|
||||||
v = NewValue(p)
|
v = NewValue(p)
|
||||||
v0 := v
|
v0 := v
|
||||||
v = v.Addr()
|
v = v.Addr()
|
||||||
v = v.(*PtrValue).Elem()
|
v = v.Elem()
|
||||||
v = v.(*StructValue).Field(0)
|
v = v.Field(0)
|
||||||
v.(*IntValue).Set(4)
|
v.SetInt(4)
|
||||||
if p.X != 3 { // should be unchanged from last time
|
if p.X != 3 { // should be unchanged from last time
|
||||||
t.Errorf("somehow value Set changed original p")
|
t.Errorf("somehow value Set changed original p")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ type visit struct {
|
||||||
// comparisons that have already been seen, which allows short circuiting on
|
// comparisons that have already been seen, which allows short circuiting on
|
||||||
// recursive types.
|
// recursive types.
|
||||||
func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
|
func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
|
||||||
if v1 == nil || v2 == nil {
|
if !v1.IsValid() || !v2.IsValid() {
|
||||||
return v1 == v2
|
return v1.IsValid() == v2.IsValid()
|
||||||
}
|
}
|
||||||
if v1.Type() != v2.Type() {
|
if v1.Type() != v2.Type() {
|
||||||
return false
|
return false
|
||||||
|
|
@ -56,57 +56,47 @@ func deepValueEqual(v1, v2 Value, visited map[uintptr]*visit, depth int) bool {
|
||||||
// Remember for later.
|
// Remember for later.
|
||||||
visited[h] = &visit{addr1, addr2, typ, seen}
|
visited[h] = &visit{addr1, addr2, typ, seen}
|
||||||
|
|
||||||
switch v := v1.(type) {
|
switch v1.Kind() {
|
||||||
case *ArrayValue:
|
case Array:
|
||||||
arr1 := v
|
if v1.Len() != v2.Len() {
|
||||||
arr2 := v2.(*ArrayValue)
|
|
||||||
if arr1.Len() != arr2.Len() {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := 0; i < arr1.Len(); i++ {
|
for i := 0; i < v1.Len(); i++ {
|
||||||
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
|
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case *SliceValue:
|
case Slice:
|
||||||
arr1 := v
|
if v1.Len() != v2.Len() {
|
||||||
arr2 := v2.(*SliceValue)
|
|
||||||
if arr1.Len() != arr2.Len() {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := 0; i < arr1.Len(); i++ {
|
for i := 0; i < v1.Len(); i++ {
|
||||||
if !deepValueEqual(arr1.Elem(i), arr2.Elem(i), visited, depth+1) {
|
if !deepValueEqual(v1.Index(i), v2.Index(i), visited, depth+1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case *InterfaceValue:
|
case Interface:
|
||||||
i1 := v.Interface()
|
if v1.IsNil() || v2.IsNil() {
|
||||||
i2 := v2.Interface()
|
return v1.IsNil() == v2.IsNil()
|
||||||
if i1 == nil || i2 == nil {
|
|
||||||
return i1 == i2
|
|
||||||
}
|
}
|
||||||
return deepValueEqual(NewValue(i1), NewValue(i2), visited, depth+1)
|
return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
|
||||||
case *PtrValue:
|
case Ptr:
|
||||||
return deepValueEqual(v.Elem(), v2.(*PtrValue).Elem(), visited, depth+1)
|
return deepValueEqual(v1.Elem(), v2.Elem(), visited, depth+1)
|
||||||
case *StructValue:
|
case Struct:
|
||||||
struct1 := v
|
for i, n := 0, v1.NumField(); i < n; i++ {
|
||||||
struct2 := v2.(*StructValue)
|
if !deepValueEqual(v1.Field(i), v2.Field(i), visited, depth+1) {
|
||||||
for i, n := 0, v.NumField(); i < n; i++ {
|
|
||||||
if !deepValueEqual(struct1.Field(i), struct2.Field(i), visited, depth+1) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case *MapValue:
|
case Map:
|
||||||
map1 := v
|
if v1.Len() != v2.Len() {
|
||||||
map2 := v2.(*MapValue)
|
|
||||||
if map1.Len() != map2.Len() {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for _, k := range map1.Keys() {
|
for _, k := range v1.MapKeys() {
|
||||||
if !deepValueEqual(map1.Elem(k), map2.Elem(k), visited, depth+1) {
|
if !deepValueEqual(v1.MapIndex(k), v2.MapIndex(k), visited, depth+1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,29 +17,29 @@ import (
|
||||||
// For debugging only.
|
// For debugging only.
|
||||||
func valueToString(val Value) string {
|
func valueToString(val Value) string {
|
||||||
var str string
|
var str string
|
||||||
if val == nil {
|
if !val.IsValid() {
|
||||||
return "<nil>"
|
return "<zero Value>"
|
||||||
}
|
}
|
||||||
typ := val.Type()
|
typ := val.Type()
|
||||||
switch val := val.(type) {
|
switch val.Kind() {
|
||||||
case *IntValue:
|
case Int, Int8, Int16, Int32, Int64:
|
||||||
return strconv.Itoa64(val.Get())
|
return strconv.Itoa64(val.Int())
|
||||||
case *UintValue:
|
case Uint, Uint8, Uint16, Uint32, Uint64, Uintptr:
|
||||||
return strconv.Uitoa64(val.Get())
|
return strconv.Uitoa64(val.Uint())
|
||||||
case *FloatValue:
|
case Float32, Float64:
|
||||||
return strconv.Ftoa64(float64(val.Get()), 'g', -1)
|
return strconv.Ftoa64(val.Float(), 'g', -1)
|
||||||
case *ComplexValue:
|
case Complex64, Complex128:
|
||||||
c := val.Get()
|
c := val.Complex()
|
||||||
return strconv.Ftoa64(float64(real(c)), 'g', -1) + "+" + strconv.Ftoa64(float64(imag(c)), 'g', -1) + "i"
|
return strconv.Ftoa64(real(c), 'g', -1) + "+" + strconv.Ftoa64(imag(c), 'g', -1) + "i"
|
||||||
case *StringValue:
|
case String:
|
||||||
return val.Get()
|
return val.String()
|
||||||
case *BoolValue:
|
case Bool:
|
||||||
if val.Get() {
|
if val.Bool() {
|
||||||
return "true"
|
return "true"
|
||||||
} else {
|
} else {
|
||||||
return "false"
|
return "false"
|
||||||
}
|
}
|
||||||
case *PtrValue:
|
case Ptr:
|
||||||
v := val
|
v := val
|
||||||
str = typ.String() + "("
|
str = typ.String() + "("
|
||||||
if v.IsNil() {
|
if v.IsNil() {
|
||||||
|
|
@ -49,7 +49,7 @@ func valueToString(val Value) string {
|
||||||
}
|
}
|
||||||
str += ")"
|
str += ")"
|
||||||
return str
|
return str
|
||||||
case ArrayOrSliceValue:
|
case Array, Slice:
|
||||||
v := val
|
v := val
|
||||||
str += typ.String()
|
str += typ.String()
|
||||||
str += "{"
|
str += "{"
|
||||||
|
|
@ -57,22 +57,22 @@ func valueToString(val Value) string {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
str += ", "
|
str += ", "
|
||||||
}
|
}
|
||||||
str += valueToString(v.Elem(i))
|
str += valueToString(v.Index(i))
|
||||||
}
|
}
|
||||||
str += "}"
|
str += "}"
|
||||||
return str
|
return str
|
||||||
case *MapValue:
|
case Map:
|
||||||
t := typ.(*MapType)
|
t := typ
|
||||||
str = t.String()
|
str = t.String()
|
||||||
str += "{"
|
str += "{"
|
||||||
str += "<can't iterate on maps>"
|
str += "<can't iterate on maps>"
|
||||||
str += "}"
|
str += "}"
|
||||||
return str
|
return str
|
||||||
case *ChanValue:
|
case Chan:
|
||||||
str = typ.String()
|
str = typ.String()
|
||||||
return str
|
return str
|
||||||
case *StructValue:
|
case Struct:
|
||||||
t := typ.(*StructType)
|
t := typ
|
||||||
v := val
|
v := val
|
||||||
str += t.String()
|
str += t.String()
|
||||||
str += "{"
|
str += "{"
|
||||||
|
|
@ -84,11 +84,11 @@ func valueToString(val Value) string {
|
||||||
}
|
}
|
||||||
str += "}"
|
str += "}"
|
||||||
return str
|
return str
|
||||||
case *InterfaceValue:
|
case Interface:
|
||||||
return typ.String() + "(" + valueToString(val.Elem()) + ")"
|
return typ.String() + "(" + valueToString(val.Elem()) + ")"
|
||||||
case *FuncValue:
|
case Func:
|
||||||
v := val
|
v := val
|
||||||
return typ.String() + "(" + strconv.Itoa64(int64(v.Get())) + ")"
|
return typ.String() + "(" + strconv.Uitoa64(uint64(v.Pointer())) + ")"
|
||||||
default:
|
default:
|
||||||
panic("valueToString: can't print type " + typ.String())
|
panic("valueToString: can't print type " + typ.String())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,11 @@
|
||||||
// The reflect package implements run-time reflection, allowing a program to
|
// The reflect package implements run-time reflection, allowing a program to
|
||||||
// manipulate objects with arbitrary types. The typical use is to take a
|
// manipulate objects with arbitrary types. The typical use is to take a
|
||||||
// value with static type interface{} and extract its dynamic type
|
// value with static type interface{} and extract its dynamic type
|
||||||
// information by calling Typeof, which returns an object with interface
|
// information by calling Typeof, which returns a Type.
|
||||||
// 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
|
// A call to NewValue returns a Value representing the run-time data.
|
||||||
// contains a *StructValue, *IntValue, etc. MakeZero takes a Type and
|
// Zero takes a Type and returns a Value representing a zero value
|
||||||
// returns a Value representing a zero value for that type.
|
// for that type.
|
||||||
package reflect
|
package reflect
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -22,6 +19,186 @@ import (
|
||||||
"unsafe"
|
"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
|
||||||
|
|
||||||
|
// NumMethods 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 "container/vector".
|
||||||
|
// 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., vector instead of "container/vector") 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
|
||||||
|
|
||||||
|
// 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 ... float), then
|
||||||
|
//
|
||||||
|
// t.NumIn() == 2
|
||||||
|
// t.In(0) is the reflect.Type for "int"
|
||||||
|
// t.In(1) is the reflect.Type for "[]float"
|
||||||
|
// 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
|
||||||
|
|
||||||
|
uncommon() *uncommonType
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Kind represents the specific kind of type that a Type represents.
|
||||||
|
// The zero Kind is not a valid kind.
|
||||||
|
type Kind uint8
|
||||||
|
|
||||||
|
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.
|
* Copy of data structures from ../runtime/type.go.
|
||||||
* For comments, see the ones in that file.
|
* For comments, see the ones in that file.
|
||||||
|
|
@ -67,48 +244,6 @@ type uncommonType struct {
|
||||||
methods []method
|
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.
|
// ChanDir represents a channel type's direction.
|
||||||
type ChanDir int
|
type ChanDir int
|
||||||
|
|
||||||
|
|
@ -118,57 +253,61 @@ const (
|
||||||
BothDir = RecvDir | SendDir
|
BothDir = RecvDir | SendDir
|
||||||
)
|
)
|
||||||
|
|
||||||
// ChanType represents a channel type.
|
|
||||||
type ChanType struct {
|
// arrayType represents a fixed array type.
|
||||||
|
type arrayType struct {
|
||||||
|
commonType "array"
|
||||||
|
elem *runtime.Type
|
||||||
|
len uintptr
|
||||||
|
}
|
||||||
|
|
||||||
|
// chanType represents a channel type.
|
||||||
|
type chanType struct {
|
||||||
commonType "chan"
|
commonType "chan"
|
||||||
elem *runtime.Type
|
elem *runtime.Type
|
||||||
dir uintptr
|
dir uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// FuncType represents a function type.
|
// funcType represents a function type.
|
||||||
type FuncType struct {
|
type funcType struct {
|
||||||
commonType "func"
|
commonType "func"
|
||||||
dotdotdot bool
|
dotdotdot bool
|
||||||
in []*runtime.Type
|
in []*runtime.Type
|
||||||
out []*runtime.Type
|
out []*runtime.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// Method on interface type
|
// imethod represents a method on an interface type
|
||||||
type imethod struct {
|
type imethod struct {
|
||||||
name *string
|
name *string
|
||||||
pkgPath *string
|
pkgPath *string
|
||||||
typ *runtime.Type
|
typ *runtime.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// InterfaceType represents an interface type.
|
// interfaceType represents an interface type.
|
||||||
type InterfaceType struct {
|
type interfaceType struct {
|
||||||
commonType "interface"
|
commonType "interface"
|
||||||
methods []imethod
|
methods []imethod
|
||||||
}
|
}
|
||||||
|
|
||||||
// MapType represents a map type.
|
// mapType represents a map type.
|
||||||
type MapType struct {
|
type mapType struct {
|
||||||
commonType "map"
|
commonType "map"
|
||||||
key *runtime.Type
|
key *runtime.Type
|
||||||
elem *runtime.Type
|
elem *runtime.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// PtrType represents a pointer type.
|
// ptrType represents a pointer type.
|
||||||
type PtrType struct {
|
type ptrType struct {
|
||||||
commonType "ptr"
|
commonType "ptr"
|
||||||
elem *runtime.Type
|
elem *runtime.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// SliceType represents a slice type.
|
// sliceType represents a slice type.
|
||||||
type SliceType struct {
|
type sliceType struct {
|
||||||
commonType "slice"
|
commonType "slice"
|
||||||
elem *runtime.Type
|
elem *runtime.Type
|
||||||
}
|
}
|
||||||
|
|
||||||
// arrayOrSliceType is an unexported method that guarantees only
|
|
||||||
// arrays and slices implement ArrayOrSliceType.
|
|
||||||
func (*SliceType) arrayOrSliceType() {}
|
|
||||||
|
|
||||||
// Struct field
|
// Struct field
|
||||||
type structField struct {
|
type structField struct {
|
||||||
name *string
|
name *string
|
||||||
|
|
@ -178,8 +317,8 @@ type structField struct {
|
||||||
offset uintptr
|
offset uintptr
|
||||||
}
|
}
|
||||||
|
|
||||||
// StructType represents a struct type.
|
// structType represents a struct type.
|
||||||
type StructType struct {
|
type structType struct {
|
||||||
commonType "struct"
|
commonType "struct"
|
||||||
fields []structField
|
fields []structField
|
||||||
}
|
}
|
||||||
|
|
@ -194,106 +333,10 @@ type StructType struct {
|
||||||
type Method struct {
|
type Method struct {
|
||||||
PkgPath string // empty for uppercase Name
|
PkgPath string // empty for uppercase Name
|
||||||
Name string
|
Name string
|
||||||
Type *FuncType
|
Type Type
|
||||||
Func *FuncValue
|
Func Value
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// Method returns the i'th method in the type's method set.
|
|
||||||
//
|
|
||||||
// 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
|
|
||||||
|
|
||||||
// NumMethods returns the number of methods in the type's method set.
|
|
||||||
NumMethod() int
|
|
||||||
|
|
||||||
common() *commonType
|
|
||||||
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
|
// High bit says whether type has
|
||||||
// embedded pointers,to help garbage collector.
|
// embedded pointers,to help garbage collector.
|
||||||
const kindMask = 0x7f
|
const kindMask = 0x7f
|
||||||
|
|
@ -306,6 +349,7 @@ func (k Kind) String() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
var kindNames = []string{
|
var kindNames = []string{
|
||||||
|
Invalid: "invalid",
|
||||||
Bool: "bool",
|
Bool: "bool",
|
||||||
Int: "int",
|
Int: "int",
|
||||||
Int8: "int8",
|
Int8: "int8",
|
||||||
|
|
@ -352,11 +396,24 @@ func (t *uncommonType) Name() string {
|
||||||
return *t.name
|
return *t.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *commonType) toType() Type {
|
||||||
|
if t == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
func (t *commonType) String() string { return *t.string }
|
func (t *commonType) String() string { return *t.string }
|
||||||
|
|
||||||
func (t *commonType) Size() uintptr { return t.size }
|
func (t *commonType) Size() uintptr { return t.size }
|
||||||
|
|
||||||
func (t *commonType) Bits() int { return int(t.size * 8) }
|
func (t *commonType) Bits() int {
|
||||||
|
k := t.Kind()
|
||||||
|
if k < Int || k > Complex128 {
|
||||||
|
panic("reflect: Bits of non-arithmetic Type")
|
||||||
|
}
|
||||||
|
return int(t.size) * 8
|
||||||
|
}
|
||||||
|
|
||||||
func (t *commonType) Align() int { return int(t.align) }
|
func (t *commonType) Align() int { return int(t.align) }
|
||||||
|
|
||||||
|
|
@ -377,9 +434,9 @@ func (t *uncommonType) Method(i int) (m Method) {
|
||||||
if p.pkgPath != nil {
|
if p.pkgPath != nil {
|
||||||
m.PkgPath = *p.pkgPath
|
m.PkgPath = *p.pkgPath
|
||||||
}
|
}
|
||||||
m.Type = toType(*p.typ).(*FuncType)
|
m.Type = toType(p.typ)
|
||||||
fn := p.tfn
|
fn := p.tfn
|
||||||
m.Func = &FuncValue{value: value{m.Type, addr(&fn), canSet}}
|
m.Func = Value{&funcValue{value: value{m.Type, addr(&fn), canSet}}}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,29 +450,154 @@ func (t *uncommonType) NumMethod() int {
|
||||||
// TODO(rsc): 6g supplies these, but they are not
|
// TODO(rsc): 6g supplies these, but they are not
|
||||||
// as efficient as they could be: they have commonType
|
// as efficient as they could be: they have commonType
|
||||||
// as the receiver instead of *commonType.
|
// as the receiver instead of *commonType.
|
||||||
func (t *commonType) NumMethod() int { return t.uncommonType.NumMethod() }
|
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) { return t.uncommonType.Method(i) }
|
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) PkgPath() string { return t.uncommonType.PkgPath() }
|
func (t *commonType) PkgPath() string {
|
||||||
|
return t.uncommonType.PkgPath()
|
||||||
|
}
|
||||||
|
|
||||||
func (t *commonType) Name() string { return t.uncommonType.Name() }
|
func (t *commonType) Name() string {
|
||||||
|
return t.uncommonType.Name()
|
||||||
|
}
|
||||||
|
|
||||||
// Len returns the number of elements in the array.
|
func (t *commonType) ChanDir() ChanDir {
|
||||||
func (t *ArrayType) Len() int { return int(t.len) }
|
if t.Kind() != Chan {
|
||||||
|
panic("reflect: ChanDir of non-chan type")
|
||||||
|
}
|
||||||
|
tt := (*chanType)(unsafe.Pointer(t))
|
||||||
|
return ChanDir(tt.dir)
|
||||||
|
}
|
||||||
|
|
||||||
// Elem returns the type of the array's elements.
|
func (t *commonType) IsVariadic() bool {
|
||||||
func (t *ArrayType) Elem() Type { return toType(*t.elem) }
|
if t.Kind() != Func {
|
||||||
|
panic("reflect: IsVariadic of non-func type")
|
||||||
|
}
|
||||||
|
tt := (*funcType)(unsafe.Pointer(t))
|
||||||
|
return tt.dotdotdot
|
||||||
|
}
|
||||||
|
|
||||||
// arrayOrSliceType is an unexported method that guarantees only
|
func (t *commonType) Elem() Type {
|
||||||
// arrays and slices implement ArrayOrSliceType.
|
switch t.Kind() {
|
||||||
func (*ArrayType) arrayOrSliceType() {}
|
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")
|
||||||
|
}
|
||||||
|
|
||||||
// Dir returns the channel direction.
|
func (t *commonType) Field(i int) StructField {
|
||||||
func (t *ChanType) Dir() ChanDir { return ChanDir(t.dir) }
|
if t.Kind() != Struct {
|
||||||
|
panic("reflect: Field of non-struct type")
|
||||||
|
}
|
||||||
|
tt := (*structType)(unsafe.Pointer(t))
|
||||||
|
return tt.Field(i)
|
||||||
|
}
|
||||||
|
|
||||||
// Elem returns the channel's element type.
|
func (t *commonType) FieldByIndex(index []int) StructField {
|
||||||
func (t *ChanType) Elem() Type { return toType(*t.elem) }
|
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 {
|
func (d ChanDir) String() string {
|
||||||
switch d {
|
switch d {
|
||||||
|
|
@ -429,43 +611,8 @@ func (d ChanDir) String() string {
|
||||||
return "ChanDir" + strconv.Itoa(int(d))
|
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, 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 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 method in the type's method set.
|
// Method returns the i'th method in the type's method set.
|
||||||
func (t *InterfaceType) Method(i int) (m Method) {
|
func (t *interfaceType) Method(i int) (m Method) {
|
||||||
if i < 0 || i >= len(t.methods) {
|
if i < 0 || i >= len(t.methods) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -474,24 +621,12 @@ func (t *InterfaceType) Method(i int) (m Method) {
|
||||||
if p.pkgPath != nil {
|
if p.pkgPath != nil {
|
||||||
m.PkgPath = *p.pkgPath
|
m.PkgPath = *p.pkgPath
|
||||||
}
|
}
|
||||||
m.Type = toType(*p.typ).(*FuncType)
|
m.Type = toType(p.typ)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumMethod returns the number of interface methods in the type's method set.
|
// NumMethod returns the number of interface methods in the type's method set.
|
||||||
func (t *InterfaceType) NumMethod() int { return len(t.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 {
|
type StructField struct {
|
||||||
PkgPath string // empty for uppercase Name
|
PkgPath string // empty for uppercase Name
|
||||||
|
|
@ -504,18 +639,18 @@ type StructField struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Field returns the i'th struct field.
|
// Field returns the i'th struct field.
|
||||||
func (t *StructType) Field(i int) (f StructField) {
|
func (t *structType) Field(i int) (f StructField) {
|
||||||
if i < 0 || i >= len(t.fields) {
|
if i < 0 || i >= len(t.fields) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
p := t.fields[i]
|
p := t.fields[i]
|
||||||
f.Type = toType(*p.typ)
|
f.Type = toType(p.typ)
|
||||||
if p.name != nil {
|
if p.name != nil {
|
||||||
f.Name = *p.name
|
f.Name = *p.name
|
||||||
} else {
|
} else {
|
||||||
t := f.Type
|
t := f.Type
|
||||||
if pt, ok := t.(*PtrType); ok {
|
if t.Kind() == Ptr {
|
||||||
t = pt.Elem()
|
t = t.Elem()
|
||||||
}
|
}
|
||||||
f.Name = t.Name()
|
f.Name = t.Name()
|
||||||
f.Anonymous = true
|
f.Anonymous = true
|
||||||
|
|
@ -535,29 +670,24 @@ func (t *StructType) Field(i int) (f StructField) {
|
||||||
// is wrong for FieldByIndex?
|
// is wrong for FieldByIndex?
|
||||||
|
|
||||||
// FieldByIndex returns the nested field corresponding to index.
|
// FieldByIndex returns the nested field corresponding to index.
|
||||||
func (t *StructType) FieldByIndex(index []int) (f StructField) {
|
func (t *structType) FieldByIndex(index []int) (f StructField) {
|
||||||
|
f.Type = Type(t.toType())
|
||||||
for i, x := range index {
|
for i, x := range index {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
ft := f.Type
|
ft := f.Type
|
||||||
if pt, ok := ft.(*PtrType); ok {
|
if ft.Kind() == Ptr && ft.Elem().Kind() == Struct {
|
||||||
ft = pt.Elem()
|
ft = ft.Elem()
|
||||||
}
|
|
||||||
if st, ok := ft.(*StructType); ok {
|
|
||||||
t = st
|
|
||||||
} else {
|
|
||||||
var f0 StructField
|
|
||||||
f = f0
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
f.Type = ft
|
||||||
}
|
}
|
||||||
f = t.Field(x)
|
f = f.Type.Field(x)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const inf = 1 << 30 // infinity - no struct has that many nesting levels
|
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) {
|
func (t *structType) fieldByNameFunc(match func(string) bool, mark map[*structType]bool, depth int) (ff StructField, fd int) {
|
||||||
fd = inf // field depth
|
fd = inf // field depth
|
||||||
|
|
||||||
if mark[t] {
|
if mark[t] {
|
||||||
|
|
@ -578,8 +708,8 @@ L:
|
||||||
d = depth
|
d = depth
|
||||||
case f.Anonymous:
|
case f.Anonymous:
|
||||||
ft := f.Type
|
ft := f.Type
|
||||||
if pt, ok := ft.(*PtrType); ok {
|
if ft.Kind() == Ptr {
|
||||||
ft = pt.Elem()
|
ft = ft.Elem()
|
||||||
}
|
}
|
||||||
switch {
|
switch {
|
||||||
case match(ft.Name()):
|
case match(ft.Name()):
|
||||||
|
|
@ -587,7 +717,8 @@ L:
|
||||||
d = depth
|
d = depth
|
||||||
case fd > depth:
|
case fd > depth:
|
||||||
// No top-level field yet; look inside nested structs.
|
// No top-level field yet; look inside nested structs.
|
||||||
if st, ok := ft.(*StructType); ok {
|
if ft.Kind() == Struct {
|
||||||
|
st := (*structType)(unsafe.Pointer(ft.(*commonType)))
|
||||||
f, d = st.fieldByNameFunc(match, mark, depth+1)
|
f, d = st.fieldByNameFunc(match, mark, depth+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -626,97 +757,54 @@ L:
|
||||||
|
|
||||||
// FieldByName returns the struct field with the given name
|
// FieldByName returns the struct field with the given name
|
||||||
// and a boolean to indicate if the field was found.
|
// and a boolean to indicate if the field was found.
|
||||||
func (t *StructType) FieldByName(name string) (f StructField, present bool) {
|
func (t *structType) FieldByName(name string) (f StructField, present bool) {
|
||||||
return t.FieldByNameFunc(func(s string) bool { return s == name })
|
return t.FieldByNameFunc(func(s string) bool { return s == name })
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldByNameFunc returns the struct field with a name that satisfies the
|
// FieldByNameFunc returns the struct field with a name that satisfies the
|
||||||
// match function and a boolean to indicate if the field was found.
|
// match function and a boolean to indicate if the field was found.
|
||||||
func (t *StructType) FieldByNameFunc(match func(string) bool) (f StructField, present bool) {
|
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 {
|
if ff, fd := t.fieldByNameFunc(match, make(map[*structType]bool), 0); fd < inf {
|
||||||
ff.Index = ff.Index[0 : fd+1]
|
ff.Index = ff.Index[0 : fd+1]
|
||||||
f, present = ff, true
|
f, present = ff, true
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// NumField returns the number of struct fields.
|
|
||||||
func (t *StructType) NumField() int { return len(t.fields) }
|
|
||||||
|
|
||||||
// Convert runtime type to reflect type.
|
// Convert runtime type to reflect type.
|
||||||
// Same memory layouts, different method sets.
|
func toType(p *runtime.Type) Type {
|
||||||
func toType(i interface{}) Type {
|
type hdr struct {
|
||||||
switch v := i.(type) {
|
x interface{}
|
||||||
case nil:
|
t commonType
|
||||||
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)
|
t := &(*hdr)(unsafe.Pointer(p)).t
|
||||||
panic("toType")
|
return t.toType()
|
||||||
}
|
|
||||||
|
|
||||||
// ArrayOrSliceType is the common interface implemented
|
|
||||||
// by both ArrayType and SliceType.
|
|
||||||
type ArrayOrSliceType interface {
|
|
||||||
Type
|
|
||||||
Elem() Type
|
|
||||||
arrayOrSliceType() // Guarantees only Array and Slice implement this interface.
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Typeof returns the reflection Type of the value in the interface{}.
|
// Typeof returns the reflection Type of the value in the interface{}.
|
||||||
func Typeof(i interface{}) Type { return toType(unsafe.Typeof(i)) }
|
func Typeof(i interface{}) Type {
|
||||||
|
type hdr struct {
|
||||||
|
typ *byte
|
||||||
|
val *commonType
|
||||||
|
}
|
||||||
|
rt := unsafe.Typeof(i)
|
||||||
|
t := (*(*hdr)(unsafe.Pointer(&rt))).val
|
||||||
|
return t.toType()
|
||||||
|
}
|
||||||
|
|
||||||
// ptrMap is the cache for PtrTo.
|
// ptrMap is the cache for PtrTo.
|
||||||
var ptrMap struct {
|
var ptrMap struct {
|
||||||
sync.RWMutex
|
sync.RWMutex
|
||||||
m map[Type]*PtrType
|
m map[*commonType]*ptrType
|
||||||
}
|
|
||||||
|
|
||||||
// runtimePtrType is the runtime layout for a *PtrType.
|
|
||||||
// The memory immediately before the *PtrType is always
|
|
||||||
// the canonical runtime.Type to be used for a *runtime.Type
|
|
||||||
// describing this PtrType.
|
|
||||||
type runtimePtrType struct {
|
|
||||||
runtime.Type
|
|
||||||
runtime.PtrType
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PtrTo returns the pointer type with element t.
|
// PtrTo returns the pointer type with element t.
|
||||||
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
|
// For example, if t represents type Foo, PtrTo(t) represents *Foo.
|
||||||
func PtrTo(t Type) *PtrType {
|
func PtrTo(t Type) Type {
|
||||||
// If t records its pointer-to type, use it.
|
// If t records its pointer-to type, use it.
|
||||||
ct := t.common()
|
ct := t.(*commonType)
|
||||||
if p := ct.ptrToThis; p != nil {
|
if p := ct.ptrToThis; p != nil {
|
||||||
return toType(*p).(*PtrType)
|
return toType(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Otherwise, synthesize one.
|
// Otherwise, synthesize one.
|
||||||
|
|
@ -726,35 +814,34 @@ func PtrTo(t Type) *PtrType {
|
||||||
// the type structures in read-only memory.
|
// the type structures in read-only memory.
|
||||||
ptrMap.RLock()
|
ptrMap.RLock()
|
||||||
if m := ptrMap.m; m != nil {
|
if m := ptrMap.m; m != nil {
|
||||||
if p := m[t]; p != nil {
|
if p := m[ct]; p != nil {
|
||||||
ptrMap.RUnlock()
|
ptrMap.RUnlock()
|
||||||
return p
|
return p.commonType.toType()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ptrMap.RUnlock()
|
ptrMap.RUnlock()
|
||||||
ptrMap.Lock()
|
ptrMap.Lock()
|
||||||
if ptrMap.m == nil {
|
if ptrMap.m == nil {
|
||||||
ptrMap.m = make(map[Type]*PtrType)
|
ptrMap.m = make(map[*commonType]*ptrType)
|
||||||
}
|
}
|
||||||
p := ptrMap.m[t]
|
p := ptrMap.m[ct]
|
||||||
if p != nil {
|
if p != nil {
|
||||||
// some other goroutine won the race and created it
|
// some other goroutine won the race and created it
|
||||||
ptrMap.Unlock()
|
ptrMap.Unlock()
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
// runtime.Type value is always right before type structure.
|
var rt struct {
|
||||||
// 2*ptrSize is size of interface header
|
i runtime.Type
|
||||||
rt := (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - uintptr(unsafe.Sizeof(runtime.Type(nil)))))
|
ptrType
|
||||||
|
}
|
||||||
|
rt.i = (*runtime.PtrType)(unsafe.Pointer(&rt.ptrType))
|
||||||
|
|
||||||
rp := new(runtimePtrType)
|
// initialize p using *byte's PtrType as a prototype.
|
||||||
rp.Type = &rp.PtrType
|
|
||||||
|
|
||||||
// initialize rp.PtrType using *byte's PtrType as a prototype.
|
|
||||||
// have to do assignment as PtrType, not runtime.PtrType,
|
// have to do assignment as PtrType, not runtime.PtrType,
|
||||||
// in order to write to unexported fields.
|
// in order to write to unexported fields.
|
||||||
p = (*PtrType)(unsafe.Pointer(&rp.PtrType))
|
p = &rt.ptrType
|
||||||
bp := (*PtrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
|
bp := (*ptrType)(unsafe.Pointer(unsafe.Typeof((*byte)(nil)).(*runtime.PtrType)))
|
||||||
*p = *bp
|
*p = *bp
|
||||||
|
|
||||||
s := "*" + *ct.string
|
s := "*" + *ct.string
|
||||||
|
|
@ -769,9 +856,9 @@ func PtrTo(t Type) *PtrType {
|
||||||
|
|
||||||
p.uncommonType = nil
|
p.uncommonType = nil
|
||||||
p.ptrToThis = nil
|
p.ptrToThis = nil
|
||||||
p.elem = rt
|
p.elem = (*runtime.Type)(unsafe.Pointer(uintptr(unsafe.Pointer(ct)) - uintptr(unsafe.Offsetof(rt.ptrType))))
|
||||||
|
|
||||||
ptrMap.m[t] = (*PtrType)(unsafe.Pointer(&rp.PtrType))
|
ptrMap.m[ct] = p
|
||||||
ptrMap.Unlock()
|
ptrMap.Unlock()
|
||||||
return p
|
return p.commonType.toType()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue