summaryrefslogtreecommitdiff
path: root/src/pkg/gob
diff options
context:
space:
mode:
Diffstat (limited to 'src/pkg/gob')
-rw-r--r--src/pkg/gob/Makefile4
-rw-r--r--src/pkg/gob/codec_test.go772
-rw-r--r--src/pkg/gob/debug.go310
-rw-r--r--src/pkg/gob/decode.go488
-rw-r--r--src/pkg/gob/decoder.go121
-rw-r--r--src/pkg/gob/doc.go307
-rw-r--r--src/pkg/gob/encode.go541
-rw-r--r--src/pkg/gob/encoder.go81
-rw-r--r--src/pkg/gob/encoder_test.go205
-rw-r--r--src/pkg/gob/error.go41
-rw-r--r--src/pkg/gob/type.go265
-rw-r--r--src/pkg/gob/type_test.go12
12 files changed, 1954 insertions, 1193 deletions
diff --git a/src/pkg/gob/Makefile b/src/pkg/gob/Makefile
index 1091adb01..68007c189 100644
--- a/src/pkg/gob/Makefile
+++ b/src/pkg/gob/Makefile
@@ -2,14 +2,16 @@
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
-include ../../Make.$(GOARCH)
+include ../../Make.inc
TARG=gob
GOFILES=\
decode.go\
decoder.go\
+ doc.go\
encode.go\
encoder.go\
+ error.go\
type.go\
include ../../Make.pkg
diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go
index 2caaaa43f..d150dbe9a 100644
--- a/src/pkg/gob/codec_test.go
+++ b/src/pkg/gob/codec_test.go
@@ -21,50 +21,50 @@ type EncodeT struct {
}
var encodeT = []EncodeT{
- EncodeT{0x00, []byte{0x00}},
- EncodeT{0x0F, []byte{0x0F}},
- EncodeT{0xFF, []byte{0xFF, 0xFF}},
- EncodeT{0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
- EncodeT{0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
- EncodeT{0x1111, []byte{0xFE, 0x11, 0x11}},
- EncodeT{0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
- EncodeT{0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
- EncodeT{1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {0x00, []byte{0x00}},
+ {0x0F, []byte{0x0F}},
+ {0xFF, []byte{0xFF, 0xFF}},
+ {0xFFFF, []byte{0xFE, 0xFF, 0xFF}},
+ {0xFFFFFF, []byte{0xFD, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFF, []byte{0xFC, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFF, []byte{0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFF, []byte{0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFF, []byte{0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0xFFFFFFFFFFFFFFFF, []byte{0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}},
+ {0x1111, []byte{0xFE, 0x11, 0x11}},
+ {0x1111111111111111, []byte{0xF8, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11}},
+ {0x8888888888888888, []byte{0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88}},
+ {1 << 63, []byte{0xF8, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+}
+
+// testError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain test.Error call.
+func testError(t *testing.T) {
+ if e := recover(); e != nil {
+ t.Error(e.(gobError).Error) // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
}
// Test basic encode/decode routines for unsigned integers
func TestUintCodec(t *testing.T) {
+ defer testError(t)
b := new(bytes.Buffer)
- encState := new(encoderState)
- encState.b = b
+ encState := newEncoderState(nil, b)
for _, tt := range encodeT {
b.Reset()
- encodeUint(encState, tt.x)
- if encState.err != nil {
- t.Error("encodeUint:", tt.x, encState.err)
- }
+ encState.encodeUint(tt.x)
if !bytes.Equal(tt.b, b.Bytes()) {
t.Errorf("encodeUint: %#x encode: expected % x got % x", tt.x, tt.b, b.Bytes())
}
}
- decState := newDecodeState(b)
+ decState := newDecodeState(nil, &b)
for u := uint64(0); ; u = (u + 1) * 7 {
b.Reset()
- encodeUint(encState, u)
- if encState.err != nil {
- t.Error("encodeUint:", u, encState.err)
- }
- v := decodeUint(decState)
- if decState.err != nil {
- t.Error("DecodeUint:", u, decState.err)
- }
+ encState.encodeUint(u)
+ v := decState.decodeUint()
if u != v {
- t.Errorf("Encode/Decode: sent %#x received %#x\n", u, v)
+ t.Errorf("Encode/Decode: sent %#x received %#x", u, v)
}
if u&(1<<63) != 0 {
break
@@ -73,21 +73,15 @@ func TestUintCodec(t *testing.T) {
}
func verifyInt(i int64, t *testing.T) {
+ defer testError(t)
var b = new(bytes.Buffer)
- encState := new(encoderState)
- encState.b = b
- encodeInt(encState, i)
- if encState.err != nil {
- t.Error("encodeInt:", i, encState.err)
- }
- decState := newDecodeState(b)
+ encState := newEncoderState(nil, b)
+ encState.encodeInt(i)
+ decState := newDecodeState(nil, &b)
decState.buf = make([]byte, 8)
- j := decodeInt(decState)
- if decState.err != nil {
- t.Error("DecodeInt:", i, decState.err)
- }
+ j := decState.decodeInt()
if i != j {
- t.Errorf("Encode/Decode: sent %#x received %#x\n", uint64(i), uint64(j))
+ t.Errorf("Encode/Decode: sent %#x received %#x", uint64(i), uint64(j))
}
}
@@ -119,8 +113,7 @@ var bytesResult = []byte{0x07, 0x05, 'h', 'e', 'l', 'l', 'o'}
func newencoderState(b *bytes.Buffer) *encoderState {
b.Reset()
- state := new(encoderState)
- state.b = b
+ state := newEncoderState(nil, b)
state.fieldnum = -1
return state
}
@@ -323,10 +316,8 @@ func TestScalarEncInstructions(t *testing.T) {
}
func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p unsafe.Pointer) {
- v := int(decodeUint(state))
- if state.err != nil {
- t.Fatalf("decoding %s field: %v", typ, state.err)
- }
+ defer testError(t)
+ v := int(state.decodeUint())
if v+state.fieldnum != 6 {
t.Fatalf("decoding field number %d, got %d", 6, v+state.fieldnum)
}
@@ -335,7 +326,8 @@ func execDec(typ string, instr *decInstr, state *decodeState, t *testing.T, p un
}
func newDecodeStateFromData(data []byte) *decodeState {
- state := newDecodeState(bytes.NewBuffer(data))
+ b := bytes.NewBuffer(data)
+ state := newDecodeState(nil, &b)
state.fieldnum = -1
return state
}
@@ -607,35 +599,35 @@ func TestScalarDecInstructions(t *testing.T) {
func TestEndToEnd(t *testing.T) {
type T2 struct {
- t string
+ T string
}
s1 := "string1"
s2 := "string2"
type T1 struct {
- a, b, c int
- m map[string]*float
- n *[3]float
- strs *[2]string
- int64s *[]int64
- ri complex64
- s string
- y []byte
- t *T2
+ A, B, C int
+ M map[string]*float
+ N *[3]float
+ Strs *[2]string
+ Int64s *[]int64
+ RI complex64
+ S string
+ Y []byte
+ T *T2
}
pi := 3.14159
e := 2.71828
t1 := &T1{
- a: 17,
- b: 18,
- c: -5,
- m: map[string]*float{"pi": &pi, "e": &e},
- n: &[3]float{1.5, 2.5, 3.5},
- strs: &[2]string{s1, s2},
- int64s: &[]int64{77, 89, 123412342134},
- ri: 17 - 23i,
- s: "Now is the time",
- y: []byte("hello, sailor"),
- t: &T2{"this is T2"},
+ A: 17,
+ B: 18,
+ C: -5,
+ M: map[string]*float{"pi": &pi, "e": &e},
+ N: &[3]float{1.5, 2.5, 3.5},
+ Strs: &[2]string{s1, s2},
+ Int64s: &[]int64{77, 89, 123412342134},
+ RI: 17 - 23i,
+ S: "Now is the time",
+ Y: []byte("hello, sailor"),
+ T: &T2{"this is T2"},
}
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(t1)
@@ -654,13 +646,13 @@ func TestEndToEnd(t *testing.T) {
func TestOverflow(t *testing.T) {
type inputT struct {
- maxi int64
- mini int64
- maxu uint64
- maxf float64
- minf float64
- maxc complex128
- minc complex128
+ Maxi int64
+ Mini int64
+ Maxu uint64
+ Maxf float64
+ Minf float64
+ Maxc complex128
+ Minc complex128
}
var it inputT
var err os.Error
@@ -671,152 +663,152 @@ func TestOverflow(t *testing.T) {
// int8
b.Reset()
it = inputT{
- maxi: math.MaxInt8 + 1,
+ Maxi: math.MaxInt8 + 1,
}
type outi8 struct {
- maxi int8
- mini int8
+ Maxi int8
+ Mini int8
}
var o1 outi8
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int8:", err)
}
it = inputT{
- mini: math.MinInt8 - 1,
+ Mini: math.MinInt8 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o1)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int8:", err)
}
// int16
b.Reset()
it = inputT{
- maxi: math.MaxInt16 + 1,
+ Maxi: math.MaxInt16 + 1,
}
type outi16 struct {
- maxi int16
- mini int16
+ Maxi int16
+ Mini int16
}
var o2 outi16
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int16:", err)
}
it = inputT{
- mini: math.MinInt16 - 1,
+ Mini: math.MinInt16 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o2)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int16:", err)
}
// int32
b.Reset()
it = inputT{
- maxi: math.MaxInt32 + 1,
+ Maxi: math.MaxInt32 + 1,
}
type outi32 struct {
- maxi int32
- mini int32
+ Maxi int32
+ Mini int32
}
var o3 outi32
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "maxi" out of range` {
+ if err == nil || err.String() != `value for "Maxi" out of range` {
t.Error("wrong overflow error for int32:", err)
}
it = inputT{
- mini: math.MinInt32 - 1,
+ Mini: math.MinInt32 - 1,
}
b.Reset()
enc.Encode(it)
err = dec.Decode(&o3)
- if err == nil || err.String() != `value for "mini" out of range` {
+ if err == nil || err.String() != `value for "Mini" out of range` {
t.Error("wrong underflow error for int32:", err)
}
// uint8
b.Reset()
it = inputT{
- maxu: math.MaxUint8 + 1,
+ Maxu: math.MaxUint8 + 1,
}
type outu8 struct {
- maxu uint8
+ Maxu uint8
}
var o4 outu8
enc.Encode(it)
err = dec.Decode(&o4)
- if err == nil || err.String() != `value for "maxu" out of range` {
+ if err == nil || err.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint8:", err)
}
// uint16
b.Reset()
it = inputT{
- maxu: math.MaxUint16 + 1,
+ Maxu: math.MaxUint16 + 1,
}
type outu16 struct {
- maxu uint16
+ Maxu uint16
}
var o5 outu16
enc.Encode(it)
err = dec.Decode(&o5)
- if err == nil || err.String() != `value for "maxu" out of range` {
+ if err == nil || err.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint16:", err)
}
// uint32
b.Reset()
it = inputT{
- maxu: math.MaxUint32 + 1,
+ Maxu: math.MaxUint32 + 1,
}
type outu32 struct {
- maxu uint32
+ Maxu uint32
}
var o6 outu32
enc.Encode(it)
err = dec.Decode(&o6)
- if err == nil || err.String() != `value for "maxu" out of range` {
+ if err == nil || err.String() != `value for "Maxu" out of range` {
t.Error("wrong overflow error for uint32:", err)
}
// float32
b.Reset()
it = inputT{
- maxf: math.MaxFloat32 * 2,
+ Maxf: math.MaxFloat32 * 2,
}
type outf32 struct {
- maxf float32
- minf float32
+ Maxf float32
+ Minf float32
}
var o7 outf32
enc.Encode(it)
err = dec.Decode(&o7)
- if err == nil || err.String() != `value for "maxf" out of range` {
+ if err == nil || err.String() != `value for "Maxf" out of range` {
t.Error("wrong overflow error for float32:", err)
}
// complex64
b.Reset()
it = inputT{
- maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
+ Maxc: cmplx(math.MaxFloat32*2, math.MaxFloat32*2),
}
type outc64 struct {
- maxc complex64
- minc complex64
+ Maxc complex64
+ Minc complex64
}
var o8 outc64
enc.Encode(it)
err = dec.Decode(&o8)
- if err == nil || err.String() != `value for "maxc" out of range` {
+ if err == nil || err.String() != `value for "Maxc" out of range` {
t.Error("wrong overflow error for complex64:", err)
}
}
@@ -824,92 +816,92 @@ func TestOverflow(t *testing.T) {
func TestNesting(t *testing.T) {
type RT struct {
- a string
- next *RT
+ A string
+ Next *RT
}
rt := new(RT)
- rt.a = "level1"
- rt.next = new(RT)
- rt.next.a = "level2"
+ rt.A = "level1"
+ rt.Next = new(RT)
+ rt.Next.A = "level2"
b := new(bytes.Buffer)
NewEncoder(b).Encode(rt)
var drt RT
dec := NewDecoder(b)
err := dec.Decode(&drt)
if err != nil {
- t.Errorf("decoder error:", err)
+ t.Fatal("decoder error:", err)
}
- if drt.a != rt.a {
+ if drt.A != rt.A {
t.Errorf("nesting: encode expected %v got %v", *rt, drt)
}
- if drt.next == nil {
+ if drt.Next == nil {
t.Errorf("nesting: recursion failed")
}
- if drt.next.a != rt.next.a {
- t.Errorf("nesting: encode expected %v got %v", *rt.next, *drt.next)
+ if drt.Next.A != rt.Next.A {
+ t.Errorf("nesting: encode expected %v got %v", *rt.Next, *drt.Next)
}
}
// These three structures have the same data with different indirections
type T0 struct {
- a int
- b int
- c int
- d int
+ A int
+ B int
+ C int
+ D int
}
type T1 struct {
- a int
- b *int
- c **int
- d ***int
+ A int
+ B *int
+ C **int
+ D ***int
}
type T2 struct {
- a ***int
- b **int
- c *int
- d int
+ A ***int
+ B **int
+ C *int
+ D int
}
func TestAutoIndirection(t *testing.T) {
// First transfer t1 into t0
var t1 T1
- t1.a = 17
- t1.b = new(int)
- *t1.b = 177
- t1.c = new(*int)
- *t1.c = new(int)
- **t1.c = 1777
- t1.d = new(**int)
- *t1.d = new(*int)
- **t1.d = new(int)
- ***t1.d = 17777
+ t1.A = 17
+ t1.B = new(int)
+ *t1.B = 177
+ t1.C = new(*int)
+ *t1.C = new(int)
+ **t1.C = 1777
+ t1.D = new(**int)
+ *t1.D = new(*int)
+ **t1.D = new(int)
+ ***t1.D = 17777
b := new(bytes.Buffer)
enc := NewEncoder(b)
enc.Encode(t1)
dec := NewDecoder(b)
var t0 T0
dec.Decode(&t0)
- if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
t.Errorf("t1->t0: expected {17 177 1777 17777}; got %v", t0)
}
// Now transfer t2 into t0
var t2 T2
- t2.d = 17777
- t2.c = new(int)
- *t2.c = 1777
- t2.b = new(*int)
- *t2.b = new(int)
- **t2.b = 177
- t2.a = new(**int)
- *t2.a = new(*int)
- **t2.a = new(int)
- ***t2.a = 17
+ t2.D = 17777
+ t2.C = new(int)
+ *t2.C = 1777
+ t2.B = new(*int)
+ *t2.B = new(int)
+ **t2.B = 177
+ t2.A = new(**int)
+ *t2.A = new(*int)
+ **t2.A = new(int)
+ ***t2.A = 17
b.Reset()
enc.Encode(t2)
t0 = T0{}
dec.Decode(&t0)
- if t0.a != 17 || t0.b != 177 || t0.c != 1777 || t0.d != 17777 {
+ if t0.A != 17 || t0.B != 177 || t0.C != 1777 || t0.D != 17777 {
t.Errorf("t2->t0 expected {17 177 1777 17777}; got %v", t0)
}
@@ -919,8 +911,8 @@ func TestAutoIndirection(t *testing.T) {
enc.Encode(t0)
t1 = T1{}
dec.Decode(&t1)
- if t1.a != 17 || *t1.b != 177 || **t1.c != 1777 || ***t1.d != 17777 {
- t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.a, *t1.b, **t1.c, ***t1.d)
+ if t1.A != 17 || *t1.B != 177 || **t1.C != 1777 || ***t1.D != 17777 {
+ t.Errorf("t0->t1 expected {17 177 1777 17777}; got {%d %d %d %d}", t1.A, *t1.B, **t1.C, ***t1.D)
}
// Now transfer t0 into t2
@@ -928,40 +920,40 @@ func TestAutoIndirection(t *testing.T) {
enc.Encode(t0)
t2 = T2{}
dec.Decode(&t2)
- if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
- t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
}
// Now do t2 again but without pre-allocated pointers.
b.Reset()
enc.Encode(t0)
- ***t2.a = 0
- **t2.b = 0
- *t2.c = 0
- t2.d = 0
+ ***t2.A = 0
+ **t2.B = 0
+ *t2.C = 0
+ t2.D = 0
dec.Decode(&t2)
- if ***t2.a != 17 || **t2.b != 177 || *t2.c != 1777 || t2.d != 17777 {
- t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.a, **t2.b, *t2.c, t2.d)
+ if ***t2.A != 17 || **t2.B != 177 || *t2.C != 1777 || t2.D != 17777 {
+ t.Errorf("t0->t2 expected {17 177 1777 17777}; got {%d %d %d %d}", ***t2.A, **t2.B, *t2.C, t2.D)
}
}
type RT0 struct {
- a int
- b string
- c float
+ A int
+ B string
+ C float
}
type RT1 struct {
- c float
- b string
- a int
- notSet string
+ C float
+ B string
+ A int
+ NotSet string
}
func TestReorderedFields(t *testing.T) {
var rt0 RT0
- rt0.a = 17
- rt0.b = "hello"
- rt0.c = 3.14159
+ rt0.A = 17
+ rt0.B = "hello"
+ rt0.C = 3.14159
b := new(bytes.Buffer)
NewEncoder(b).Encode(rt0)
dec := NewDecoder(b)
@@ -969,41 +961,41 @@ func TestReorderedFields(t *testing.T) {
// Wire type is RT0, local type is RT1.
err := dec.Decode(&rt1)
if err != nil {
- t.Error("decode error:", err)
+ t.Fatal("decode error:", err)
}
- if rt0.a != rt1.a || rt0.b != rt1.b || rt0.c != rt1.c {
+ if rt0.A != rt1.A || rt0.B != rt1.B || rt0.C != rt1.C {
t.Errorf("rt1->rt0: expected %v; got %v", rt0, rt1)
}
}
// Like an RT0 but with fields we'll ignore on the decode side.
type IT0 struct {
- a int64
- b string
- ignore_d []int
- ignore_e [3]float
- ignore_f bool
- ignore_g string
- ignore_h []byte
- ignore_i *RT1
- ignore_m map[string]int
- c float
+ A int64
+ B string
+ Ignore_d []int
+ Ignore_e [3]float
+ Ignore_f bool
+ Ignore_g string
+ Ignore_h []byte
+ Ignore_i *RT1
+ Ignore_m map[string]int
+ C float
}
func TestIgnoredFields(t *testing.T) {
var it0 IT0
- it0.a = 17
- it0.b = "hello"
- it0.c = 3.14159
- it0.ignore_d = []int{1, 2, 3}
- it0.ignore_e[0] = 1.0
- it0.ignore_e[1] = 2.0
- it0.ignore_e[2] = 3.0
- it0.ignore_f = true
- it0.ignore_g = "pay no attention"
- it0.ignore_h = []byte("to the curtain")
- it0.ignore_i = &RT1{3.1, "hi", 7, "hello"}
- it0.ignore_m = map[string]int{"one": 1, "two": 2}
+ it0.A = 17
+ it0.B = "hello"
+ it0.C = 3.14159
+ it0.Ignore_d = []int{1, 2, 3}
+ it0.Ignore_e[0] = 1.0
+ it0.Ignore_e[1] = 2.0
+ it0.Ignore_e[2] = 3.0
+ it0.Ignore_f = true
+ it0.Ignore_g = "pay no attention"
+ it0.Ignore_h = []byte("to the curtain")
+ it0.Ignore_i = &RT1{3.1, "hi", 7, "hello"}
+ it0.Ignore_m = map[string]int{"one": 1, "two": 2}
b := new(bytes.Buffer)
NewEncoder(b).Encode(it0)
@@ -1014,56 +1006,58 @@ func TestIgnoredFields(t *testing.T) {
if err != nil {
t.Error("error: ", err)
}
- if int(it0.a) != rt1.a || it0.b != rt1.b || it0.c != rt1.c {
- t.Errorf("rt1->rt0: expected %v; got %v", it0, rt1)
+ if int(it0.A) != rt1.A || it0.B != rt1.B || it0.C != rt1.C {
+ t.Errorf("rt0->rt1: expected %v; got %v", it0, rt1)
}
}
type Bad0 struct {
- inter interface{}
- c float
+ ch chan int
+ c float
}
+var nilEncoder *Encoder
+
func TestInvalidField(t *testing.T) {
var bad0 Bad0
- bad0.inter = 17
+ bad0.ch = make(chan int)
b := new(bytes.Buffer)
- err := encode(b, reflect.NewValue(&bad0))
+ err := nilEncoder.encode(b, reflect.NewValue(&bad0))
if err == nil {
t.Error("expected error; got none")
- } else if strings.Index(err.String(), "interface") < 0 {
+ } else if strings.Index(err.String(), "type") < 0 {
t.Error("expected type error; got", err)
}
}
type Indirect struct {
- a ***[3]int
- s ***[]int
- m ****map[string]int
+ A ***[3]int
+ S ***[]int
+ M ****map[string]int
}
type Direct struct {
- a [3]int
- s []int
- m map[string]int
+ A [3]int
+ S []int
+ M map[string]int
}
func TestIndirectSliceMapArray(t *testing.T) {
// Marshal indirect, unmarshal to direct.
i := new(Indirect)
- i.a = new(**[3]int)
- *i.a = new(*[3]int)
- **i.a = new([3]int)
- ***i.a = [3]int{1, 2, 3}
- i.s = new(**[]int)
- *i.s = new(*[]int)
- **i.s = new([]int)
- ***i.s = []int{4, 5, 6}
- i.m = new(***map[string]int)
- *i.m = new(**map[string]int)
- **i.m = new(*map[string]int)
- ***i.m = new(map[string]int)
- ****i.m = map[string]int{"one": 1, "two": 2, "three": 3}
+ i.A = new(**[3]int)
+ *i.A = new(*[3]int)
+ **i.A = new([3]int)
+ ***i.A = [3]int{1, 2, 3}
+ i.S = new(**[]int)
+ *i.S = new(*[]int)
+ **i.S = new([]int)
+ ***i.S = []int{4, 5, 6}
+ i.M = new(***map[string]int)
+ *i.M = new(**map[string]int)
+ **i.M = new(*map[string]int)
+ ***i.M = new(map[string]int)
+ ****i.M = map[string]int{"one": 1, "two": 2, "three": 3}
b := new(bytes.Buffer)
NewEncoder(b).Encode(i)
dec := NewDecoder(b)
@@ -1072,34 +1066,328 @@ func TestIndirectSliceMapArray(t *testing.T) {
if err != nil {
t.Error("error: ", err)
}
- if len(d.a) != 3 || d.a[0] != 1 || d.a[1] != 2 || d.a[2] != 3 {
- t.Errorf("indirect to direct: d.a is %v not %v", d.a, ***i.a)
+ if len(d.A) != 3 || d.A[0] != 1 || d.A[1] != 2 || d.A[2] != 3 {
+ t.Errorf("indirect to direct: d.A is %v not %v", d.A, ***i.A)
}
- if len(d.s) != 3 || d.s[0] != 4 || d.s[1] != 5 || d.s[2] != 6 {
- t.Errorf("indirect to direct: d.s is %v not %v", d.s, ***i.s)
+ if len(d.S) != 3 || d.S[0] != 4 || d.S[1] != 5 || d.S[2] != 6 {
+ t.Errorf("indirect to direct: d.S is %v not %v", d.S, ***i.S)
}
- if len(d.m) != 3 || d.m["one"] != 1 || d.m["two"] != 2 || d.m["three"] != 3 {
- t.Errorf("indirect to direct: d.m is %v not %v", d.m, ***i.m)
+ if len(d.M) != 3 || d.M["one"] != 1 || d.M["two"] != 2 || d.M["three"] != 3 {
+ t.Errorf("indirect to direct: d.M is %v not %v", d.M, ***i.M)
}
// Marshal direct, unmarshal to indirect.
- d.a = [3]int{11, 22, 33}
- d.s = []int{44, 55, 66}
- d.m = map[string]int{"four": 4, "five": 5, "six": 6}
+ d.A = [3]int{11, 22, 33}
+ d.S = []int{44, 55, 66}
+ d.M = map[string]int{"four": 4, "five": 5, "six": 6}
i = new(Indirect)
b.Reset()
NewEncoder(b).Encode(d)
dec = NewDecoder(b)
err = dec.Decode(&i)
if err != nil {
- t.Error("error: ", err)
+ t.Fatal("error: ", err)
+ }
+ if len(***i.A) != 3 || (***i.A)[0] != 11 || (***i.A)[1] != 22 || (***i.A)[2] != 33 {
+ t.Errorf("direct to indirect: ***i.A is %v not %v", ***i.A, d.A)
+ }
+ if len(***i.S) != 3 || (***i.S)[0] != 44 || (***i.S)[1] != 55 || (***i.S)[2] != 66 {
+ t.Errorf("direct to indirect: ***i.S is %v not %v", ***i.S, ***i.S)
+ }
+ if len(****i.M) != 3 || (****i.M)["four"] != 4 || (****i.M)["five"] != 5 || (****i.M)["six"] != 6 {
+ t.Errorf("direct to indirect: ****i.M is %v not %v", ****i.M, d.M)
+ }
+}
+
+// An interface with several implementations
+type Squarer interface {
+ Square() int
+}
+
+type Int int
+
+func (i Int) Square() int {
+ return int(i * i)
+}
+
+type Float float
+
+func (f Float) Square() int {
+ return int(f * f)
+}
+
+type Vector []int
+
+func (v Vector) Square() int {
+ sum := 0
+ for _, x := range v {
+ sum += x * x
+ }
+ return sum
+}
+
+type Point struct {
+ a, b int
+}
+
+func (p Point) Square() int {
+ return p.a*p.a + p.b*p.b
+}
+
+// A struct with interfaces in it.
+type InterfaceItem struct {
+ I int
+ Sq1, Sq2, Sq3 Squarer
+ F float
+ Sq []Squarer
+}
+
+// The same struct without interfaces
+type NoInterfaceItem struct {
+ I int
+ F float
+}
+
+func TestInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Vector will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ vVal := Vector{1, 2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, vVal, 11.5, []Squarer{iVal, fVal, nil, vVal}}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Vector{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := InterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.Sq1 == nil || item2.Sq1.Square() != iVal.Square() {
+ t.Error("Int did not decode correctly")
+ }
+ if item2.Sq2 == nil || item2.Sq2.Square() != fVal.Square() {
+ t.Error("Float did not decode correctly")
+ }
+ if item2.Sq3 == nil || item2.Sq3.Square() != vVal.Square() {
+ t.Error("Vector did not decode correctly")
+ }
+ if item2.F != item1.F {
+ t.Error("normal float did not decode correctly")
}
- if len(***i.a) != 3 || (***i.a)[0] != 11 || (***i.a)[1] != 22 || (***i.a)[2] != 33 {
- t.Errorf("direct to indirect: ***i.a is %v not %v", ***i.a, d.a)
+ // Now check that we received a slice of Squarers correctly, including a nil element
+ if len(item1.Sq) != len(item2.Sq) {
+ t.Fatalf("[]Squarer length wrong: got %d; expected %d", len(item2.Sq), len(item1.Sq))
}
- if len(***i.s) != 3 || (***i.s)[0] != 44 || (***i.s)[1] != 55 || (***i.s)[2] != 66 {
- t.Errorf("direct to indirect: ***i.s is %v not %v", ***i.s, ***i.s)
+ for i, v1 := range item1.Sq {
+ v2 := item2.Sq[i]
+ if v1 == nil || v2 == nil {
+ if v1 != nil || v2 != nil {
+ t.Errorf("item %d inconsistent nils", i)
+ }
+ continue
+ if v1.Square() != v2.Square() {
+ t.Errorf("item %d inconsistent values: %v %v", i, v1, v2)
+ }
+ }
}
- if len(****i.m) != 3 || (****i.m)["four"] != 4 || (****i.m)["five"] != 5 || (****i.m)["six"] != 6 {
- t.Errorf("direct to indirect: ****i.m is %v not %v", ****i.m, d.m)
+
+}
+
+// A struct with all basic types, stored in interfaces.
+type BasicInterfaceItem struct {
+ Int, Int8, Int16, Int32, Int64 interface{}
+ Uint, Uint8, Uint16, Uint32, Uint64 interface{}
+ Float, Float32, Float64 interface{}
+ Complex, Complex64, Complex128 interface{}
+ Bool interface{}
+ String interface{}
+ Bytes interface{}
+}
+
+func TestInterfaceBasic(t *testing.T) {
+ b := new(bytes.Buffer)
+ item1 := &BasicInterfaceItem{
+ int(1), int8(1), int16(1), int32(1), int64(1),
+ uint(1), uint8(1), uint16(1), uint32(1), uint64(1),
+ float(1), float32(1), float64(1),
+ complex(0i), complex64(0i), complex128(0i),
+ true,
+ "hello",
+ []byte("sailor"),
+ }
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &BasicInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if !reflect.DeepEqual(item1, item2) {
+ t.Errorf("encode expected %v got %v", item1, item2)
+ }
+ // Hand check a couple for correct types.
+ if v, ok := item2.Bool.(bool); !ok || !v {
+ t.Error("boolean should be true")
+ }
+ if v, ok := item2.String.(string); !ok || v != item1.String.(string) {
+ t.Errorf("string should be %v is %v", item1.String, v)
+ }
+}
+
+type String string
+
+type PtrInterfaceItem struct {
+ Str1 interface{} // basic
+ Str2 interface{} // derived
+}
+
+// We'll send pointers; should receive values.
+// Also check that we can register T but send *T.
+func TestInterfacePointer(t *testing.T) {
+ b := new(bytes.Buffer)
+ str1 := "howdy"
+ str2 := String("kiddo")
+ item1 := &PtrInterfaceItem{
+ &str1,
+ &str2,
+ }
+ // Register the type.
+ Register(str2)
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := &PtrInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ // Hand test for correct types and values.
+ if v, ok := item2.Str1.(string); !ok || v != str1 {
+ t.Errorf("basic string failed: %q should be %q", v, str1)
+ }
+ if v, ok := item2.Str2.(String); !ok || v != str2 {
+ t.Errorf("derived type String failed: %q should be %q", v, str2)
+ }
+}
+
+func TestIgnoreInterface(t *testing.T) {
+ iVal := Int(3)
+ fVal := Float(5)
+ // Sending a Point will require that the receiver define a type in the middle of
+ // receiving the value for item2.
+ pVal := Point{2, 3}
+ b := new(bytes.Buffer)
+ item1 := &InterfaceItem{1, iVal, fVal, pVal, 11.5, nil}
+ // Register the types.
+ Register(Int(0))
+ Register(Float(0))
+ Register(Point{})
+ err := NewEncoder(b).Encode(item1)
+ if err != nil {
+ t.Error("expected no encode error; got", err)
+ }
+
+ item2 := NoInterfaceItem{}
+ err = NewDecoder(b).Decode(&item2)
+ if err != nil {
+ t.Fatal("decode:", err)
+ }
+ if item2.I != item1.I {
+ t.Error("normal int did not decode correctly")
+ }
+ if item2.F != item2.F {
+ t.Error("normal float did not decode correctly")
+ }
+}
+
+type U struct {
+ A int
+ B string
+ c float
+ D uint
+}
+
+func TestUnexportedFields(t *testing.T) {
+ var u0 U
+ u0.A = 17
+ u0.B = "hello"
+ u0.c = 3.14159
+ u0.D = 23
+ b := new(bytes.Buffer)
+ NewEncoder(b).Encode(u0)
+ dec := NewDecoder(b)
+ var u1 U
+ u1.c = 1234.
+ err := dec.Decode(&u1)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+ if u0.A != u0.A || u0.B != u1.B || u0.D != u1.D {
+ t.Errorf("u1->u0: expected %v; got %v", u0, u1)
+ }
+ if u1.c != 1234. {
+ t.Error("u1.c modified")
+ }
+}
+
+// A type that won't be defined in the gob until we send it in an interface value.
+type OnTheFly struct {
+ A int
+}
+
+type DT struct {
+ // X OnTheFly
+ A int
+ B string
+ C float
+ I interface{}
+ J interface{}
+ I_nil interface{}
+ M map[string]int
+ T [3]int
+ S []string
+}
+
+func TestDebug(t *testing.T) {
+ if debugFunc == nil {
+ return
+ }
+ Register(OnTheFly{})
+ var dt DT
+ dt.A = 17
+ dt.B = "hello"
+ dt.C = 3.14159
+ dt.I = 271828
+ dt.J = OnTheFly{3}
+ dt.I_nil = nil
+ dt.M = map[string]int{"one": 1, "two": 2}
+ dt.T = [3]int{11, 22, 33}
+ dt.S = []string{"hi", "joe"}
+ b := new(bytes.Buffer)
+ err := NewEncoder(b).Encode(dt)
+ if err != nil {
+ t.Fatal("encode:", err)
+ }
+ debugBuffer := bytes.NewBuffer(b.Bytes())
+ dt2 := &DT{}
+ err = NewDecoder(b).Decode(&dt2)
+ if err != nil {
+ t.Error("decode:", err)
}
+ debugFunc(debugBuffer)
}
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
index 02f2602ed..f3632a080 100644
--- a/src/pkg/gob/debug.go
+++ b/src/pkg/gob/debug.go
@@ -1,157 +1,236 @@
package gob
// This file is not normally included in the gob package. Used only for debugging the package itself.
+// Add debug.go to the files listed in the Makefile to add Debug to the gob package.
import (
"bytes"
"fmt"
"io"
- "log"
"os"
+ "reflect"
+ "runtime"
)
-// Debug prints a human-readable representation of the gob data read from r.
-func Debug(r io.Reader) { NewDecoder(r).debug() }
+var dump = false // If true, print the remaining bytes in the input buffer at each item.
-// debug is like Decode but just prints what it finds. It should be safe even for corrupted data.
-func (dec *Decoder) debug() {
- dec.state.err = nil
- for {
- // Read a count.
- var nbytes uint64
- nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
- if dec.state.err != nil {
- break
- }
+// Init installs the debugging facility. If this file is not compiled in the
+// package, the test in codec_test.go is a no-op.
+func init() {
+ debugFunc = Debug
+}
- // Allocate the buffer.
- if nbytes > uint64(len(dec.buf)) {
- dec.buf = make([]byte, nbytes+1000)
+// Debug prints a human-readable representation of the gob data read from r.
+func Debug(r io.Reader) {
+ defer func() {
+ if e := recover(); e != nil {
+ if _, ok := e.(runtime.Error); ok {
+ panic(e)
+ }
+ fmt.Printf("error during debugging: %v\n", e)
}
- dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes])
+ }()
+ NewDecoder(r).debug()
+}
- // Read the data
- _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
- if dec.state.err != nil {
- if dec.state.err == os.EOF {
- dec.state.err = io.ErrUnexpectedEOF
- }
- break
+// debugRecv is like recv but prints what it sees.
+func (dec *Decoder) debugRecv() {
+ if dec.byteBuffer != nil && dec.byteBuffer.Len() != 0 {
+ fmt.Printf("error in recv: %d bytes left in input buffer\n", dec.byteBuffer.Len())
+ return
+ }
+ // Read a count.
+ var nbytes uint64
+ nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+ if dec.err != nil {
+ fmt.Printf("receiver error on count: %s\n", dec.err)
+ return
+ }
+ // Allocate the buffer.
+ if nbytes > uint64(len(dec.buf)) {
+ dec.buf = make([]byte, nbytes+1000)
+ }
+ dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
+
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+ if dec.err != nil {
+ fmt.Printf("receiver error on data: %s\n", dec.err)
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
}
+ return
+ }
+ if dump {
+ fmt.Printf("received %d bytes:\n\t% x\n", nbytes, dec.byteBuffer.Bytes())
+ }
+}
+
+// debug is like Decode but just prints what it finds. It should be safe even for corrupted data.
+func (dec *Decoder) debug() {
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.err = nil
+ dec.debugRecv()
+ if dec.err != nil {
+ return
+ }
+ dec.debugFromBuffer(0, false)
+}
+
+// printFromBuffer prints the next value. The buffer contains data, but it may
+// be a type descriptor and we may need to load more data to see the value;
+// printType takes care of that.
+func (dec *Decoder) debugFromBuffer(indent int, countPresent bool) {
+ for dec.state.b.Len() > 0 {
// Receive a type id.
- id := typeId(decodeInt(dec.state))
- if dec.state.err != nil {
- break
- }
+ id := typeId(dec.state.decodeInt())
// Is it a new type?
if id < 0 { // 0 is the error state, handled above
// If the id is negative, we have a type.
- fmt.Printf("new type id %d\n", -id)
- dec.printType(-id)
- if dec.state.err != nil {
+ dec.debugRecvType(-id)
+ if dec.err != nil {
break
}
continue
}
- fmt.Printf("type id %d\n", id)
// No, it's a value.
- // Make sure the type has been defined already.
- _, ok := dec.wireType[id]
- if !ok {
- dec.state.err = errBadType
+ // Make sure the type has been defined already or is a builtin type (for
+ // top-level singleton values).
+ if dec.wireType[id] == nil && builtinIdToType[id] == nil {
+ dec.err = errBadType
break
}
- fmt.Printf("\t%d bytes:\t% x\n", nbytes, dec.state.b.Bytes())
- dec.printData(0, id)
+ if countPresent {
+ dec.state.decodeUint()
+ }
+ dec.debugPrint(indent, id)
break
}
- if dec.state.err != nil {
- log.Stderr("debug:", dec.state.err)
- }
}
-func (dec *Decoder) printType(id typeId) {
+func (dec *Decoder) debugRecvType(id typeId) {
// Have we already seen this type? That's an error
if _, alreadySeen := dec.wireType[id]; alreadySeen {
- dec.state.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.ErrorString("gob: duplicate type received")
return
}
// Type:
wire := new(wireType)
- dec.state.err = dec.decode(tWireType, wire)
- if dec.state.err == nil {
+ dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+ if dec.err == nil {
printWireType(wire)
}
// Remember we've seen this type.
dec.wireType[id] = wire
+
+ // Load the next parcel.
+ dec.debugRecv()
}
func printWireType(wire *wireType) {
+ fmt.Printf("type definition {\n")
switch {
- case wire.array != nil:
- printCommonType("array", &wire.array.commonType)
- fmt.Printf("\tlen %d\n\telemid %d\n", wire.array.Len, wire.array.Elem)
- case wire.slice != nil:
- printCommonType("slice", &wire.slice.commonType)
- fmt.Printf("\telemid %d\n", wire.slice.Elem)
- case wire.strct != nil:
- printCommonType("struct", &wire.strct.commonType)
- for i, field := range wire.strct.field {
- fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id)
+ case wire.ArrayT != nil:
+ printCommonType("array", &wire.ArrayT.CommonType)
+ fmt.Printf("\tlen %d\n\telemid %d\n", wire.ArrayT.Len, wire.ArrayT.Elem)
+ case wire.MapT != nil:
+ printCommonType("map", &wire.MapT.CommonType)
+ fmt.Printf("\tkeyid %d\n", wire.MapT.Key)
+ fmt.Printf("\telemid %d\n", wire.MapT.Elem)
+ case wire.SliceT != nil:
+ printCommonType("slice", &wire.SliceT.CommonType)
+ fmt.Printf("\telemid %d\n", wire.SliceT.Elem)
+ case wire.StructT != nil:
+ printCommonType("struct", &wire.StructT.CommonType)
+ for i, field := range wire.StructT.Field {
+ fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.Name, field.Id)
}
}
+ fmt.Printf("}\n")
}
-func printCommonType(kind string, common *commonType) {
- fmt.Printf("\t%s %s\n\tid: %d\n", kind, common.name, common._id)
+func printCommonType(kind string, common *CommonType) {
+ fmt.Printf("\t%s %q\n\tid: %d\n", kind, common.Name, common.Id)
}
-func (dec *Decoder) printData(indent int, id typeId) {
- if dec.state.err != nil {
- return
+func (dec *Decoder) debugPrint(indent int, id typeId) {
+ wire, ok := dec.wireType[id]
+ if ok && wire.StructT != nil {
+ dec.debugStruct(indent+1, id, wire)
+ } else {
+ dec.debugSingle(indent+1, id, wire)
}
+}
+
+func (dec *Decoder) debugSingle(indent int, id typeId, wire *wireType) {
// is it a builtin type?
_, ok := builtinIdToType[id]
+ if !ok && wire == nil {
+ errorf("type id %d not defined\n", id)
+ }
+ dec.state.decodeUint()
+ dec.printItem(indent, id)
+}
+
+func (dec *Decoder) printItem(indent int, id typeId) {
+ if dump {
+ fmt.Printf("print item %d bytes: % x\n", dec.state.b.Len(), dec.state.b.Bytes())
+ }
+ _, ok := builtinIdToType[id]
if ok {
dec.printBuiltin(indent, id)
return
}
wire, ok := dec.wireType[id]
if !ok {
- fmt.Printf("type id %d not defined\n", id)
- return
+ errorf("type id %d not defined\n", id)
}
switch {
- case wire.array != nil:
- dec.printArray(indent+1, wire)
- case wire.slice != nil:
- dec.printSlice(indent+1, wire)
- case wire.strct != nil:
- dec.printStruct(indent+1, wire)
+ case wire.ArrayT != nil:
+ dec.printArray(indent, wire)
+ case wire.MapT != nil:
+ dec.printMap(indent, wire)
+ case wire.SliceT != nil:
+ dec.printSlice(indent, wire)
+ case wire.StructT != nil:
+ dec.debugStruct(indent, id, wire)
}
}
func (dec *Decoder) printArray(indent int, wire *wireType) {
- elemId := wire.array.Elem
- n := int(decodeUint(dec.state))
- for i := 0; i < n && dec.state.err == nil; i++ {
- dec.printData(indent, elemId)
+ elemId := wire.ArrayT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, elemId)
}
- if n != wire.array.Len {
+ if n != wire.ArrayT.Len {
tab(indent)
- fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.array.Len)
+ fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.ArrayT.Len)
+ }
+}
+
+func (dec *Decoder) printMap(indent int, wire *wireType) {
+ keyId := wire.MapT.Key
+ elemId := wire.MapT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, keyId)
+ dec.printItem(indent+1, elemId)
}
}
func (dec *Decoder) printSlice(indent int, wire *wireType) {
- elemId := wire.slice.Elem
- n := int(decodeUint(dec.state))
- for i := 0; i < n && dec.state.err == nil; i++ {
- dec.printData(indent, elemId)
+ elemId := wire.SliceT.Elem
+ n := int(dec.state.decodeUint())
+ for i := 0; i < n && dec.err == nil; i++ {
+ dec.printItem(indent, elemId)
}
}
@@ -159,58 +238,73 @@ func (dec *Decoder) printBuiltin(indent int, id typeId) {
tab(indent)
switch id {
case tBool:
- if decodeInt(dec.state) == 0 {
- fmt.Printf("false")
+ if dec.state.decodeInt() == 0 {
+ fmt.Printf("false\n")
} else {
- fmt.Printf("true")
+ fmt.Printf("true\n")
}
case tInt:
- fmt.Printf("%d", decodeInt(dec.state))
+ fmt.Printf("%d\n", dec.state.decodeInt())
case tUint:
- fmt.Printf("%d", decodeUint(dec.state))
+ fmt.Printf("%d\n", dec.state.decodeUint())
case tFloat:
- fmt.Printf("%g", floatFromBits(decodeUint(dec.state)))
+ fmt.Printf("%g\n", floatFromBits(dec.state.decodeUint()))
case tBytes:
- b := make([]byte, decodeUint(dec.state))
+ b := make([]byte, dec.state.decodeUint())
dec.state.b.Read(b)
- fmt.Printf("% x", b)
+ fmt.Printf("% x\n", b)
case tString:
- b := make([]byte, decodeUint(dec.state))
+ b := make([]byte, dec.state.decodeUint())
+ dec.state.b.Read(b)
+ fmt.Printf("%q\n", b)
+ case tInterface:
+ b := make([]byte, dec.state.decodeUint())
dec.state.b.Read(b)
- fmt.Printf("%q", b)
+ if len(b) == 0 {
+ fmt.Printf("nil interface")
+ } else {
+ fmt.Printf("interface value; type %q\n", b)
+ dec.debugFromBuffer(indent, true)
+ }
default:
- fmt.Print("unknown")
+ fmt.Print("unknown\n")
}
- fmt.Print("\n")
}
-func (dec *Decoder) printStruct(indent int, wire *wireType) {
- strct := wire.strct
- state := newDecodeState(dec.state.b)
+func (dec *Decoder) debugStruct(indent int, id typeId, wire *wireType) {
+ tab(indent)
+ fmt.Printf("%s struct {\n", id.name())
+ strct := wire.StructT
+ state := newDecodeState(dec, dec.state.b)
state.fieldnum = -1
- for state.err == nil {
- delta := int(decodeUint(state))
+ for dec.err == nil {
+ delta := int(state.decodeUint())
if delta < 0 {
- dec.state.err = os.ErrorString("gob decode: corrupted data: negative delta")
- return
+ errorf("gob decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
- return
+ if delta == 0 { // struct terminator is zero delta fieldnum
+ break
}
- fieldnum := state.fieldnum + delta
- if fieldnum < 0 || fieldnum >= len(strct.field) {
- dec.state.err = os.ErrorString("field number out of range")
- return
+ fieldNum := state.fieldnum + delta
+ if fieldNum < 0 || fieldNum >= len(strct.Field) {
+ errorf("field number out of range")
+ break
}
tab(indent)
- fmt.Printf("field %d:\n", fieldnum)
- dec.printData(indent+1, strct.field[fieldnum].id)
- state.fieldnum = fieldnum
+ fmt.Printf("%s(%d):\n", wire.StructT.Field[fieldNum].Name, fieldNum)
+ dec.printItem(indent+1, strct.Field[fieldNum].Id)
+ state.fieldnum = fieldNum
}
+ tab(indent)
+ fmt.Printf(" } // end %s struct\n", id.name())
}
func tab(indent int) {
- for i := 0; i < indent; i++ {
- fmt.Print("\t")
+ for i, w := 0, 0; i < indent; i += w {
+ w = 10
+ if i+w > indent {
+ w = indent - i
+ }
+ fmt.Print("\t\t\t\t\t\t\t\t\t\t"[:w])
}
}
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index a70799e9a..f88ca72da 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -13,7 +13,9 @@ import (
"math"
"os"
"reflect"
+ "unicode"
"unsafe"
+ "utf8"
)
var (
@@ -22,16 +24,20 @@ var (
errRange = os.ErrorString("gob: internal error: field numbers out of bounds")
)
-// The global execution state of an instance of the decoder.
+// The execution state of an instance of the decoder. A new state
+// is created for nested objects.
type decodeState struct {
- b *bytes.Buffer
- err os.Error
+ dec *Decoder
+ // The buffer is stored with an extra indirection because it may be replaced
+ // if we load a type during decode (when reading an interface value).
+ b **bytes.Buffer
fieldnum int // the last field number read.
buf []byte
}
-func newDecodeState(b *bytes.Buffer) *decodeState {
+func newDecodeState(dec *Decoder, b **bytes.Buffer) *decodeState {
d := new(decodeState)
+ d.dec = dec
d.b = b
d.buf = make([]byte, uint64Size)
return d
@@ -74,24 +80,23 @@ func decodeUintReader(r io.Reader, buf []byte) (x uint64, err os.Error) {
}
// decodeUint reads an encoded unsigned integer from state.r.
-// Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
-func decodeUint(state *decodeState) (x uint64) {
- if state.err != nil {
- return
+func (state *decodeState) decodeUint() (x uint64) {
+ b, err := state.b.ReadByte()
+ if err != nil {
+ error(err)
}
- var b uint8
- b, state.err = state.b.ReadByte()
- if b <= 0x7f { // includes state.err != nil
+ if b <= 0x7f {
return uint64(b)
}
nb := -int(int8(b))
if nb > uint64Size {
- state.err = errBadUint
- return
+ error(errBadUint)
+ }
+ n, err := state.b.Read(state.buf[0:nb])
+ if err != nil {
+ error(err)
}
- var n int
- n, state.err = state.b.Read(state.buf[0:nb])
// Don't need to check error; it's safe to loop regardless.
// Could check that the high byte is zero but it's not worth it.
for i := 0; i < n; i++ {
@@ -102,13 +107,9 @@ func decodeUint(state *decodeState) (x uint64) {
}
// decodeInt reads an encoded signed integer from state.r.
-// Sets state.err. If state.err is already non-nil, it does nothing.
// Does not check for overflow.
-func decodeInt(state *decodeState) int64 {
- x := decodeUint(state)
- if state.err != nil {
- return 0
- }
+func (state *decodeState) decodeInt() int64 {
+ x := state.decodeUint()
if x&1 != 0 {
return ^int64(x >> 1)
}
@@ -146,12 +147,12 @@ func decIndirect(p unsafe.Pointer, indir int) unsafe.Pointer {
}
func ignoreUint(i *decInstr, state *decodeState, p unsafe.Pointer) {
- decodeUint(state)
+ state.decodeUint()
}
func ignoreTwoUints(i *decInstr, state *decodeState, p unsafe.Pointer) {
- decodeUint(state)
- decodeUint(state)
+ state.decodeUint()
+ state.decodeUint()
}
func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -161,7 +162,7 @@ func decBool(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*bool)(p) = decodeInt(state) != 0
+ *(*bool)(p) = state.decodeInt() != 0
}
func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -171,9 +172,9 @@ func decInt8(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt8 || math.MaxInt8 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int8)(p) = int8(v)
}
@@ -186,9 +187,9 @@ func decUint8(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint8 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint8)(p) = uint8(v)
}
@@ -201,9 +202,9 @@ func decInt16(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt16 || math.MaxInt16 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int16)(p) = int16(v)
}
@@ -216,9 +217,9 @@ func decUint16(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint16 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint16)(p) = uint16(v)
}
@@ -231,9 +232,9 @@ func decInt32(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeInt(state)
+ v := state.decodeInt()
if v < math.MinInt32 || math.MaxInt32 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*int32)(p) = int32(v)
}
@@ -246,9 +247,9 @@ func decUint32(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- v := decodeUint(state)
+ v := state.decodeUint()
if math.MaxUint32 < v {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*uint32)(p) = uint32(v)
}
@@ -261,7 +262,7 @@ func decInt64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*int64)(p) = int64(decodeInt(state))
+ *(*int64)(p) = int64(state.decodeInt())
}
func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
@@ -271,7 +272,7 @@ func decUint64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*uint64)(p) = uint64(decodeUint(state))
+ *(*uint64)(p) = uint64(state.decodeUint())
}
// Floating-point numbers are transmitted as uint64s holding the bits
@@ -290,14 +291,14 @@ func floatFromBits(u uint64) float64 {
}
func storeFloat32(i *decInstr, state *decodeState, p unsafe.Pointer) {
- v := floatFromBits(decodeUint(state))
+ v := floatFromBits(state.decodeUint())
av := v
if av < 0 {
av = -av
}
// +Inf is OK in both 32- and 64-bit floats. Underflow is always OK.
if math.MaxFloat32 < av && av <= math.MaxFloat64 {
- state.err = i.ovfl
+ error(i.ovfl)
} else {
*(*float32)(p) = float32(v)
}
@@ -320,7 +321,7 @@ func decFloat64(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- *(*float64)(p) = floatFromBits(uint64(decodeUint(state)))
+ *(*float64)(p) = floatFromBits(uint64(state.decodeUint()))
}
// Complex numbers are just a pair of floating-point numbers, real part first.
@@ -342,8 +343,8 @@ func decComplex128(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- real := floatFromBits(uint64(decodeUint(state)))
- imag := floatFromBits(uint64(decodeUint(state)))
+ real := floatFromBits(uint64(state.decodeUint()))
+ imag := floatFromBits(uint64(state.decodeUint()))
*(*complex128)(p) = cmplx(real, imag)
}
@@ -355,7 +356,7 @@ func decUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]uint8, decodeUint(state))
+ b := make([]uint8, state.decodeUint())
state.b.Read(b)
*(*[]uint8)(p) = b
}
@@ -368,13 +369,13 @@ func decString(i *decInstr, state *decodeState, p unsafe.Pointer) {
}
p = *(*unsafe.Pointer)(p)
}
- b := make([]byte, decodeUint(state))
+ b := make([]byte, state.decodeUint())
state.b.Read(b)
*(*string)(p) = string(b)
}
func ignoreUint8Array(i *decInstr, state *decodeState, p unsafe.Pointer) {
- b := make([]byte, decodeUint(state))
+ b := make([]byte, state.decodeUint())
state.b.Read(b)
}
@@ -404,15 +405,15 @@ func allocate(rtyp reflect.Type, p uintptr, indir int) uintptr {
return *(*uintptr)(up)
}
-func decodeSingle(engine *decEngine, rtyp reflect.Type, b *bytes.Buffer, p uintptr, indir int) os.Error {
+func (dec *Decoder) decodeSingle(engine *decEngine, rtyp reflect.Type, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
p = allocate(rtyp, p, indir)
- state := newDecodeState(b)
+ state := newDecodeState(dec, b)
state.fieldnum = singletonField
basep := p
- delta := int(decodeUint(state))
+ delta := int(state.decodeUint())
if delta != 0 {
- state.err = os.ErrorString("gob decode: corrupted data: non-zero delta for singleton")
- return state.err
+ errorf("gob decode: corrupted data: non-zero delta for singleton")
}
instr := &engine.instr[singletonField]
ptr := unsafe.Pointer(basep) // offset will be zero
@@ -420,26 +421,26 @@ func decodeSingle(engine *decEngine, rtyp reflect.Type, b *bytes.Buffer, p uintp
ptr = decIndirect(ptr, instr.indir)
}
instr.op(instr, state, ptr)
- return state.err
+ return nil
}
-func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer, p uintptr, indir int) os.Error {
+func (dec *Decoder) decodeStruct(engine *decEngine, rtyp *reflect.StructType, b **bytes.Buffer, p uintptr, indir int) (err os.Error) {
+ defer catchError(&err)
p = allocate(rtyp, p, indir)
- state := newDecodeState(b)
+ state := newDecodeState(dec, b)
state.fieldnum = -1
basep := p
- for state.err == nil {
- delta := int(decodeUint(state))
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
if delta < 0 {
- state.err = os.ErrorString("gob decode: corrupted data: negative delta")
- break
+ errorf("gob decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
+ if delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- state.err = errRange
+ error(errRange)
break
}
instr := &engine.instr[fieldnum]
@@ -450,36 +451,35 @@ func decodeStruct(engine *decEngine, rtyp *reflect.StructType, b *bytes.Buffer,
instr.op(instr, state, p)
state.fieldnum = fieldnum
}
- return state.err
+ return nil
}
-func ignoreStruct(engine *decEngine, b *bytes.Buffer) os.Error {
- state := newDecodeState(b)
+func (dec *Decoder) ignoreStruct(engine *decEngine, b **bytes.Buffer) (err os.Error) {
+ defer catchError(&err)
+ state := newDecodeState(dec, b)
state.fieldnum = -1
- for state.err == nil {
- delta := int(decodeUint(state))
+ for state.b.Len() > 0 {
+ delta := int(state.decodeUint())
if delta < 0 {
- state.err = os.ErrorString("gob ignore decode: corrupted data: negative delta")
- break
+ errorf("gob ignore decode: corrupted data: negative delta")
}
- if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
+ if delta == 0 { // struct terminator is zero delta fieldnum
break
}
fieldnum := state.fieldnum + delta
if fieldnum >= len(engine.instr) {
- state.err = errRange
- break
+ error(errRange)
}
instr := &engine.instr[fieldnum]
instr.op(instr, state, unsafe.Pointer(nil))
state.fieldnum = fieldnum
}
- return state.err
+ return nil
}
-func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, elemIndir int, ovfl os.ErrorString) {
instr := &decInstr{elemOp, 0, elemIndir, 0, ovfl}
- for i := 0; i < length && state.err == nil; i++ {
+ for i := 0; i < length; i++ {
up := unsafe.Pointer(p)
if elemIndir > 1 {
up = decIndirect(up, elemIndir)
@@ -487,17 +487,16 @@ func decodeArrayHelper(state *decodeState, p uintptr, elemOp decOp, elemWid uint
elemOp(instr, state, up)
p += uintptr(elemWid)
}
- return state.err
}
-func decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeArray(atyp *reflect.ArrayType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, length, indir, elemIndir int, ovfl os.ErrorString) {
if indir > 0 {
p = allocate(atyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
- if n := decodeUint(state); n != uint64(length) {
- return os.ErrorString("gob: length mismatch in decodeArray")
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in decodeArray")
}
- return decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, p, elemOp, elemWid, length, elemIndir, ovfl)
}
func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, ovfl os.ErrorString) reflect.Value {
@@ -510,7 +509,7 @@ func decodeIntoValue(state *decodeState, op decOp, indir int, v reflect.Value, o
return v
}
-func decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) os.Error {
+func (dec *Decoder) decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elemOp decOp, indir, keyIndir, elemIndir int, ovfl os.ErrorString) {
if indir > 0 {
p = allocate(mtyp, p, 1) // All but the last level has been allocated by dec.Indirect
}
@@ -523,50 +522,40 @@ func decodeMap(mtyp *reflect.MapType, state *decodeState, p uintptr, keyOp, elem
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewValue(unsafe.Unreflect(mtyp, unsafe.Pointer((p)))).(*reflect.MapValue)
- n := int(decodeUint(state))
- for i := 0; i < n && state.err == nil; i++ {
+ n := int(state.decodeUint())
+ for i := 0; i < n; i++ {
key := decodeIntoValue(state, keyOp, keyIndir, reflect.MakeZero(mtyp.Key()), ovfl)
- if state.err != nil {
- break
- }
elem := decodeIntoValue(state, elemOp, elemIndir, reflect.MakeZero(mtyp.Elem()), ovfl)
- if state.err != nil {
- break
- }
v.SetElem(key, elem)
}
- return state.err
}
-func ignoreArrayHelper(state *decodeState, elemOp decOp, length int) os.Error {
+func (dec *Decoder) ignoreArrayHelper(state *decodeState, elemOp decOp, length int) {
instr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
- for i := 0; i < length && state.err == nil; i++ {
+ for i := 0; i < length; i++ {
elemOp(instr, state, nil)
}
- return state.err
}
-func ignoreArray(state *decodeState, elemOp decOp, length int) os.Error {
- if n := decodeUint(state); n != uint64(length) {
- return os.ErrorString("gob: length mismatch in ignoreArray")
+func (dec *Decoder) ignoreArray(state *decodeState, elemOp decOp, length int) {
+ if n := state.decodeUint(); n != uint64(length) {
+ errorf("gob: length mismatch in ignoreArray")
}
- return ignoreArrayHelper(state, elemOp, length)
+ dec.ignoreArrayHelper(state, elemOp, length)
}
-func ignoreMap(state *decodeState, keyOp, elemOp decOp) os.Error {
- n := int(decodeUint(state))
+func (dec *Decoder) ignoreMap(state *decodeState, keyOp, elemOp decOp) {
+ n := int(state.decodeUint())
keyInstr := &decInstr{keyOp, 0, 0, 0, os.ErrorString("no error")}
elemInstr := &decInstr{elemOp, 0, 0, 0, os.ErrorString("no error")}
- for i := 0; i < n && state.err == nil; i++ {
+ for i := 0; i < n; i++ {
keyOp(keyInstr, state, nil)
elemOp(elemInstr, state, nil)
}
- return state.err
}
-
-func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) os.Error {
- n := int(uintptr(decodeUint(state)))
+func (dec *Decoder) decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp decOp, elemWid uintptr, indir, elemIndir int, ovfl os.ErrorString) {
+ n := int(uintptr(state.decodeUint()))
if indir > 0 {
up := unsafe.Pointer(p)
if *(*unsafe.Pointer)(up) == nil {
@@ -581,11 +570,77 @@ func decodeSlice(atyp *reflect.SliceType, state *decodeState, p uintptr, elemOp
hdrp.Data = uintptr(unsafe.NewArray(atyp.Elem(), n))
hdrp.Len = n
hdrp.Cap = n
- return decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
+ dec.decodeArrayHelper(state, hdrp.Data, elemOp, elemWid, n, elemIndir, ovfl)
}
-func ignoreSlice(state *decodeState, elemOp decOp) os.Error {
- return ignoreArrayHelper(state, elemOp, int(decodeUint(state)))
+func (dec *Decoder) ignoreSlice(state *decodeState, elemOp decOp) {
+ dec.ignoreArrayHelper(state, elemOp, int(state.decodeUint()))
+}
+
+// setInterfaceValue sets an interface value to a concrete value through
+// reflection. If the concrete value does not implement the interface, the
+// setting will panic. This routine turns the panic into an error return.
+// This dance avoids manually checking that the value satisfies the
+// interface.
+// TODO(rsc): avoid panic+recover after fixing issue 327.
+func setInterfaceValue(ivalue *reflect.InterfaceValue, value reflect.Value) {
+ defer func() {
+ if e := recover(); e != nil {
+ error(e.(os.Error))
+ }
+ }()
+ ivalue.Set(value)
+}
+
+// decodeInterface receives the name of a concrete type followed by its value.
+// If the name is empty, the value is nil and no value is sent.
+func (dec *Decoder) decodeInterface(ityp *reflect.InterfaceType, state *decodeState, p uintptr, indir int) {
+ // Create an interface reflect.Value. We need one even for the nil case.
+ ivalue := reflect.MakeZero(ityp).(*reflect.InterfaceValue)
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ state.b.Read(b)
+ name := string(b)
+ if name == "" {
+ // Copy the representation of the nil interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+ return
+ }
+ // The concrete type must be registered.
+ typ, ok := nameToConcreteType[name]
+ if !ok {
+ errorf("gob: name not registered for interface: %q", name)
+ }
+ // Read the concrete value.
+ value := reflect.MakeZero(typ)
+ dec.decodeValueFromBuffer(value, false, true)
+ if dec.err != nil {
+ error(dec.err)
+ }
+ // Allocate the destination interface value.
+ if indir > 0 {
+ p = allocate(ityp, p, 1) // All but the last level has been allocated by dec.Indirect
+ }
+ // Assign the concrete value to the interface.
+ // Tread carefully; it might not satisfy the interface.
+ setInterfaceValue(ivalue, value)
+ // Copy the representation of the interface value to the target.
+ // This is horribly unsafe and special.
+ *(*[2]uintptr)(unsafe.Pointer(p)) = ivalue.Get()
+}
+
+func (dec *Decoder) ignoreInterface(state *decodeState) {
+ // Read the name of the concrete type.
+ b := make([]byte, state.decodeUint())
+ _, err := state.b.Read(b)
+ if err != nil {
+ error(err)
+ }
+ dec.decodeValueFromBuffer(nil, true, true)
+ if dec.err != nil {
+ error(err)
+ }
}
// Index by Go types.
@@ -608,17 +663,18 @@ var decOpMap = []decOp{
// Indexed by gob types. tComplex will be added during type.init().
var decIgnoreOpMap = map[typeId]decOp{
- tBool: ignoreUint,
- tInt: ignoreUint,
- tUint: ignoreUint,
- tFloat: ignoreUint,
- tBytes: ignoreUint8Array,
- tString: ignoreUint8Array,
+ tBool: ignoreUint,
+ tInt: ignoreUint,
+ tUint: ignoreUint,
+ tFloat: ignoreUint,
+ tBytes: ignoreUint8Array,
+ tString: ignoreUint8Array,
+ tComplex: ignoreTwoUints,
}
// Return the decoding op for the base type under rt and
// the indirection count to reach it.
-func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int, os.Error) {
+func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp, int) {
typ, indir := indirect(rt)
var op decOp
k := typ.Kind()
@@ -630,32 +686,23 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
switch t := typ.(type) {
case *reflect.ArrayType:
name = "element of " + name
- elemId := dec.wireType[wireId].arrayT.Elem
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
- }
+ elemId := dec.wireType[wireId].ArrayT.Elem
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
+ state.dec.decodeArray(t, state, uintptr(p), elemOp, t.Elem().Size(), t.Len(), i.indir, elemIndir, ovfl)
}
case *reflect.MapType:
name = "element of " + name
- keyId := dec.wireType[wireId].mapT.Key
- elemId := dec.wireType[wireId].mapT.Elem
- keyOp, keyIndir, err := dec.decOpFor(keyId, t.Key(), name)
- if err != nil {
- return nil, 0, err
- }
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
- }
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp, keyIndir := dec.decOpFor(keyId, t.Key(), name)
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
up := unsafe.Pointer(p)
- state.err = decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
+ state.dec.decodeMap(t, state, uintptr(up), keyOp, elemOp, i.indir, keyIndir, elemIndir, ovfl)
}
case *reflect.SliceType:
@@ -668,111 +715,105 @@ func (dec *Decoder) decOpFor(wireId typeId, rt reflect.Type, name string) (decOp
if tt, ok := builtinIdToType[wireId]; ok {
elemId = tt.(*sliceType).Elem
} else {
- elemId = dec.wireType[wireId].sliceT.Elem
- }
- elemOp, elemIndir, err := dec.decOpFor(elemId, t.Elem(), name)
- if err != nil {
- return nil, 0, err
+ elemId = dec.wireType[wireId].SliceT.Elem
}
+ elemOp, elemIndir := dec.decOpFor(elemId, t.Elem(), name)
ovfl := overflow(name)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
+ state.dec.decodeSlice(t, state, uintptr(p), elemOp, t.Elem().Size(), i.indir, elemIndir, ovfl)
}
case *reflect.StructType:
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getDecEnginePtr(wireId, typ)
if err != nil {
- return nil, 0, err
+ error(err)
}
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
- state.err = decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+ err = dec.decodeStruct(*enginePtr, t, state.b, uintptr(p), i.indir)
+ if err != nil {
+ error(err)
+ }
+ }
+ case *reflect.InterfaceType:
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.decodeInterface(t, state, uintptr(p), i.indir)
}
}
}
if op == nil {
- return nil, 0, os.ErrorString("gob: decode can't handle type " + rt.String())
+ errorf("gob: decode can't handle type %s", rt.String())
}
- return op, indir, nil
+ return op, indir
}
// Return the decoding op for a field that has no destination.
-func (dec *Decoder) decIgnoreOpFor(wireId typeId) (decOp, os.Error) {
+func (dec *Decoder) decIgnoreOpFor(wireId typeId) decOp {
op, ok := decIgnoreOpMap[wireId]
if !ok {
+ if wireId == tInterface {
+ // Special case because it's a method: the ignored item might
+ // define types and we need to record their state in the decoder.
+ op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
+ dec.ignoreInterface(state)
+ }
+ return op
+ }
// Special cases
wire := dec.wireType[wireId]
switch {
case wire == nil:
panic("internal error: can't find ignore op for type " + wireId.string())
- case wire.arrayT != nil:
- elemId := wire.arrayT.Elem
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.ArrayT != nil:
+ elemId := wire.ArrayT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreArray(state, elemOp, wire.arrayT.Len)
+ state.dec.ignoreArray(state, elemOp, wire.ArrayT.Len)
}
- case wire.mapT != nil:
- keyId := dec.wireType[wireId].mapT.Key
- elemId := dec.wireType[wireId].mapT.Elem
- keyOp, err := dec.decIgnoreOpFor(keyId)
- if err != nil {
- return nil, err
- }
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.MapT != nil:
+ keyId := dec.wireType[wireId].MapT.Key
+ elemId := dec.wireType[wireId].MapT.Elem
+ keyOp := dec.decIgnoreOpFor(keyId)
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreMap(state, keyOp, elemOp)
+ state.dec.ignoreMap(state, keyOp, elemOp)
}
- case wire.sliceT != nil:
- elemId := wire.sliceT.Elem
- elemOp, err := dec.decIgnoreOpFor(elemId)
- if err != nil {
- return nil, err
- }
+ case wire.SliceT != nil:
+ elemId := wire.SliceT.Elem
+ elemOp := dec.decIgnoreOpFor(elemId)
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
- state.err = ignoreSlice(state, elemOp)
+ state.dec.ignoreSlice(state, elemOp)
}
- case wire.structT != nil:
+ case wire.StructT != nil:
// Generate a closure that calls out to the engine for the nested type.
enginePtr, err := dec.getIgnoreEnginePtr(wireId)
if err != nil {
- return nil, err
+ error(err)
}
op = func(i *decInstr, state *decodeState, p unsafe.Pointer) {
// indirect through enginePtr to delay evaluation for recursive structs
- state.err = ignoreStruct(*enginePtr, state.b)
+ state.dec.ignoreStruct(*enginePtr, state.b)
}
}
}
if op == nil {
- return nil, os.ErrorString("ignore can't handle type " + wireId.string())
+ errorf("ignore can't handle type %s", wireId.string())
}
- return op, nil
+ return op
}
// Are these two gob Types compatible?
// Answers the question for basic types, arrays, and slices.
// Structs are considered ok; fields will be checked later.
func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
- for {
- if pt, ok := fr.(*reflect.PtrType); ok {
- fr = pt.Elem()
- continue
- }
- break
- }
+ fr, _ = indirect(fr)
switch t := fr.(type) {
default:
- // interface, map, chan, etc: cannot handle.
+ // map, chan, etc: cannot handle.
return false
case *reflect.BoolType:
return fw == tBool
@@ -786,20 +827,22 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
return fw == tComplex
case *reflect.StringType:
return fw == tString
+ case *reflect.InterfaceType:
+ return fw == tInterface
case *reflect.ArrayType:
wire, ok := dec.wireType[fw]
- if !ok || wire.arrayT == nil {
+ if !ok || wire.ArrayT == nil {
return false
}
- array := wire.arrayT
+ array := wire.ArrayT
return t.Len() == array.Len && dec.compatibleType(t.Elem(), array.Elem)
case *reflect.MapType:
wire, ok := dec.wireType[fw]
- if !ok || wire.mapT == nil {
+ if !ok || wire.MapT == nil {
return false
}
- mapType := wire.mapT
- return dec.compatibleType(t.Key(), mapType.Key) && dec.compatibleType(t.Elem(), mapType.Elem)
+ MapType := wire.MapT
+ return dec.compatibleType(t.Key(), MapType.Key) && dec.compatibleType(t.Elem(), MapType.Elem)
case *reflect.SliceType:
// Is it an array of bytes?
if t.Elem().Kind() == reflect.Uint8 {
@@ -810,7 +853,7 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
if tt, ok := builtinIdToType[fw]; ok {
sw = tt.(*sliceType)
} else {
- sw = dec.wireType[fw].sliceT
+ sw = dec.wireType[fw].SliceT
}
elem, _ := indirect(t.Elem())
return sw != nil && dec.compatibleType(elem, sw.Elem)
@@ -820,61 +863,74 @@ func (dec *Decoder) compatibleType(fr reflect.Type, fw typeId) bool {
return true
}
+// typeString returns a human-readable description of the type identified by remoteId.
+func (dec *Decoder) typeString(remoteId typeId) string {
+ if t := idToType[remoteId]; t != nil {
+ // globally known type.
+ return t.string()
+ }
+ return dec.wireType[remoteId].string()
+}
+
+
func (dec *Decoder) compileSingle(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
engine = new(decEngine)
engine.instr = make([]decInstr, 1) // one item
name := rt.String() // best we can do
if !dec.compatibleType(rt, remoteId) {
- return nil, os.ErrorString("gob: wrong type received for local value " + name)
- }
- op, indir, err := dec.decOpFor(remoteId, rt, name)
- if err != nil {
- return nil, err
+ return nil, os.ErrorString("gob: wrong type received for local value " + name + ": " + dec.typeString(remoteId))
}
+ op, indir := dec.decOpFor(remoteId, rt, name)
ovfl := os.ErrorString(`value for "` + name + `" out of range`)
engine.instr[singletonField] = decInstr{op, singletonField, indir, 0, ovfl}
engine.numInstr = 1
return
}
+// Is this an exported - upper case - name?
+func isExported(name string) bool {
+ rune, _ := utf8.DecodeRuneInString(name)
+ return unicode.IsUpper(rune)
+}
+
func (dec *Decoder) compileDec(remoteId typeId, rt reflect.Type) (engine *decEngine, err os.Error) {
+ defer catchError(&err)
srt, ok := rt.(*reflect.StructType)
if !ok {
return dec.compileSingle(remoteId, rt)
}
var wireStruct *structType
- // Builtin types can come from global pool; the rest must be defined by the decoder
+ // Builtin types can come from global pool; the rest must be defined by the decoder.
+ // Also we know we're decoding a struct now, so the client must have sent one.
if t, ok := builtinIdToType[remoteId]; ok {
- wireStruct = t.(*structType)
+ wireStruct, _ = t.(*structType)
} else {
- wireStruct = dec.wireType[remoteId].structT
+ wireStruct = dec.wireType[remoteId].StructT
+ }
+ if wireStruct == nil {
+ errorf("gob: type mismatch in decoder: want struct type %s; got non-struct", rt.String())
}
engine = new(decEngine)
- engine.instr = make([]decInstr, len(wireStruct.field))
+ engine.instr = make([]decInstr, len(wireStruct.Field))
// Loop over the fields of the wire type.
- for fieldnum := 0; fieldnum < len(wireStruct.field); fieldnum++ {
- wireField := wireStruct.field[fieldnum]
+ for fieldnum := 0; fieldnum < len(wireStruct.Field); fieldnum++ {
+ wireField := wireStruct.Field[fieldnum]
+ if wireField.Name == "" {
+ errorf("gob: empty name for remote field of type %s", wireStruct.Name)
+ }
+ ovfl := overflow(wireField.Name)
// Find the field of the local type with the same name.
- localField, present := srt.FieldByName(wireField.name)
- ovfl := overflow(wireField.name)
+ localField, present := srt.FieldByName(wireField.Name)
// TODO(r): anonymous names
- if !present {
- op, err := dec.decIgnoreOpFor(wireField.id)
- if err != nil {
- return nil, err
- }
+ if !present || !isExported(wireField.Name) {
+ op := dec.decIgnoreOpFor(wireField.Id)
engine.instr[fieldnum] = decInstr{op, fieldnum, 0, 0, ovfl}
continue
}
- if !dec.compatibleType(localField.Type, wireField.id) {
- return nil, os.ErrorString("gob: wrong type (" +
- localField.Type.String() + ") for received field " +
- wireStruct.name + "." + wireField.name)
- }
- op, indir, err := dec.decOpFor(wireField.id, localField.Type, localField.Name)
- if err != nil {
- return nil, err
+ if !dec.compatibleType(localField.Type, wireField.Id) {
+ errorf("gob: wrong type (%s) for received field %s.%s", localField.Type, wireStruct.Name, wireField.Name)
}
+ op, indir := dec.decOpFor(wireField.Id, localField.Type, localField.Name)
engine.instr[fieldnum] = decInstr{op, fieldnum, indir, uintptr(localField.Offset), ovfl}
engine.numInstr++
}
@@ -899,7 +955,7 @@ func (dec *Decoder) getDecEnginePtr(remoteId typeId, rt reflect.Type) (enginePtr
return
}
-// When ignoring data, in effect we compile it into this type
+// When ignoring struct data, in effect we compile it into this type
type emptyStruct struct{}
var emptyStructType = reflect.Typeof(emptyStruct{})
@@ -927,13 +983,13 @@ func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error {
}
engine := *enginePtr
if st, ok := rt.(*reflect.StructType); ok {
- if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].structT.field) > 0 {
+ if engine.numInstr == 0 && st.NumField() > 0 && len(dec.wireType[wireId].StructT.Field) > 0 {
name := rt.Name()
return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name)
}
- return decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
+ return dec.decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir)
}
- return decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
+ return dec.decodeSingle(engine, rt, dec.state.b, uintptr(val.Addr()), indir)
}
func init() {
diff --git a/src/pkg/gob/decoder.go b/src/pkg/gob/decoder.go
index cf16433eb..664001a4b 100644
--- a/src/pkg/gob/decoder.go
+++ b/src/pkg/gob/decoder.go
@@ -24,6 +24,8 @@ type Decoder struct {
countState *decodeState // reads counts from wire
buf []byte
countBuf [9]byte // counts may be uint64s (unlikely!), require 9 bytes
+ byteBuffer *bytes.Buffer
+ err os.Error
}
// NewDecoder returns a new decoder that reads from the io.Reader.
@@ -31,25 +33,32 @@ func NewDecoder(r io.Reader) *Decoder {
dec := new(Decoder)
dec.r = r
dec.wireType = make(map[typeId]*wireType)
- dec.state = newDecodeState(nil) // buffer set in Decode(); rest is unimportant
+ dec.state = newDecodeState(dec, &dec.byteBuffer) // buffer set in Decode()
dec.decoderCache = make(map[reflect.Type]map[typeId]**decEngine)
dec.ignorerCache = make(map[typeId]**decEngine)
return dec
}
+// recvType loads the definition of a type and reloads the Decoder's buffer.
func (dec *Decoder) recvType(id typeId) {
// Have we already seen this type? That's an error
if dec.wireType[id] != nil {
- dec.state.err = os.ErrorString("gob: duplicate type received")
+ dec.err = os.ErrorString("gob: duplicate type received")
return
}
// Type:
wire := new(wireType)
- dec.state.err = dec.decode(tWireType, reflect.NewValue(wire))
+ dec.err = dec.decode(tWireType, reflect.NewValue(wire))
+ if dec.err != nil {
+ return
+ }
// Remember we've seen this type.
dec.wireType[id] = wire
+
+ // Load the next parcel.
+ dec.recv()
}
// Decode reads the next value from the connection and stores
@@ -61,69 +70,95 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// If e represents a value as opposed to a pointer, the answer won't
// get back to the caller. Make sure it's a pointer.
if value.Type().Kind() != reflect.Ptr {
- dec.state.err = os.ErrorString("gob: attempt to decode into a non-pointer")
- return dec.state.err
+ dec.err = os.ErrorString("gob: attempt to decode into a non-pointer")
+ return dec.err
}
return dec.DecodeValue(value)
}
-// DecodeValue reads the next value from the connection and stores
-// it in the data represented by the reflection value.
-// The value must be the correct type for the next
-// data item received.
-func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here.
- dec.mutex.Lock()
- defer dec.mutex.Unlock()
-
- dec.state.err = nil
- for {
- // Read a count.
- var nbytes uint64
- nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
- if dec.state.err != nil {
- break
- }
- // Allocate the buffer.
- if nbytes > uint64(len(dec.buf)) {
- dec.buf = make([]byte, nbytes+1000)
- }
- dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes])
+// recv reads the next count-delimited item from the input. It is the converse
+// of Encoder.send.
+func (dec *Decoder) recv() {
+ // Read a count.
+ var nbytes uint64
+ nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
+ if dec.err != nil {
+ return
+ }
+ // Allocate the buffer.
+ if nbytes > uint64(len(dec.buf)) {
+ dec.buf = make([]byte, nbytes+1000)
+ }
+ dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
- // Read the data
- _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
- if dec.state.err != nil {
- if dec.state.err == os.EOF {
- dec.state.err = io.ErrUnexpectedEOF
- }
- break
+ // Read the data
+ _, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+ if dec.err != nil {
+ if dec.err == os.EOF {
+ dec.err = io.ErrUnexpectedEOF
}
+ return
+ }
+}
+// decodeValueFromBuffer grabs the next value from the input. The Decoder's
+// buffer already contains data. If the next item in the buffer is a type
+// descriptor, it may be necessary to reload the buffer, but recvType does that.
+func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignoreInterfaceValue, countPresent bool) {
+ for dec.state.b.Len() > 0 {
// Receive a type id.
- id := typeId(decodeInt(dec.state))
- if dec.state.err != nil {
- break
- }
+ id := typeId(dec.state.decodeInt())
// Is it a new type?
if id < 0 { // 0 is the error state, handled above
// If the id is negative, we have a type.
dec.recvType(-id)
- if dec.state.err != nil {
+ if dec.err != nil {
break
}
continue
}
- // No, it's a value.
// Make sure the type has been defined already or is a builtin type (for
// top-level singleton values).
if dec.wireType[id] == nil && builtinIdToType[id] == nil {
- dec.state.err = errBadType
+ dec.err = errBadType
break
}
- dec.state.err = dec.decode(id, value)
+ // An interface value is preceded by a byte count.
+ if countPresent {
+ count := int(dec.state.decodeUint())
+ if ignoreInterfaceValue {
+ // An interface value is preceded by a byte count. Just skip that many bytes.
+ dec.state.b.Next(int(count))
+ break
+ }
+ // Otherwise fall through and decode it.
+ }
+ dec.err = dec.decode(id, value)
break
}
- return dec.state.err
}
+
+// DecodeValue reads the next value from the connection and stores
+// it in the data represented by the reflection value.
+// The value must be the correct type for the next
+// data item received.
+func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here.
+ dec.mutex.Lock()
+ defer dec.mutex.Unlock()
+
+ dec.err = nil
+ dec.recv()
+ if dec.err != nil {
+ return dec.err
+ }
+ dec.decodeValueFromBuffer(value, false, false)
+ return dec.err
+}
+
+// If debug.go is compiled into the program , debugFunc prints a human-readable
+// representation of the gob data read from r by calling that file's Debug function.
+// Otherwise it is nil.
+var debugFunc func(io.Reader)
diff --git a/src/pkg/gob/doc.go b/src/pkg/gob/doc.go
new file mode 100644
index 000000000..31253f16d
--- /dev/null
+++ b/src/pkg/gob/doc.go
@@ -0,0 +1,307 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+The gob package manages streams of gobs - binary values exchanged between an
+Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
+arguments and results of remote procedure calls (RPCs) such as those provided by
+package "rpc".
+
+A stream of gobs is self-describing. Each data item in the stream is preceded by
+a specification of its type, expressed in terms of a small set of predefined
+types. Pointers are not transmitted, but the things they point to are
+transmitted; that is, the values are flattened. Recursive types work fine, but
+recursive values (data with cycles) are problematic. This may change.
+
+To use gobs, create an Encoder and present it with a series of data items as
+values or addresses that can be dereferenced to values. The Encoder makes sure
+all type information is sent before it is needed. At the receive side, a
+Decoder retrieves values from the encoded stream and unpacks them into local
+variables.
+
+The source and destination values/types need not correspond exactly. For structs,
+fields (identified by name) that are in the source but absent from the receiving
+variable will be ignored. Fields that are in the receiving variable but missing
+from the transmitted type or value will be ignored in the destination. If a field
+with the same name is present in both, their types must be compatible. Both the
+receiver and transmitter will do all necessary indirection and dereferencing to
+convert between gobs and actual Go values. For instance, a gob type that is
+schematically,
+
+ struct { a, b int }
+
+can be sent from or received into any of these Go types:
+
+ struct { a, b int } // the same
+ *struct { a, b int } // extra indirection of the struct
+ struct { *a, **b int } // extra indirection of the fields
+ struct { a, b int64 } // different concrete value type; see below
+
+It may also be received into any of these:
+
+ struct { a, b int } // the same
+ struct { b, a int } // ordering doesn't matter; matching is by name
+ struct { a, b, c int } // extra field (c) ignored
+ struct { b int } // missing field (a) ignored; data will be dropped
+ struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
+
+Attempting to receive into these types will draw a decode error:
+
+ struct { a int; b uint } // change of signedness for b
+ struct { a int; b float } // change of type for b
+ struct { } // no field names in common
+ struct { c, d int } // no field names in common
+
+Integers are transmitted two ways: arbitrary precision signed integers or
+arbitrary precision unsigned integers. There is no int8, int16 etc.
+discrimination in the gob format; there are only signed and unsigned integers. As
+described below, the transmitter sends the value in a variable-length encoding;
+the receiver accepts the value and stores it in the destination variable.
+Floating-point numbers are always sent using IEEE-754 64-bit precision (see
+below).
+
+Signed integers may be received into any signed integer variable: int, int16, etc.;
+unsigned integers may be received into any unsigned integer variable; and floating
+point values may be received into any floating point variable. However,
+the destination variable must be able to represent the value or the decode
+operation will fail.
+
+Structs, arrays and slices are also supported. Strings and arrays of bytes are
+supported with a special, efficient representation (see below).
+
+Functions and channels cannot be sent in a gob. Attempting
+to encode a value that contains one will fail.
+
+The rest of this comment documents the encoding, details that are not important
+for most users. Details are presented bottom-up.
+
+An unsigned integer is sent one of two ways. If it is less than 128, it is sent
+as a byte with that value. Otherwise it is sent as a minimal-length big-endian
+(high byte first) byte stream holding the value, preceded by one byte holding the
+byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and
+256 is transmitted as (FE 01 00).
+
+A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
+
+A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
+upward contain the value; bit 0 says whether they should be complemented upon
+receipt. The encode algorithm looks like this:
+
+ uint u;
+ if i < 0 {
+ u = (^i << 1) | 1 // complement i, bit 0 is 1
+ } else {
+ u = (i << 1) // do not complement i, bit 0 is 0
+ }
+ encodeUnsigned(u)
+
+The low bit is therefore analogous to a sign bit, but making it the complement bit
+instead guarantees that the largest negative integer is not a special case. For
+example, -129=^128=(^256>>1) encodes as (FE 01 01).
+
+Floating-point numbers are always sent as a representation of a float64 value.
+That value is converted to a uint64 using math.Float64bits. The uint64 is then
+byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
+exponent and high-precision part of the mantissa go first. Since the low bits are
+often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
+three bytes (FE 31 40).
+
+Strings and slices of bytes are sent as an unsigned count followed by that many
+uninterpreted bytes of the value.
+
+All other slices and arrays are sent as an unsigned count followed by that many
+elements using the standard gob encoding for their type, recursively.
+
+Structs are sent as a sequence of (field number, field value) pairs. The field
+value is sent using the standard gob encoding for its type, recursively. If a
+field has the zero value for its type, it is omitted from the transmission. The
+field number is defined by the type of the encoded struct: the first field of the
+encoded type is field 0, the second is field 1, etc. When encoding a value, the
+field numbers are delta encoded for efficiency and the fields are always sent in
+order of increasing field number; the deltas are therefore unsigned. The
+initialization for the delta encoding sets the field number to -1, so an unsigned
+integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
+= 7 or (01 07). Finally, after all the fields have been sent a terminating mark
+denotes the end of the struct. That mark is a delta=0 value, which has
+representation (00).
+
+Interface types are not checked for compatibility; all interface types are
+treated, for transmission, as members of a single "interface" type, analogous to
+int or []byte - in effect they're all treated as interface{}. Interface values
+are transmitted as a string identifying the concrete type being sent (a name
+that must be pre-defined by calling Register), followed by a byte count of the
+length of the following data (so the value can be skipped if it cannot be
+stored), followed by the usual encoding of concrete (dynamic) value stored in
+the interface value. (A nil interface value is identified by the empty string
+and transmits no value.) Upon receipt, the decoder verifies that the unpacked
+concrete item satisfies the interface of the receiving variable.
+
+The representation of types is described below. When a type is defined on a given
+connection between an Encoder and Decoder, it is assigned a signed integer type
+id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
+the type of v and all its elements and then it sends the pair (typeid, encoded-v)
+where typeid is the type id of the encoded type of v and encoded-v is the gob
+encoding of the value v.
+
+To define a type, the encoder chooses an unused, positive type id and sends the
+pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
+description, constructed from these types:
+
+ type wireType struct {
+ ArrayT *ArrayType
+ SliceT *SliceType
+ StructT *StructType
+ MapT *MapType
+ }
+ type ArrayType struct {
+ CommonType
+ Elem typeId
+ Len int
+ }
+ type CommonType {
+ Name string // the name of the struct type
+ Id int // the id of the type, repeated so it's inside the type
+ }
+ type SliceType struct {
+ CommonType
+ Elem typeId
+ }
+ type StructType struct {
+ CommonType
+ Field []*fieldType // the fields of the struct.
+ }
+ type FieldType struct {
+ Name string // the name of the field.
+ Id int // the type id of the field, which must be already defined
+ }
+ type MapType struct {
+ CommonType
+ Key typeId
+ Elem typeId
+ }
+
+If there are nested type ids, the types for all inner type ids must be defined
+before the top-level type id is used to describe an encoded-v.
+
+For simplicity in setup, the connection is defined to understand these types a
+priori, as well as the basic gob types int, uint, etc. Their ids are:
+
+ bool 1
+ int 2
+ uint 3
+ float 4
+ []byte 5
+ string 6
+ complex 7
+ interface 8
+ // gap for reserved ids.
+ WireType 16
+ ArrayType 17
+ CommonType 18
+ SliceType 19
+ StructType 20
+ FieldType 21
+ // 22 is slice of fieldType.
+ MapType 23
+
+Finally, each message created by a call to Encode is preceded by an encoded
+unsigned integer count of the number of bytes remaining in the message. After
+the initial type name, interface values are wrapped the same way; in effect, the
+interface value acts like a recursive invocation of Encode.
+
+In summary, a gob stream looks like
+
+ (byteCount (-type id, encoding of a wireType)* (type id, encoding of a value))*
+
+where * signifies zero or more repetitions and the type id of a value must
+be predefined or be defined before the value in the stream.
+*/
+package gob
+
+/*
+For implementers and the curious, here is an encoded example. Given
+ type Point struct {x, y int}
+and the value
+ p := Point{22, 33}
+the bytes transmitted that encode p will be:
+ 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00
+ 01 02 01 01 78 01 04 00 01 01 79 01 04 00 00 00
+ 07 ff 82 01 2c 01 42 00
+They are determined as follows.
+
+Since this is the first transmission of type Point, the type descriptor
+for Point itself must be sent before the value. This is the first type
+we've sent on this Encoder, so it has type id 65 (0 through 64 are
+reserved).
+
+ 1f // This item (a type descriptor) is 31 bytes long.
+ ff 81 // The negative of the id for the type we're defining, -65.
+ // This is one byte (indicated by FF = -1) followed by
+ // ^-65<<1 | 1. The low 1 bit signals to complement the
+ // rest upon receipt.
+
+ // Now we send a type descriptor, which is itself a struct (wireType).
+ // The type of wireType itself is known (it's built in, as is the type of
+ // all its components), so we just need to send a *value* of type wireType
+ // that represents type "Point".
+ // Here starts the encoding of that value.
+ // Set the field number implicitly to -1; this is done at the beginning
+ // of every struct, including nested structs.
+ 03 // Add 3 to field number; now 2 (wireType.structType; this is a struct).
+ // structType starts with an embedded commonType, which appears
+ // as a regular structure here too.
+ 01 // add 1 to field number (now 0); start of embedded commonType.
+ 01 // add 1 to field number (now 0, the name of the type)
+ 05 // string is (unsigned) 5 bytes long
+ 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
+ 01 // add 1 to field number (now 1, the id of the type)
+ ff 82 // wireType.structType.commonType._id = 65
+ 00 // end of embedded wiretype.structType.commonType struct
+ 01 // add 1 to field number (now 1, the field array in wireType.structType)
+ 02 // There are two fields in the type (len(structType.field))
+ 01 // Start of first field structure; add 1 to get field number 0: field[0].name
+ 01 // 1 byte
+ 78 // structType.field[0].name = "x"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // structType.field[0].typeId is 2 (signed int).
+ 00 // End of structType.field[0]; start structType.field[1]; set field number to -1.
+ 01 // Add 1 to get field number 0: field[1].name
+ 01 // 1 byte
+ 79 // structType.field[1].name = "y"
+ 01 // Add 1 to get field number 1: field[0].id
+ 04 // struct.Type.field[1].typeId is 2 (signed int).
+ 00 // End of structType.field[1]; end of structType.field.
+ 00 // end of wireType.structType structure
+ 00 // end of wireType structure
+
+Now we can send the Point value. Again the field number resets to -1:
+
+ 07 // this value is 7 bytes long
+ ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1)
+ 01 // add one to field number, yielding field 0
+ 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
+ 01 // add one to field number, yielding field 1
+ 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
+ 00 // end of structure
+
+The type encoding is long and fairly intricate but we send it only once.
+If p is transmitted a second time, the type is already known so the
+output will be just:
+
+ 07 ff 82 01 2c 01 42 00
+
+A single non-struct value at top level is transmitted like a field with
+delta tag 0. For instance, a signed integer with value 3 presented as
+the argument to Encode will emit:
+
+ 03 04 00 06
+
+Which represents:
+
+ 03 // this value is 3 bytes long
+ 04 // the type number, 2, represents an integer
+ 00 // tag delta 0
+ 06 // value 3
+
+*/
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index 00548868b..3431eafa7 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -2,270 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-/*
- The gob package manages streams of gobs - binary values exchanged between an
- Encoder (transmitter) and a Decoder (receiver). A typical use is transporting
- arguments and results of remote procedure calls (RPCs) such as those provided by
- package "rpc".
-
- A stream of gobs is self-describing. Each data item in the stream is preceded by
- a specification of its type, expressed in terms of a small set of predefined
- types. Pointers are not transmitted, but the things they point to are
- transmitted; that is, the values are flattened. Recursive types work fine, but
- recursive values (data with cycles) are problematic. This may change.
-
- To use gobs, create an Encoder and present it with a series of data items as
- values or addresses that can be dereferenced to values. The Encoder makes sure
- all type information is sent before it is needed. At the receive side, a
- Decoder retrieves values from the encoded stream and unpacks them into local
- variables.
-
- The source and destination values/types need not correspond exactly. For structs,
- fields (identified by name) that are in the source but absent from the receiving
- variable will be ignored. Fields that are in the receiving variable but missing
- from the transmitted type or value will be ignored in the destination. If a field
- with the same name is present in both, their types must be compatible. Both the
- receiver and transmitter will do all necessary indirection and dereferencing to
- convert between gobs and actual Go values. For instance, a gob type that is
- schematically,
-
- struct { a, b int }
-
- can be sent from or received into any of these Go types:
-
- struct { a, b int } // the same
- *struct { a, b int } // extra indirection of the struct
- struct { *a, **b int } // extra indirection of the fields
- struct { a, b int64 } // different concrete value type; see below
-
- It may also be received into any of these:
-
- struct { a, b int } // the same
- struct { b, a int } // ordering doesn't matter; matching is by name
- struct { a, b, c int } // extra field (c) ignored
- struct { b int } // missing field (a) ignored; data will be dropped
- struct { b, c int } // missing field (a) ignored; extra field (c) ignored.
-
- Attempting to receive into these types will draw a decode error:
-
- struct { a int; b uint } // change of signedness for b
- struct { a int; b float } // change of type for b
- struct { } // no field names in common
- struct { c, d int } // no field names in common
-
- Integers are transmitted two ways: arbitrary precision signed integers or
- arbitrary precision unsigned integers. There is no int8, int16 etc.
- discrimination in the gob format; there are only signed and unsigned integers. As
- described below, the transmitter sends the value in a variable-length encoding;
- the receiver accepts the value and stores it in the destination variable.
- Floating-point numbers are always sent using IEEE-754 64-bit precision (see
- below).
-
- Signed integers may be received into any signed integer variable: int, int16, etc.;
- unsigned integers may be received into any unsigned integer variable; and floating
- point values may be received into any floating point variable. However,
- the destination variable must be able to represent the value or the decode
- operation will fail.
-
- Structs, arrays and slices are also supported. Strings and arrays of bytes are
- supported with a special, efficient representation (see below).
-
- Interfaces, functions, and channels cannot be sent in a gob. Attempting
- to encode a value that contains one will fail.
-
- The rest of this comment documents the encoding, details that are not important
- for most users. Details are presented bottom-up.
-
- An unsigned integer is sent one of two ways. If it is less than 128, it is sent
- as a byte with that value. Otherwise it is sent as a minimal-length big-endian
- (high byte first) byte stream holding the value, preceded by one byte holding the
- byte count, negated. Thus 0 is transmitted as (00), 7 is transmitted as (07) and
- 256 is transmitted as (FE 01 00).
-
- A boolean is encoded within an unsigned integer: 0 for false, 1 for true.
-
- A signed integer, i, is encoded within an unsigned integer, u. Within u, bits 1
- upward contain the value; bit 0 says whether they should be complemented upon
- receipt. The encode algorithm looks like this:
-
- uint u;
- if i < 0 {
- u = (^i << 1) | 1 // complement i, bit 0 is 1
- } else {
- u = (i << 1) // do not complement i, bit 0 is 0
- }
- encodeUnsigned(u)
-
- The low bit is therefore analogous to a sign bit, but making it the complement bit
- instead guarantees that the largest negative integer is not a special case. For
- example, -129=^128=(^256>>1) encodes as (FE 01 01).
-
- Floating-point numbers are always sent as a representation of a float64 value.
- That value is converted to a uint64 using math.Float64bits. The uint64 is then
- byte-reversed and sent as a regular unsigned integer. The byte-reversal means the
- exponent and high-precision part of the mantissa go first. Since the low bits are
- often zero, this can save encoding bytes. For instance, 17.0 is encoded in only
- three bytes (FE 31 40).
-
- Strings and slices of bytes are sent as an unsigned count followed by that many
- uninterpreted bytes of the value.
-
- All other slices and arrays are sent as an unsigned count followed by that many
- elements using the standard gob encoding for their type, recursively.
-
- Structs are sent as a sequence of (field number, field value) pairs. The field
- value is sent using the standard gob encoding for its type, recursively. If a
- field has the zero value for its type, it is omitted from the transmission. The
- field number is defined by the type of the encoded struct: the first field of the
- encoded type is field 0, the second is field 1, etc. When encoding a value, the
- field numbers are delta encoded for efficiency and the fields are always sent in
- order of increasing field number; the deltas are therefore unsigned. The
- initialization for the delta encoding sets the field number to -1, so an unsigned
- integer field 0 with value 7 is transmitted as unsigned delta = 1, unsigned value
- = 7 or (01 0E). Finally, after all the fields have been sent a terminating mark
- denotes the end of the struct. That mark is a delta=0 value, which has
- representation (00).
-
- The representation of types is described below. When a type is defined on a given
- connection between an Encoder and Decoder, it is assigned a signed integer type
- id. When Encoder.Encode(v) is called, it makes sure there is an id assigned for
- the type of v and all its elements and then it sends the pair (typeid, encoded-v)
- where typeid is the type id of the encoded type of v and encoded-v is the gob
- encoding of the value v.
-
- To define a type, the encoder chooses an unused, positive type id and sends the
- pair (-type id, encoded-type) where encoded-type is the gob encoding of a wireType
- description, constructed from these types:
-
- type wireType struct {
- s structType;
- }
- type fieldType struct {
- name string; // the name of the field.
- id int; // the type id of the field, which must be already defined
- }
- type commonType {
- name string; // the name of the struct type
- id int; // the id of the type, repeated for so it's inside the type
- }
- type structType struct {
- commonType;
- field []fieldType; // the fields of the struct.
- }
-
- If there are nested type ids, the types for all inner type ids must be defined
- before the top-level type id is used to describe an encoded-v.
-
- For simplicity in setup, the connection is defined to understand these types a
- priori, as well as the basic gob types int, uint, etc. Their ids are:
-
- bool 1
- int 2
- uint 3
- float 4
- []byte 5
- string 6
- wireType 7
- structType 8
- commonType 9
- fieldType 10
-
- In summary, a gob stream looks like
-
- ((-type id, encoding of a wireType)* (type id, encoding of a value))*
-
- where * signifies zero or more repetitions and the type id of a value must
- be predefined or be defined before the value in the stream.
-*/
package gob
-/*
- For implementers and the curious, here is an encoded example. Given
- type Point {x, y int}
- and the value
- p := Point{22, 33}
- the bytes transmitted that encode p will be:
- 1f ff 81 03 01 01 05 50 6f 69 6e 74 01 ff 82 00 01 02 01 01 78
- 01 04 00 01 01 79 01 04 00 00 00 07 ff 82 01 2c 01 42 00 07 ff
- 82 01 2c 01 42 00
- They are determined as follows.
-
- Since this is the first transmission of type Point, the type descriptor
- for Point itself must be sent before the value. This is the first type
- we've sent on this Encoder, so it has type id 65 (0 through 64 are
- reserved).
-
- 1f // This item (a type descriptor) is 31 bytes long.
- ff 81 // The negative of the id for the type we're defining, -65.
- // This is one byte (indicated by FF = -1) followed by
- // ^-65<<1 | 1. The low 1 bit signals to complement the
- // rest upon receipt.
-
- // Now we send a type descriptor, which is itself a struct (wireType).
- // The type of wireType itself is known (it's built in, as is the type of
- // all its components), so we just need to send a *value* of type wireType
- // that represents type "Point".
- // Here starts the encoding of that value.
- // Set the field number implicitly to zero; this is done at the beginning
- // of every struct, including nested structs.
- 03 // Add 3 to field number; now 3 (wireType.structType; this is a struct).
- // structType starts with an embedded commonType, which appears
- // as a regular structure here too.
- 01 // add 1 to field number (now 1); start of embedded commonType.
- 01 // add one to field number (now 1, the name of the type)
- 05 // string is (unsigned) 5 bytes long
- 50 6f 69 6e 74 // wireType.structType.commonType.name = "Point"
- 01 // add one to field number (now 2, the id of the type)
- ff 82 // wireType.structType.commonType._id = 65
- 00 // end of embedded wiretype.structType.commonType struct
- 01 // add one to field number (now 2, the Field array in wireType.structType)
- 02 // There are two fields in the type (len(structType.field))
- 01 // Start of first field structure; add 1 to get field number 1: field[0].name
- 01 // 1 byte
- 78 // structType.field[0].name = "x"
- 01 // Add 1 to get field number 2: field[0].id
- 04 // structType.field[0].typeId is 2 (signed int).
- 00 // End of structType.field[0]; start structType.field[1]; set field number to 0.
- 01 // Add 1 to get field number 1: field[1].name
- 01 // 1 byte
- 79 // structType.field[1].name = "y"
- 01 // Add 1 to get field number 2: field[0].id
- 04 // struct.Type.field[1].typeId is 2 (signed int).
- 00 // End of structType.field[1]; end of structType.field.
- 00 // end of wireType.structType structure
- 00 // end of wireType structure
-
- Now we can send the Point value. Again the field number resets to zero:
-
- 07 // this value is 7 bytes long
- ff 82 // the type number, 65 (1 byte (-FF) followed by 65<<1)
- 01 // add one to field number, yielding field 1
- 2c // encoding of signed "22" (0x22 = 44 = 22<<1); Point.x = 22
- 01 // add one to field number, yielding field 2
- 42 // encoding of signed "33" (0x42 = 66 = 33<<1); Point.y = 33
- 00 // end of structure
-
- The type encoding is long and fairly intricate but we send it only once.
- If p is transmitted a second time, the type is already known so the
- output will be just:
-
- 07 ff 82 01 2c 01 42 00
-
- A single non-struct value at top level is transmitted like a field with
- delta tag 0. For instance, a signed integer with value 3 presented as
- the argument to Encode will emit:
-
- 03 04 00 06
-
- Which represents:
-
- 03 // this value is 3 bytes long
- 04 // the type number, 2, represents an integer
- 00 // tag delta 0
- 06 // value 3
-
-*/
-
import (
"bytes"
"io"
@@ -282,26 +20,29 @@ const uint64Size = unsafe.Sizeof(uint64(0))
// number is initialized to -1 so 0 comes out as delta(1). A delta of
// 0 terminates the structure.
type encoderState struct {
+ enc *Encoder
b *bytes.Buffer
- err os.Error // error encountered during encoding.
sendZero bool // encoding an array element or map key/value pair; send zero values
fieldnum int // the last field number written.
buf [1 + uint64Size]byte // buffer used by the encoder; here to avoid allocation.
}
+func newEncoderState(enc *Encoder, b *bytes.Buffer) *encoderState {
+ return &encoderState{enc: enc, b: b}
+}
+
// Unsigned integers have a two-state encoding. If the number is less
// than 128 (0 through 0x7F), its value is written directly.
// Otherwise the value is written in big-endian byte order preceded
// by the byte length, negated.
-// encodeUint writes an encoded unsigned integer to state.b. Sets state.err.
-// If state.err is already non-nil, it does nothing.
-func encodeUint(state *encoderState, x uint64) {
- if state.err != nil {
- return
- }
+// encodeUint writes an encoded unsigned integer to state.b.
+func (state *encoderState) encodeUint(x uint64) {
if x <= 0x7F {
- state.err = state.b.WriteByte(uint8(x))
+ err := state.b.WriteByte(uint8(x))
+ if err != nil {
+ error(err)
+ }
return
}
var n, m int
@@ -312,20 +53,23 @@ func encodeUint(state *encoderState, x uint64) {
m--
}
state.buf[m] = uint8(-(n - 1))
- n, state.err = state.b.Write(state.buf[m : uint64Size+1])
+ n, err := state.b.Write(state.buf[m : uint64Size+1])
+ if err != nil {
+ error(err)
+ }
}
// encodeInt writes an encoded signed integer to state.w.
-// The low bit of the encoding says whether to bit complement the (other bits of the) uint to recover the int.
-// Sets state.err. If state.err is already non-nil, it does nothing.
-func encodeInt(state *encoderState, i int64) {
+// The low bit of the encoding says whether to bit complement the (other bits of the)
+// uint to recover the int.
+func (state *encoderState) encodeInt(i int64) {
var x uint64
if i < 0 {
x = uint64(^i<<1) | 1
} else {
x = uint64(i << 1)
}
- encodeUint(state, uint64(x))
+ state.encodeUint(uint64(x))
}
type encOp func(i *encInstr, state *encoderState, p unsafe.Pointer)
@@ -342,7 +86,7 @@ type encInstr struct {
// If the instruction pointer is nil, do nothing
func (state *encoderState) update(instr *encInstr) {
if instr != nil {
- encodeUint(state, uint64(instr.field-state.fieldnum))
+ state.encodeUint(uint64(instr.field - state.fieldnum))
state.fieldnum = instr.field
}
}
@@ -368,9 +112,9 @@ func encBool(i *encInstr, state *encoderState, p unsafe.Pointer) {
if b || state.sendZero {
state.update(i)
if b {
- encodeUint(state, 1)
+ state.encodeUint(1)
} else {
- encodeUint(state, 0)
+ state.encodeUint(0)
}
}
}
@@ -379,7 +123,7 @@ func encInt(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -387,7 +131,7 @@ func encUint(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -395,7 +139,7 @@ func encInt8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int8)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -403,7 +147,7 @@ func encUint8(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint8)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -411,7 +155,7 @@ func encInt16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int16)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -419,7 +163,7 @@ func encUint16(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint16)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -427,7 +171,7 @@ func encInt32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := int64(*(*int32)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -435,7 +179,7 @@ func encUint32(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uint32)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -443,7 +187,7 @@ func encInt64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*int64)(p)
if v != 0 || state.sendZero {
state.update(i)
- encodeInt(state, v)
+ state.encodeInt(v)
}
}
@@ -451,7 +195,7 @@ func encUint64(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := *(*uint64)(p)
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -459,7 +203,7 @@ func encUintptr(i *encInstr, state *encoderState, p unsafe.Pointer) {
v := uint64(*(*uintptr)(p))
if v != 0 || state.sendZero {
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -484,7 +228,7 @@ func encFloat(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
v := floatBits(float64(f))
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -493,7 +237,7 @@ func encFloat32(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
v := floatBits(float64(f))
state.update(i)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -502,7 +246,7 @@ func encFloat64(i *encInstr, state *encoderState, p unsafe.Pointer) {
if f != 0 || state.sendZero {
state.update(i)
v := floatBits(f)
- encodeUint(state, v)
+ state.encodeUint(v)
}
}
@@ -513,8 +257,8 @@ func encComplex(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
@@ -524,8 +268,8 @@ func encComplex64(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(float64(real(c)))
ipart := floatBits(float64(imag(c)))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
@@ -535,17 +279,20 @@ func encComplex128(i *encInstr, state *encoderState, p unsafe.Pointer) {
rpart := floatBits(real(c))
ipart := floatBits(imag(c))
state.update(i)
- encodeUint(state, rpart)
- encodeUint(state, ipart)
+ state.encodeUint(rpart)
+ state.encodeUint(ipart)
}
}
+func encNoOp(i *encInstr, state *encoderState, p unsafe.Pointer) {
+}
+
// Byte arrays are encoded as an unsigned count followed by the raw bytes.
func encUint8Array(i *encInstr, state *encoderState, p unsafe.Pointer) {
b := *(*[]byte)(p)
if len(b) > 0 || state.sendZero {
state.update(i)
- encodeUint(state, uint64(len(b)))
+ state.encodeUint(uint64(len(b)))
state.b.Write(b)
}
}
@@ -555,14 +302,14 @@ func encString(i *encInstr, state *encoderState, p unsafe.Pointer) {
s := *(*string)(p)
if len(s) > 0 || state.sendZero {
state.update(i)
- encodeUint(state, uint64(len(s)))
+ state.encodeUint(uint64(len(s)))
io.WriteString(state.b, s)
}
}
// The end of a struct is marked by a delta field number of 0.
func encStructTerminator(i *encInstr, state *encoderState, p unsafe.Pointer) {
- encodeUint(state, 0)
+ state.encodeUint(0)
}
// Execution engine
@@ -575,9 +322,8 @@ type encEngine struct {
const singletonField = 0
-func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeSingle(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
state.fieldnum = singletonField
// There is no surrounding struct to frame the transmission, so we must
// generate data even if the item is zero. To do this, set sendZero.
@@ -586,16 +332,14 @@ func encodeSingle(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
p := unsafe.Pointer(basep) // offset will be zero
if instr.indir > 0 {
if p = encIndirect(p, instr.indir); p == nil {
- return nil
+ return
}
}
instr.op(instr, state, p)
- return state.err
}
-func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeStruct(b *bytes.Buffer, engine *encEngine, basep uintptr) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
for i := 0; i < len(engine.instr); i++ {
instr := &engine.instr[i]
@@ -606,33 +350,26 @@ func encodeStruct(engine *encEngine, b *bytes.Buffer, basep uintptr) os.Error {
}
}
instr.op(instr, state, p)
- if state.err != nil {
- break
- }
}
- return state.err
}
-func encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeArray(b *bytes.Buffer, p uintptr, op encOp, elemWid uintptr, elemIndir int, length int) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
state.sendZero = true
- encodeUint(state, uint64(length))
- for i := 0; i < length && state.err == nil; i++ {
+ state.encodeUint(uint64(length))
+ for i := 0; i < length; i++ {
elemp := p
up := unsafe.Pointer(elemp)
if elemIndir > 0 {
if up = encIndirect(up, elemIndir); up == nil {
- state.err = os.ErrorString("gob: encodeArray: nil element")
- break
+ errorf("gob: encodeArray: nil element")
}
elemp = uintptr(up)
}
op(nil, state, unsafe.Pointer(elemp))
p += uintptr(elemWid)
}
- return state.err
}
func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir int) {
@@ -640,27 +377,60 @@ func encodeReflectValue(state *encoderState, v reflect.Value, op encOp, indir in
v = reflect.Indirect(v)
}
if v == nil {
- state.err = os.ErrorString("gob: encodeReflectValue: nil element")
- return
+ errorf("gob: encodeReflectValue: nil element")
}
op(nil, state, unsafe.Pointer(v.Addr()))
}
-func encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) os.Error {
- state := new(encoderState)
- state.b = b
+func (enc *Encoder) encodeMap(b *bytes.Buffer, mv *reflect.MapValue, keyOp, elemOp encOp, keyIndir, elemIndir int) {
+ state := newEncoderState(enc, b)
state.fieldnum = -1
state.sendZero = true
keys := mv.Keys()
- encodeUint(state, uint64(len(keys)))
+ state.encodeUint(uint64(len(keys)))
for _, key := range keys {
- if state.err != nil {
- break
- }
encodeReflectValue(state, key, keyOp, keyIndir)
encodeReflectValue(state, mv.Elem(key), elemOp, elemIndir)
}
- return state.err
+}
+
+// To send an interface, we send a string identifying the concrete type, followed
+// by the type identifier (which might require defining that type right now), followed
+// by the concrete value. A nil value gets sent as the empty string for the name,
+// followed by no value.
+func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue) {
+ state := newEncoderState(enc, b)
+ state.fieldnum = -1
+ state.sendZero = true
+ if iv.IsNil() {
+ state.encodeUint(0)
+ return
+ }
+
+ typ, _ := indirect(iv.Elem().Type())
+ name, ok := concreteTypeToName[typ]
+ if !ok {
+ errorf("gob: type not registered for interface: %s", typ)
+ }
+ // Send the name.
+ state.encodeUint(uint64(len(name)))
+ _, err := io.WriteString(state.b, name)
+ if err != nil {
+ error(err)
+ }
+ // Send (and maybe first define) the type id.
+ enc.sendTypeDescriptor(typ)
+ // Encode the value into a new buffer.
+ data := new(bytes.Buffer)
+ err = enc.encode(data, iv.Elem())
+ if err != nil {
+ error(err)
+ }
+ state.encodeUint(uint64(data.Len()))
+ _, err = state.b.Write(data.Bytes())
+ if err != nil {
+ error(err)
+ }
}
var encOpMap = []encOp{
@@ -687,7 +457,7 @@ var encOpMap = []encOp{
// Return the encoding op for the base type under rt and
// the indirection count to reach it.
-func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
+func (enc *Encoder) encOpFor(rt reflect.Type) (encOp, int) {
typ, indir := indirect(rt)
var op encOp
k := typ.Kind()
@@ -703,128 +473,123 @@ func encOpFor(rt reflect.Type) (encOp, int, os.Error) {
break
}
// Slices have a header; we decode it to find the underlying array.
- elemOp, indir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ elemOp, indir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
slice := (*reflect.SliceHeader)(p)
- if slice.Len == 0 {
+ if !state.sendZero && slice.Len == 0 {
return
}
state.update(i)
- state.err = encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
+ state.enc.encodeArray(state.b, slice.Data, elemOp, t.Elem().Size(), indir, int(slice.Len))
}
case *reflect.ArrayType:
// True arrays have size in the type.
- elemOp, indir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ elemOp, indir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
- slice := (*reflect.SliceHeader)(p)
- if slice.Len == 0 {
- return
- }
state.update(i)
- state.err = encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
+ state.enc.encodeArray(state.b, uintptr(p), elemOp, t.Elem().Size(), indir, t.Len())
}
case *reflect.MapType:
- keyOp, keyIndir, err := encOpFor(t.Key())
- if err != nil {
- return nil, 0, err
- }
- elemOp, elemIndir, err := encOpFor(t.Elem())
- if err != nil {
- return nil, 0, err
- }
+ keyOp, keyIndir := enc.encOpFor(t.Key())
+ elemOp, elemIndir := enc.encOpFor(t.Elem())
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
// Maps cannot be accessed by moving addresses around the way
// that slices etc. can. We must recover a full reflection value for
// the iteration.
v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
mv := reflect.Indirect(v).(*reflect.MapValue)
- if mv.Len() == 0 {
+ if !state.sendZero && mv.Len() == 0 {
return
}
state.update(i)
- state.err = encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
+ state.enc.encodeMap(state.b, mv, keyOp, elemOp, keyIndir, elemIndir)
}
case *reflect.StructType:
// Generate a closure that calls out to the engine for the nested type.
- _, err := getEncEngine(typ)
- if err != nil {
- return nil, 0, err
- }
+ enc.getEncEngine(typ)
info := mustGetTypeInfo(typ)
op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
state.update(i)
// indirect through info to delay evaluation for recursive structs
- state.err = encodeStruct(info.encoder, state.b, uintptr(p))
+ state.enc.encodeStruct(state.b, info.encoder, uintptr(p))
+ }
+ case *reflect.InterfaceType:
+ op = func(i *encInstr, state *encoderState, p unsafe.Pointer) {
+ // Interfaces transmit the name and contents of the concrete
+ // value they contain.
+ v := reflect.NewValue(unsafe.Unreflect(t, unsafe.Pointer((p))))
+ iv := reflect.Indirect(v).(*reflect.InterfaceValue)
+ if !state.sendZero && (iv == nil || iv.IsNil()) {
+ return
+ }
+ state.update(i)
+ state.enc.encodeInterface(state.b, iv)
}
}
}
if op == nil {
- return op, indir, os.ErrorString("gob enc: can't happen: encode type " + rt.String())
+ errorf("gob enc: can't happen: encode type %s", rt.String())
}
- return op, indir, nil
+ return op, indir
}
// The local Type was compiled from the actual value, so we know it's compatible.
-func compileEnc(rt reflect.Type) (*encEngine, os.Error) {
+func (enc *Encoder) compileEnc(rt reflect.Type) *encEngine {
srt, isStruct := rt.(*reflect.StructType)
engine := new(encEngine)
if isStruct {
engine.instr = make([]encInstr, srt.NumField()+1) // +1 for terminator
for fieldnum := 0; fieldnum < srt.NumField(); fieldnum++ {
f := srt.Field(fieldnum)
- op, indir, err := encOpFor(f.Type)
- if err != nil {
- return nil, err
+ op, indir := enc.encOpFor(f.Type)
+ if !isExported(f.Name) {
+ op = encNoOp
}
engine.instr[fieldnum] = encInstr{op, fieldnum, indir, uintptr(f.Offset)}
}
engine.instr[srt.NumField()] = encInstr{encStructTerminator, 0, 0, 0}
} else {
engine.instr = make([]encInstr, 1)
- op, indir, err := encOpFor(rt)
- if err != nil {
- return nil, err
- }
+ op, indir := enc.encOpFor(rt)
engine.instr[0] = encInstr{op, singletonField, indir, 0} // offset is zero
}
- return engine, nil
+ return engine
}
// typeLock must be held (or we're in initialization and guaranteed single-threaded).
// The reflection type must have all its indirections processed out.
-func getEncEngine(rt reflect.Type) (*encEngine, os.Error) {
- info, err := getTypeInfo(rt)
- if err != nil {
- return nil, err
+func (enc *Encoder) getEncEngine(rt reflect.Type) *encEngine {
+ info, err1 := getTypeInfo(rt)
+ if err1 != nil {
+ error(err1)
}
if info.encoder == nil {
// mark this engine as underway before compiling to handle recursive types.
info.encoder = new(encEngine)
- info.encoder, err = compileEnc(rt)
+ info.encoder = enc.compileEnc(rt)
}
- return info.encoder, err
+ return info.encoder
+}
+
+// Put this in a function so we can hold the lock only while compiling, not when encoding.
+func (enc *Encoder) lockAndGetEncEngine(rt reflect.Type) *encEngine {
+ typeLock.Lock()
+ defer typeLock.Unlock()
+ return enc.getEncEngine(rt)
}
-func encode(b *bytes.Buffer, value reflect.Value) os.Error {
+func (enc *Encoder) encode(b *bytes.Buffer, value reflect.Value) (err os.Error) {
+ defer catchError(&err)
// Dereference down to the underlying object.
rt, indir := indirect(value.Type())
for i := 0; i < indir; i++ {
value = reflect.Indirect(value)
}
- typeLock.Lock()
- engine, err := getEncEngine(rt)
- typeLock.Unlock()
- if err != nil {
- return err
- }
+ engine := enc.lockAndGetEncEngine(rt)
if value.Type().Kind() == reflect.Struct {
- return encodeStruct(engine, b, value.Addr())
+ enc.encodeStruct(b, engine, value.Addr())
+ } else {
+ enc.encodeSingle(b, engine, value.Addr())
}
- return encodeSingle(engine, b, value.Addr())
+ return nil
}
diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go
index aba8d0e5c..8869b2629 100644
--- a/src/pkg/gob/encoder.go
+++ b/src/pkg/gob/encoder.go
@@ -21,6 +21,7 @@ type Encoder struct {
state *encoderState // so we can encode integers, strings directly
countState *encoderState // stage for writing counts
buf []byte // for collecting the output.
+ err os.Error
}
// NewEncoder returns a new encoder that will transmit on the io.Writer.
@@ -28,10 +29,8 @@ func NewEncoder(w io.Writer) *Encoder {
enc := new(Encoder)
enc.w = w
enc.sent = make(map[reflect.Type]typeId)
- enc.state = new(encoderState)
- enc.state.b = new(bytes.Buffer) // the rest isn't important; all we need is buffer and writer
- enc.countState = new(encoderState)
- enc.countState.b = new(bytes.Buffer) // the rest isn't important; all we need is buffer and writer
+ enc.state = newEncoderState(enc, new(bytes.Buffer))
+ enc.countState = newEncoderState(enc, new(bytes.Buffer))
return enc
}
@@ -40,8 +39,8 @@ func (enc *Encoder) badType(rt reflect.Type) {
}
func (enc *Encoder) setError(err os.Error) {
- if enc.state.err == nil { // remember the first.
- enc.state.err = err
+ if enc.err == nil { // remember the first.
+ enc.err = err
}
enc.state.b.Reset()
}
@@ -49,7 +48,7 @@ func (enc *Encoder) setError(err os.Error) {
// Send the data item preceded by a unsigned count of its length.
func (enc *Encoder) send() {
// Encode the length.
- encodeUint(enc.countState, uint64(enc.state.b.Len()))
+ enc.countState.encodeUint(uint64(enc.state.b.Len()))
// Build the buffer.
countLen := enc.countState.b.Len()
total := countLen + enc.state.b.Len()
@@ -74,7 +73,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
switch rt := rt.(type) {
default:
- // Basic types do not need to be described.
+ // Basic types and interfaces do not need to be described.
return
case *reflect.SliceType:
// If it's []uint8, don't send; it's considered basic.
@@ -92,7 +91,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
case *reflect.StructType:
// structs must be sent so we know their fields.
break
- case *reflect.ChanType, *reflect.FuncType, *reflect.InterfaceType:
+ case *reflect.ChanType, *reflect.FuncType:
// Probably a bad field in a struct.
enc.badType(rt)
return
@@ -113,11 +112,11 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
}
// Send the pair (-id, type)
// Id:
- encodeInt(enc.state, -int64(info.id))
+ enc.state.encodeInt(-int64(info.id))
// Type:
- encode(enc.state.b, reflect.NewValue(info.wire))
+ enc.encode(enc.state.b, reflect.NewValue(info.wire))
enc.send()
- if enc.state.err != nil {
+ if enc.err != nil {
return
}
@@ -134,7 +133,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) {
case reflect.ArrayOrSliceType:
enc.sendType(st.Elem())
}
- return
+ return true
}
// Encode transmits the data item represented by the empty interface value,
@@ -143,30 +142,17 @@ func (enc *Encoder) Encode(e interface{}) os.Error {
return enc.EncodeValue(reflect.NewValue(e))
}
-// EncodeValue transmits the data item represented by the reflection value,
-// guaranteeing that all necessary type information has been transmitted first.
-func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
- // Make sure we're single-threaded through here, so multiple
- // goroutines can share an encoder.
- enc.mutex.Lock()
- defer enc.mutex.Unlock()
-
- enc.state.err = nil
- rt, _ := indirect(value.Type())
-
- // Sanity check only: encoder should never come in with data present.
- if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
- enc.state.err = os.ErrorString("encoder: buffer not empty")
- return enc.state.err
- }
-
+// sendTypeId makes sure the remote side knows about this type.
+// It will send a descriptor if this is the first time the type has been
+// sent. Regardless, it sends the id.
+func (enc *Encoder) sendTypeDescriptor(rt reflect.Type) {
// Make sure the type is known to the other side.
// First, have we already sent this type?
if _, alreadySent := enc.sent[rt]; !alreadySent {
// No, so send it.
sent := enc.sendType(rt)
- if enc.state.err != nil {
- return enc.state.err
+ if enc.err != nil {
+ return
}
// If the type info has still not been transmitted, it means we have
// a singleton basic type (int, []byte etc.) at top level. We don't
@@ -177,22 +163,45 @@ func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
typeLock.Unlock()
if err != nil {
enc.setError(err)
- return err
+ return
}
enc.sent[rt] = info.id
}
}
// Identify the type of this top-level value.
- encodeInt(enc.state, int64(enc.sent[rt]))
+ enc.state.encodeInt(int64(enc.sent[rt]))
+}
+
+// EncodeValue transmits the data item represented by the reflection value,
+// guaranteeing that all necessary type information has been transmitted first.
+func (enc *Encoder) EncodeValue(value reflect.Value) os.Error {
+ // Make sure we're single-threaded through here, so multiple
+ // goroutines can share an encoder.
+ enc.mutex.Lock()
+ defer enc.mutex.Unlock()
+
+ enc.err = nil
+ rt, _ := indirect(value.Type())
+
+ // Sanity check only: encoder should never come in with data present.
+ if enc.state.b.Len() > 0 || enc.countState.b.Len() > 0 {
+ enc.err = os.ErrorString("encoder: buffer not empty")
+ return enc.err
+ }
+
+ enc.sendTypeDescriptor(rt)
+ if enc.err != nil {
+ return enc.err
+ }
// Encode the object.
- err := encode(enc.state.b, value)
+ err := enc.encode(enc.state.b, value)
if err != nil {
enc.setError(err)
} else {
enc.send()
}
- return enc.state.err
+ return enc.err
}
diff --git a/src/pkg/gob/encoder_test.go b/src/pkg/gob/encoder_test.go
index b578cd0f8..db0b7db66 100644
--- a/src/pkg/gob/encoder_test.go
+++ b/src/pkg/gob/encoder_test.go
@@ -14,48 +14,48 @@ import (
)
type ET2 struct {
- x string
+ X string
}
type ET1 struct {
- a int
- et2 *ET2
- next *ET1
+ A int
+ Et2 *ET2
+ Next *ET1
}
// Like ET1 but with a different name for a field
type ET3 struct {
- a int
- et2 *ET2
- differentNext *ET1
+ A int
+ Et2 *ET2
+ DifferentNext *ET1
}
// Like ET1 but with a different type for a field
type ET4 struct {
- a int
- et2 float
- next int
+ A int
+ Et2 float
+ Next int
}
func TestEncoderDecoder(t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
et1 := new(ET1)
- et1.a = 7
- et1.et2 = new(ET2)
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("encoder fail:", enc.state.err)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
newEt1 := new(ET1)
- dec.Decode(newEt1)
- if dec.state.err != nil {
- t.Fatal("error decoding ET1:", dec.state.err)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("error decoding ET1:", err)
}
if !reflect.DeepEqual(et1, newEt1) {
- t.Fatalf("invalid data for et1: expected %+v; got %+v\n", *et1, *newEt1)
+ t.Fatalf("invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
}
if b.Len() != 0 {
t.Error("not at eof;", b.Len(), "bytes left")
@@ -63,25 +63,25 @@ func TestEncoderDecoder(t *testing.T) {
enc.Encode(et1)
newEt1 = new(ET1)
- dec.Decode(newEt1)
- if dec.state.err != nil {
- t.Fatal("round 2: error decoding ET1:", dec.state.err)
+ err = dec.Decode(newEt1)
+ if err != nil {
+ t.Fatal("round 2: error decoding ET1:", err)
}
if !reflect.DeepEqual(et1, newEt1) {
- t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v\n", *et1, *newEt1)
+ t.Fatalf("round 2: invalid data for et1: expected %+v; got %+v", *et1, *newEt1)
}
if b.Len() != 0 {
t.Error("round 2: not at eof;", b.Len(), "bytes left")
}
// Now test with a running encoder/decoder pair that we recognize a type mismatch.
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("round 3: encoder fail:", enc.state.err)
+ err = enc.Encode(et1)
+ if err != nil {
+ t.Error("round 3: encoder fail:", err)
}
newEt2 := new(ET2)
- dec.Decode(newEt2)
- if dec.state.err == nil {
+ err = dec.Decode(newEt2)
+ if err == nil {
t.Fatal("round 3: expected `bad type' error decoding ET2")
}
}
@@ -92,19 +92,19 @@ func badTypeCheck(e interface{}, shouldFail bool, msg string, t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
et1 := new(ET1)
- et1.a = 7
- et1.et2 = new(ET2)
- enc.Encode(et1)
- if enc.state.err != nil {
- t.Error("encoder fail:", enc.state.err)
+ et1.A = 7
+ et1.Et2 = new(ET2)
+ err := enc.Encode(et1)
+ if err != nil {
+ t.Error("encoder fail:", err)
}
dec := NewDecoder(b)
- dec.Decode(e)
- if shouldFail && (dec.state.err == nil) {
+ err = dec.Decode(e)
+ if shouldFail && err == nil {
t.Error("expected error for", msg)
}
- if !shouldFail && (dec.state.err != nil) {
- t.Error("unexpected error for", msg, dec.state.err)
+ if !shouldFail && err != nil {
+ t.Error("unexpected error for", msg, err)
}
}
@@ -118,9 +118,9 @@ func TestWrongTypeDecoder(t *testing.T) {
func corruptDataCheck(s string, err os.Error, t *testing.T) {
b := bytes.NewBufferString(s)
dec := NewDecoder(b)
- dec.Decode(new(ET2))
- if dec.state.err != err {
- t.Error("expected error", err, "got", dec.state.err)
+ err1 := dec.Decode(new(ET2))
+ if err1 != err {
+ t.Error("expected error", err, "got", err1)
}
}
@@ -135,7 +135,6 @@ func TestBadData(t *testing.T) {
var unsupportedValues = []interface{}{
make(chan int),
func(a int) bool { return true },
- new(interface{}),
}
func TestUnsupported(t *testing.T) {
@@ -152,14 +151,14 @@ func TestUnsupported(t *testing.T) {
func encAndDec(in, out interface{}) os.Error {
b := new(bytes.Buffer)
enc := NewEncoder(b)
- enc.Encode(in)
- if enc.state.err != nil {
- return enc.state.err
+ err := enc.Encode(in)
+ if err != nil {
+ return err
}
dec := NewDecoder(b)
- dec.Decode(out)
- if dec.state.err != nil {
- return dec.state.err
+ err = dec.Decode(out)
+ if err != nil {
+ return err
}
return nil
}
@@ -167,7 +166,7 @@ func encAndDec(in, out interface{}) os.Error {
func TestTypeToPtrType(t *testing.T) {
// Encode a T, decode a *T
type Type0 struct {
- a int
+ A int
}
t0 := Type0{7}
t0p := (*Type0)(nil)
@@ -179,7 +178,7 @@ func TestTypeToPtrType(t *testing.T) {
func TestPtrTypeToType(t *testing.T) {
// Encode a *T, decode a T
type Type1 struct {
- a uint
+ A uint
}
t1p := &Type1{17}
var t1 Type1
@@ -190,26 +189,26 @@ func TestPtrTypeToType(t *testing.T) {
func TestTypeToPtrPtrPtrPtrType(t *testing.T) {
type Type2 struct {
- a ****float
+ A ****float
}
t2 := Type2{}
- t2.a = new(***float)
- *t2.a = new(**float)
- **t2.a = new(*float)
- ***t2.a = new(float)
- ****t2.a = 27.4
+ t2.A = new(***float)
+ *t2.A = new(**float)
+ **t2.A = new(*float)
+ ***t2.A = new(float)
+ ****t2.A = 27.4
t2pppp := new(***Type2)
if err := encAndDec(t2, t2pppp); err != nil {
- t.Error(err)
+ t.Fatal(err)
}
- if ****(****t2pppp).a != ****t2.a {
- t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).a, ****t2.a)
+ if ****(****t2pppp).A != ****t2.A {
+ t.Errorf("wrong value after decode: %g not %g", ****(****t2pppp).A, ****t2.A)
}
}
func TestSlice(t *testing.T) {
type Type3 struct {
- a []string
+ A []string
}
t3p := &Type3{[]string{"hello", "world"}}
var t3 Type3
@@ -232,11 +231,11 @@ func TestValueError(t *testing.T) {
func TestArray(t *testing.T) {
type Type5 struct {
- a [3]string
- b [3]byte
+ A [3]string
+ B [3]byte
}
type Type6 struct {
- a [2]string // can't hold t5.a
+ A [2]string // can't hold t5.a
}
t5 := Type5{[3]string{"hello", ",", "world"}, [3]byte{1, 2, 3}}
var t5p Type5
@@ -252,10 +251,10 @@ func TestArray(t *testing.T) {
// Regression test for bug: must send zero values inside arrays
func TestDefaultsInArray(t *testing.T) {
type Type7 struct {
- b []bool
- i []int
- s []string
- f []float
+ B []bool
+ I []int
+ S []string
+ F []float
}
t7 := Type7{
[]bool{false, false, true},
@@ -274,6 +273,7 @@ var testFloat32 float32
var testString string
var testSlice []string
var testMap map[string]int
+var testArray [7]int
type SingleTest struct {
in interface{}
@@ -282,14 +282,16 @@ type SingleTest struct {
}
var singleTests = []SingleTest{
- SingleTest{17, &testInt, ""},
- SingleTest{float32(17.5), &testFloat32, ""},
- SingleTest{"bike shed", &testString, ""},
- SingleTest{[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
- SingleTest{map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {17, &testInt, ""},
+ {float32(17.5), &testFloat32, ""},
+ {"bike shed", &testString, ""},
+ {[]string{"bike", "shed", "paint", "color"}, &testSlice, ""},
+ {map[string]int{"seven": 7, "twelve": 12}, &testMap, ""},
+ {[7]int{4, 55, 0, 0, 0, 0, 0}, &testArray, ""}, // case that once triggered a bug
+ {[7]int{4, 55, 1, 44, 22, 66, 1234}, &testArray, ""},
// Decode errors
- SingleTest{172, &testFloat32, "wrong type"},
+ {172, &testFloat32, "wrong type"},
}
func TestSingletons(t *testing.T) {
@@ -320,7 +322,64 @@ func TestSingletons(t *testing.T) {
// Get rid of the pointer in the rhs
val := reflect.NewValue(test.out).(*reflect.PtrValue).Elem().Interface()
if !reflect.DeepEqual(test.in, val) {
- t.Errorf("decoding int: expected %v got %v", test.in, val)
+ t.Errorf("decoding singleton: expected %v got %v", test.in, val)
}
}
}
+
+func TestStructNonStruct(t *testing.T) {
+ type Struct struct {
+ A string
+ }
+ type NonStruct string
+ s := Struct{"hello"}
+ var sp Struct
+ if err := encAndDec(s, &sp); err != nil {
+ t.Error(err)
+ }
+ var ns NonStruct
+ if err := encAndDec(s, &ns); err == nil {
+ t.Error("should get error for struct/non-struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for struct/non-struct expected type error; got", err)
+ }
+ // Now try the other way
+ var nsp NonStruct
+ if err := encAndDec(ns, &nsp); err != nil {
+ t.Error(err)
+ }
+ if err := encAndDec(ns, &s); err == nil {
+ t.Error("should get error for non-struct/struct")
+ } else if strings.Index(err.String(), "type") < 0 {
+ t.Error("for non-struct/struct expected type error; got", err)
+ }
+}
+
+type interfaceIndirectTestI interface {
+ F() bool
+}
+
+type interfaceIndirectTestT struct{}
+
+func (this *interfaceIndirectTestT) F() bool {
+ return true
+}
+
+// A version of a bug reported on golang-nuts. Also tests top-level
+// slice of interfaces. The issue was registering *T caused T to be
+// stored as the concrete type.
+func TestInterfaceIndirect(t *testing.T) {
+ Register(&interfaceIndirectTestT{})
+ b := new(bytes.Buffer)
+ w := []interfaceIndirectTestI{&interfaceIndirectTestT{}}
+ err := NewEncoder(b).Encode(w)
+ if err != nil {
+ t.Fatal("encode error:", err)
+ }
+
+ var r []interfaceIndirectTestI
+ err = NewDecoder(b).Decode(&r)
+ if err != nil {
+ t.Fatal("decode error:", err)
+ }
+}
diff --git a/src/pkg/gob/error.go b/src/pkg/gob/error.go
new file mode 100644
index 000000000..b053761fb
--- /dev/null
+++ b/src/pkg/gob/error.go
@@ -0,0 +1,41 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package gob
+
+import (
+ "fmt"
+ "os"
+)
+
+// Errors in decoding and encoding are handled using panic and recover.
+// Panics caused by user error (that is, everything except run-time panics
+// such as "index out of bounds" errors) do not leave the file that caused
+// them, but are instead turned into plain os.Error returns. Encoding and
+// decoding functions and methods that do not return an os.Error either use
+// panic to report an error or are guaranteed error-free.
+
+// A gobError wraps an os.Error and is used to distinguish errors (panics) generated in this package.
+type gobError struct {
+ os.Error
+}
+
+// errorf is like error but takes Printf-style arguments to construct an os.Error.
+func errorf(format string, args ...interface{}) {
+ error(fmt.Errorf(format, args...))
+}
+
+// error wraps the argument error and uses it as the argument to panic.
+func error(err os.Error) {
+ panic(gobError{Error: err})
+}
+
+// catchError is meant to be used as a deferred function to turn a panic(gobError) into a
+// plain os.Error. It overwrites the error return of the function that deferred its call.
+func catchError(err *os.Error) {
+ if e := recover(); e != nil {
+ *err = e.(gobError).Error // Will re-panic if not one of our errors, such as a runtime error.
+ }
+ return
+}
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index 0b01b74dc..c00af87bf 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -29,7 +29,7 @@ const firstUserId = 64 // lowest id number granted to user
type gobType interface {
id() typeId
setId(id typeId)
- Name() string
+ name() string
string() string // not public; only for debugging
safeString(seen map[typeId]bool) string
}
@@ -52,42 +52,60 @@ func (t typeId) gobType() gobType {
}
// string returns the string representation of the type associated with the typeId.
-func (t typeId) string() string { return t.gobType().string() }
+func (t typeId) string() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().string()
+}
// Name returns the name of the type associated with the typeId.
-func (t typeId) Name() string { return t.gobType().Name() }
+func (t typeId) name() string {
+ if t.gobType() == nil {
+ return "<nil>"
+ }
+ return t.gobType().name()
+}
// Common elements of all types.
-type commonType struct {
- name string
- _id typeId
+type CommonType struct {
+ Name string
+ Id typeId
}
-func (t *commonType) id() typeId { return t._id }
+func (t *CommonType) id() typeId { return t.Id }
-func (t *commonType) setId(id typeId) { t._id = id }
+func (t *CommonType) setId(id typeId) { t.Id = id }
-func (t *commonType) string() string { return t.name }
+func (t *CommonType) string() string { return t.Name }
-func (t *commonType) safeString(seen map[typeId]bool) string {
- return t.name
+func (t *CommonType) safeString(seen map[typeId]bool) string {
+ return t.Name
}
-func (t *commonType) Name() string { return t.name }
+func (t *CommonType) name() string { return t.Name }
// Create and check predefined types
// The string for tBytes is "bytes" not "[]byte" to signify its specialness.
var (
// Primordial types, needed during initialization.
- tBool = bootstrapType("bool", false, 1)
- tInt = bootstrapType("int", int(0), 2)
- tUint = bootstrapType("uint", uint(0), 3)
- tFloat = bootstrapType("float", float64(0), 4)
- tBytes = bootstrapType("bytes", make([]byte, 0), 5)
- tString = bootstrapType("string", "", 6)
- // Types added to the language later, not needed during initialization.
- tComplex typeId
+ tBool = bootstrapType("bool", false, 1)
+ tInt = bootstrapType("int", int(0), 2)
+ tUint = bootstrapType("uint", uint(0), 3)
+ tFloat = bootstrapType("float", float64(0), 4)
+ tBytes = bootstrapType("bytes", make([]byte, 0), 5)
+ tString = bootstrapType("string", "", 6)
+ tComplex = bootstrapType("complex", 0+0i, 7)
+ tInterface = bootstrapType("interface", interface{}(nil), 8)
+ // Reserve some Ids for compatible expansion
+ tReserved7 = bootstrapType("_reserved1", struct{ r7 int }{}, 9)
+ tReserved6 = bootstrapType("_reserved1", struct{ r6 int }{}, 10)
+ tReserved5 = bootstrapType("_reserved1", struct{ r5 int }{}, 11)
+ tReserved4 = bootstrapType("_reserved1", struct{ r4 int }{}, 12)
+ tReserved3 = bootstrapType("_reserved1", struct{ r3 int }{}, 13)
+ tReserved2 = bootstrapType("_reserved1", struct{ r2 int }{}, 14)
+ tReserved1 = bootstrapType("_reserved1", struct{ r1 int }{}, 15)
)
// Predefined because it's needed by the Decoder
@@ -95,15 +113,13 @@ var tWireType = mustGetTypeInfo(reflect.Typeof(wireType{})).id
func init() {
// Some magic numbers to make sure there are no surprises.
- checkId(7, tWireType)
- checkId(9, mustGetTypeInfo(reflect.Typeof(commonType{})).id)
- checkId(11, mustGetTypeInfo(reflect.Typeof(structType{})).id)
- checkId(12, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
-
- // Complex was added after gob was written, so appears after the
- // fundamental types are built.
- tComplex = bootstrapType("complex", 0+0i, 15)
- decIgnoreOpMap[tComplex] = ignoreTwoUints
+ checkId(16, tWireType)
+ checkId(17, mustGetTypeInfo(reflect.Typeof(arrayType{})).id)
+ checkId(18, mustGetTypeInfo(reflect.Typeof(CommonType{})).id)
+ checkId(19, mustGetTypeInfo(reflect.Typeof(sliceType{})).id)
+ checkId(20, mustGetTypeInfo(reflect.Typeof(structType{})).id)
+ checkId(21, mustGetTypeInfo(reflect.Typeof(fieldType{})).id)
+ checkId(23, mustGetTypeInfo(reflect.Typeof(mapType{})).id)
builtinIdToType = make(map[typeId]gobType)
for k, v := range idToType {
@@ -116,26 +132,27 @@ func init() {
panic(fmt.Sprintln("nextId too large:", nextId))
}
nextId = firstUserId
+ registerBasics()
}
// Array type
type arrayType struct {
- commonType
+ CommonType
Elem typeId
Len int
}
func newArrayType(name string, elem gobType, length int) *arrayType {
- a := &arrayType{commonType{name: name}, elem.id(), length}
+ a := &arrayType{CommonType{Name: name}, elem.id(), length}
setTypeId(a)
return a
}
func (a *arrayType) safeString(seen map[typeId]bool) string {
- if seen[a._id] {
- return a.name
+ if seen[a.Id] {
+ return a.Name
}
- seen[a._id] = true
+ seen[a.Id] = true
return fmt.Sprintf("[%d]%s", a.Len, a.Elem.gobType().safeString(seen))
}
@@ -143,22 +160,22 @@ func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool))
// Map type
type mapType struct {
- commonType
+ CommonType
Key typeId
Elem typeId
}
func newMapType(name string, key, elem gobType) *mapType {
- m := &mapType{commonType{name: name}, key.id(), elem.id()}
+ m := &mapType{CommonType{Name: name}, key.id(), elem.id()}
setTypeId(m)
return m
}
func (m *mapType) safeString(seen map[typeId]bool) string {
- if seen[m._id] {
- return m.name
+ if seen[m.Id] {
+ return m.Name
}
- seen[m._id] = true
+ seen[m.Id] = true
key := m.Key.gobType().safeString(seen)
elem := m.Elem.gobType().safeString(seen)
return fmt.Sprintf("map[%s]%s", key, elem)
@@ -168,21 +185,21 @@ func (m *mapType) string() string { return m.safeString(make(map[typeId]bool)) }
// Slice type
type sliceType struct {
- commonType
+ CommonType
Elem typeId
}
func newSliceType(name string, elem gobType) *sliceType {
- s := &sliceType{commonType{name: name}, elem.id()}
+ s := &sliceType{CommonType{Name: name}, elem.id()}
setTypeId(s)
return s
}
func (s *sliceType) safeString(seen map[typeId]bool) string {
- if seen[s._id] {
- return s.name
+ if seen[s.Id] {
+ return s.Name
}
- seen[s._id] = true
+ seen[s.Id] = true
return fmt.Sprintf("[]%s", s.Elem.gobType().safeString(seen))
}
@@ -190,26 +207,26 @@ func (s *sliceType) string() string { return s.safeString(make(map[typeId]bool))
// Struct type
type fieldType struct {
- name string
- id typeId
+ Name string
+ Id typeId
}
type structType struct {
- commonType
- field []*fieldType
+ CommonType
+ Field []*fieldType
}
func (s *structType) safeString(seen map[typeId]bool) string {
if s == nil {
return "<nil>"
}
- if _, ok := seen[s._id]; ok {
- return s.name
+ if _, ok := seen[s.Id]; ok {
+ return s.Name
}
- seen[s._id] = true
- str := s.name + " = struct { "
- for _, f := range s.field {
- str += fmt.Sprintf("%s %s; ", f.name, f.id.gobType().safeString(seen))
+ seen[s.Id] = true
+ str := s.Name + " = struct { "
+ for _, f := range s.Field {
+ str += fmt.Sprintf("%s %s; ", f.Name, f.Id.gobType().safeString(seen))
}
str += "}"
return str
@@ -218,13 +235,13 @@ func (s *structType) safeString(seen map[typeId]bool) string {
func (s *structType) string() string { return s.safeString(make(map[typeId]bool)) }
func newStructType(name string) *structType {
- s := &structType{commonType{name: name}, nil}
+ s := &structType{CommonType{Name: name}, nil}
setTypeId(s)
return s
}
// Step through the indirections on a type to discover the base type.
-// Return the number of indirections.
+// Return the base type and the number of indirections.
func indirect(t reflect.Type) (rt reflect.Type, count int) {
rt = t
for {
@@ -259,6 +276,9 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
case *reflect.StringType:
return tString.gobType(), nil
+ case *reflect.InterfaceType:
+ return tInterface.gobType(), nil
+
case *reflect.ArrayType:
gt, err := getType("", t.Elem())
if err != nil {
@@ -300,7 +320,8 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
typ, _ := indirect(f.Type)
tname := typ.Name()
if tname == "" {
- tname = f.Type.String()
+ t, _ := indirect(f.Type)
+ tname = t.String()
}
gt, err := getType(tname, f.Type)
if err != nil {
@@ -308,7 +329,7 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
}
field[i] = &fieldType{f.Name, gt.id()}
}
- strType.field = field
+ strType.Field = field
return strType, nil
default:
@@ -320,14 +341,7 @@ func newTypeObject(name string, rt reflect.Type) (gobType, os.Error) {
// getType returns the Gob type describing the given reflect.Type.
// typeLock must be held.
func getType(name string, rt reflect.Type) (gobType, os.Error) {
- // Flatten the data structure by collapsing out pointers
- for {
- pt, ok := rt.(*reflect.PtrType)
- if !ok {
- break
- }
- rt = pt.Elem()
- }
+ rt, _ = indirect(rt)
typ, present := types[rt]
if present {
return typ, nil
@@ -341,7 +355,8 @@ func getType(name string, rt reflect.Type) (gobType, os.Error) {
func checkId(want, got typeId) {
if want != got {
- panic("bootstrap type wrong id: " + got.Name() + " " + got.string() + " not " + want.string())
+ fmt.Fprintf(os.Stderr, "checkId: %d should be %d\n", int(want), int(got))
+ panic("bootstrap type wrong id: " + got.name() + " " + got.string() + " not " + want.string())
}
}
@@ -352,7 +367,7 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
if present {
panic("bootstrap type already present: " + name + ", " + rt.String())
}
- typ := &commonType{name: name}
+ typ := &CommonType{Name: name}
types[rt] = typ
setTypeId(typ)
checkId(expect, nextId)
@@ -371,17 +386,28 @@ func bootstrapType(name string, e interface{}, expect typeId) typeId {
// To maintain binary compatibility, if you extend this type, always put
// the new fields last.
type wireType struct {
- arrayT *arrayType
- sliceT *sliceType
- structT *structType
- mapT *mapType
+ ArrayT *arrayType
+ SliceT *sliceType
+ StructT *structType
+ MapT *mapType
}
-func (w *wireType) name() string {
- if w.structT != nil {
- return w.structT.name
+func (w *wireType) string() string {
+ const unknown = "unknown type"
+ if w == nil {
+ return unknown
}
- return "unknown"
+ switch {
+ case w.ArrayT != nil:
+ return w.ArrayT.Name
+ case w.SliceT != nil:
+ return w.SliceT.Name
+ case w.StructT != nil:
+ return w.StructT.Name
+ case w.MapT != nil:
+ return w.MapT.Name
+ }
+ return unknown
}
type typeInfo struct {
@@ -410,16 +436,16 @@ func getTypeInfo(rt reflect.Type) (*typeInfo, os.Error) {
t := info.id.gobType()
switch typ := rt.(type) {
case *reflect.ArrayType:
- info.wire = &wireType{arrayT: t.(*arrayType)}
+ info.wire = &wireType{ArrayT: t.(*arrayType)}
case *reflect.MapType:
- info.wire = &wireType{mapT: t.(*mapType)}
+ info.wire = &wireType{MapT: t.(*mapType)}
case *reflect.SliceType:
// []byte == []uint8 is a special case handled separately
if typ.Elem().Kind() != reflect.Uint8 {
- info.wire = &wireType{sliceT: t.(*sliceType)}
+ info.wire = &wireType{SliceT: t.(*sliceType)}
}
case *reflect.StructType:
- info.wire = &wireType{structT: t.(*structType)}
+ info.wire = &wireType{StructT: t.(*structType)}
}
typeInfoMap[rt] = info
}
@@ -434,3 +460,82 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
}
return t
}
+
+var (
+ nameToConcreteType = make(map[string]reflect.Type)
+ concreteTypeToName = make(map[reflect.Type]string)
+)
+
+// RegisterName is like Register but uses the provided name rather than the
+// type's default.
+func RegisterName(name string, value interface{}) {
+ if name == "" {
+ // reserved for nil
+ panic("attempt to register empty name")
+ }
+ rt, _ := indirect(reflect.Typeof(value))
+ // Check for incompatible duplicates.
+ if t, ok := nameToConcreteType[name]; ok && t != rt {
+ panic("gob: registering duplicate types for " + name)
+ }
+ if n, ok := concreteTypeToName[rt]; ok && n != name {
+ panic("gob: registering duplicate names for " + rt.String())
+ }
+ // Store the name and type provided by the user....
+ nameToConcreteType[name] = reflect.Typeof(value)
+ // but the flattened type in the type table, since that's what decode needs.
+ concreteTypeToName[rt] = name
+}
+
+// Register records a type, identified by a value for that type, under its
+// internal type name. That name will identify the concrete type of a value
+// sent or received as an interface variable. Only types that will be
+// transferred as implementations of interface values need to be registered.
+// Expecting to be used only during initialization, it panics if the mapping
+// between types and names is not a bijection.
+func Register(value interface{}) {
+ // Default to printed representation for unnamed types
+ rt := reflect.Typeof(value)
+ name := rt.String()
+
+ // But for named types (or pointers to them), qualify with import path.
+ // Dereference one pointer looking for a named type.
+ star := ""
+ if rt.Name() == "" {
+ if pt, ok := rt.(*reflect.PtrType); ok {
+ star = "*"
+ rt = pt
+ }
+ }
+ if rt.Name() != "" {
+ if rt.PkgPath() == "" {
+ name = star + rt.Name()
+ } else {
+ name = star + rt.PkgPath() + "." + rt.Name()
+ }
+ }
+
+ RegisterName(name, value)
+}
+
+func registerBasics() {
+ Register(int(0))
+ Register(int8(0))
+ Register(int16(0))
+ Register(int32(0))
+ Register(int64(0))
+ Register(uint(0))
+ Register(uint8(0))
+ Register(uint16(0))
+ Register(uint32(0))
+ Register(uint64(0))
+ Register(float(0))
+ Register(float32(0))
+ Register(float64(0))
+ Register(complex(0i))
+ Register(complex64(0i))
+ Register(complex128(0i))
+ Register(false)
+ Register("")
+ Register([]byte(nil))
+}
diff --git a/src/pkg/gob/type_test.go b/src/pkg/gob/type_test.go
index 6acfa7135..106e4f10b 100644
--- a/src/pkg/gob/type_test.go
+++ b/src/pkg/gob/type_test.go
@@ -15,12 +15,12 @@ type typeT struct {
}
var basicTypes = []typeT{
- typeT{tBool, "bool"},
- typeT{tInt, "int"},
- typeT{tUint, "uint"},
- typeT{tFloat, "float"},
- typeT{tBytes, "bytes"},
- typeT{tString, "string"},
+ {tBool, "bool"},
+ {tInt, "int"},
+ {tUint, "uint"},
+ {tFloat, "float"},
+ {tBytes, "bytes"},
+ {tString, "string"},
}
func getTypeUnlocked(name string, rt reflect.Type) gobType {