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:
Russ Cox 2011-04-08 12:26:51 -04:00
parent 846a368b88
commit fb175cf77e
5 changed files with 1437 additions and 888 deletions

View file

@ -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")
} }

View file

@ -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
} }
} }

View file

@ -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())
} }

View file

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