1
0
mirror of https://github.com/golang/go synced 2024-11-21 22:34:48 -07:00

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
This commit is contained in:
Rob Pike 2011-03-04 14:18:52 -08:00
parent 99f17aa0b8
commit 9442e9518d
4 changed files with 52 additions and 24 deletions

View File

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

View File

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

View File

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

View File

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