aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Pike <r@golang.org>2011-03-04 14:18:52 -0800
committerRob Pike <r@golang.org>2011-03-04 14:18:52 -0800
commit9442e9518dc54c0444e44eb0898c6c7ce4d28a4f (patch)
tree3a47583d0952f2c4be0358b4e88724245c9784ab
parent99f17aa0b8af774e3639d00d4bc95a2c3a7d153a (diff)
downloadgo-9442e9518dc54c0444e44eb0898c6c7ce4d28a4f.tar.gz
go-9442e9518dc54c0444e44eb0898c6c7ce4d28a4f.zip
gob: enable the GobEncoder and GobDecoder interfaces.
These allow data items to control their own representation. For now, the implementation requires that the value passed to Encode and Decode must be exactly the type of the methods' receiver; it cannot be, for instance, T if the receiver is of type *T. This will be fixed in a later CL. R=rsc CC=golang-dev https://golang.org/cl/4235051
-rw-r--r--src/pkg/gob/decode.go2
-rw-r--r--src/pkg/gob/encode.go2
-rw-r--r--src/pkg/gob/gobencdec_test.go18
-rw-r--r--src/pkg/gob/type.go54
4 files changed, 52 insertions, 24 deletions
diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go
index 37f49312a8..34689a8ef2 100644
--- a/src/pkg/gob/decode.go
+++ b/src/pkg/gob/decode.go
@@ -738,7 +738,7 @@ func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value, index
error(err)
}
// We know it's a GobDecoder, so just call the method directly.
- err = v.Interface().(_GobDecoder)._GobDecode(b)
+ err = v.Interface().(GobDecoder).GobDecode(b)
if err != nil {
error(err)
}
diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go
index d69e734ff9..773b348423 100644
--- a/src/pkg/gob/encode.go
+++ b/src/pkg/gob/encode.go
@@ -449,7 +449,7 @@ func (enc *Encoder) encodeInterface(b *bytes.Buffer, iv *reflect.InterfaceValue)
func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int) {
// TODO: should we catch panics from the called method?
// We know it's a GobEncoder, so just call the method directly.
- data, err := v.Interface().(_GobEncoder)._GobEncode()
+ data, err := v.Interface().(GobEncoder).GobEncode()
if err != nil {
error(err)
}
diff --git a/src/pkg/gob/gobencdec_test.go b/src/pkg/gob/gobencdec_test.go
index dbe7d3fe31..82ca68170e 100644
--- a/src/pkg/gob/gobencdec_test.go
+++ b/src/pkg/gob/gobencdec_test.go
@@ -30,7 +30,7 @@ type ValueGobber string // encodes with a value, decodes with a pointer.
// The relevant methods
-func (g *ByteStruct) _GobEncode() ([]byte, os.Error) {
+func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
b := make([]byte, 3)
b[0] = g.a
b[1] = g.a + 1
@@ -38,7 +38,7 @@ func (g *ByteStruct) _GobEncode() ([]byte, os.Error) {
return b, nil
}
-func (g *ByteStruct) _GobDecode(data []byte) os.Error {
+func (g *ByteStruct) GobDecode(data []byte) os.Error {
if g == nil {
return os.ErrorString("NIL RECEIVER")
}
@@ -55,11 +55,11 @@ func (g *ByteStruct) _GobDecode(data []byte) os.Error {
return nil
}
-func (g *StringStruct) _GobEncode() ([]byte, os.Error) {
+func (g *StringStruct) GobEncode() ([]byte, os.Error) {
return []byte(g.s), nil
}
-func (g *StringStruct) _GobDecode(data []byte) os.Error {
+func (g *StringStruct) GobDecode(data []byte) os.Error {
// Expect N sequential-valued bytes.
if len(data) == 0 {
return os.EOF
@@ -74,20 +74,20 @@ func (g *StringStruct) _GobDecode(data []byte) os.Error {
return nil
}
-func (g *Gobber) _GobEncode() ([]byte, os.Error) {
+func (g *Gobber) GobEncode() ([]byte, os.Error) {
return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
}
-func (g *Gobber) _GobDecode(data []byte) os.Error {
+func (g *Gobber) GobDecode(data []byte) os.Error {
_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
return err
}
-func (v ValueGobber) _GobEncode() ([]byte, os.Error) {
+func (v ValueGobber) GobEncode() ([]byte, os.Error) {
return []byte(fmt.Sprintf("VALUE=%s", v)), nil
}
-func (v *ValueGobber) _GobDecode(data []byte) os.Error {
+func (v *ValueGobber) GobDecode(data []byte) os.Error {
_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
return err
}
@@ -232,7 +232,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
x := &GobTest2{}
err = dec.Decode(x)
if err == nil {
- t.Fatal("expected decode error for mistmatched fields (encoder to non-decoder)")
+ t.Fatal("expected decode error for mismatched fields (encoder to non-decoder)")
}
if strings.Index(err.String(), "type") < 0 {
t.Fatal("expected type error; got", err)
diff --git a/src/pkg/gob/type.go b/src/pkg/gob/type.go
index 05d5f122e9..39744c90b4 100644
--- a/src/pkg/gob/type.go
+++ b/src/pkg/gob/type.go
@@ -18,8 +18,8 @@ type userTypeInfo struct {
user reflect.Type // the type the user handed us
base reflect.Type // the base type after all indirections
indir int // number of indirections to reach the base type
- isGobEncoder bool // does the type implement _GobEncoder?
- isGobDecoder bool // does the type implement _GobDecoder?
+ isGobEncoder bool // does the type implement GobEncoder?
+ isGobDecoder bool // does the type implement GobDecoder?
encIndir int8 // number of indirections to reach the receiver type; may be negative
decIndir int8 // number of indirections to reach the receiver type; may be negative
}
@@ -86,8 +86,8 @@ func validUserType(rt reflect.Type) (ut *userTypeInfo, err os.Error) {
}
const (
- gobEncodeMethodName = "_GobEncode"
- gobDecodeMethodName = "_GobDecode"
+ gobEncodeMethodName = "GobEncode"
+ gobDecodeMethodName = "GobDecode"
)
// implementsGobEncoder reports whether the type implements the interface. It also
@@ -104,7 +104,7 @@ func implementsGobEncoder(rt reflect.Type) (implements bool, indir int8) {
// dereferencing to the base type until we find an implementation.
for {
if rt.NumMethod() > 0 { // avoid allocations etc. unless there's some chance
- if _, ok := reflect.MakeZero(rt).Interface().(_GobEncoder); ok {
+ if _, ok := reflect.MakeZero(rt).Interface().(GobEncoder); ok {
return true, indir
}
}
@@ -132,7 +132,7 @@ func implementsGobDecoder(rt reflect.Type) (implements bool, indir int8) {
// dereferencing to the base type until we find an implementation.
for {
if rt.NumMethod() > 0 { // avoid allocations etc. unless there's some chance
- if _, ok := reflect.MakeZero(rt).Interface().(_GobDecoder); ok {
+ if _, ok := reflect.MakeZero(rt).Interface().(GobDecoder); ok {
return true, indir
}
}
@@ -306,7 +306,7 @@ func (a *arrayType) safeString(seen map[typeId]bool) string {
func (a *arrayType) string() string { return a.safeString(make(map[typeId]bool)) }
-// GobEncoder type (something that implements the _GobEncoder interface)
+// GobEncoder type (something that implements the GobEncoder interface)
type gobEncoderType struct {
CommonType
}
@@ -695,12 +695,40 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
return t
}
-type _GobEncoder interface {
- _GobEncode() ([]byte, os.Error)
-} // use _ prefix until we get it working properly
-type _GobDecoder interface {
- _GobDecode([]byte) os.Error
-} // use _ prefix until we get it working properly
+// GobEncoder is the interface describing data that provides its own
+// representation for encoding values for transmission to a GobDecoder.
+// A type that implements GobEncoder and GobDecoder has complete
+// control over the representation of its data and may therefore
+// contain things such as private fields, channels, and functions,
+// which are not usually transmissable in gob streams.
+//
+// Note: Since gobs can be stored permanently, It is good design
+// to guarantee the encoding used by a GobEncoder is stable as the
+// software evolves. For instance, it might make sense for GobEncode
+// to include a version number in the encoding.
+//
+// Note: At the moment, the type implementing GobEncoder must
+// be exactly the type passed to Encode. For example, if *T implements
+// GobEncoder, the data item must be of type *T, not T or **T.
+type GobEncoder interface {
+ // GobEncode returns a byte slice representing the encoding of the
+ // receiver for transmission to a GobDecoder, usually of the same
+ // concrete type.
+ GobEncode() ([]byte, os.Error)
+}
+
+// GobDecoder is the interface describing data that provides its own
+// routine for decoding transmitted values sent by a GobEncoder.
+//
+// Note: At the moment, the type implementing GobDecoder must
+// be exactly the type passed to Decode. For example, if *T implements
+// GobDecoder, the data item must be of type *T, not T or **T.
+type GobDecoder interface {
+ // GobDecode overwrites the receiver, which must be a pointer,
+ // with the value represented by the byte slice, which was written
+ // by GobEncode, usually for the same concrete type.
+ GobDecode([]byte) os.Error
+}
var (
nameToConcreteType = make(map[string]reflect.Type)