mirror of
https://github.com/golang/go
synced 2024-11-24 21:10:04 -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:
parent
99f17aa0b8
commit
9442e9518d
@ -738,7 +738,7 @@ func (dec *Decoder) decodeGobDecoder(state *decoderState, v reflect.Value, index
|
|||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
// We know it's a GobDecoder, so just call the method directly.
|
// 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 {
|
if err != nil {
|
||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
|
@ -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) {
|
func (enc *Encoder) encodeGobEncoder(b *bytes.Buffer, v reflect.Value, index int) {
|
||||||
// TODO: should we catch panics from the called method?
|
// TODO: should we catch panics from the called method?
|
||||||
// We know it's a GobEncoder, so just call the method directly.
|
// 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 {
|
if err != nil {
|
||||||
error(err)
|
error(err)
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ type ValueGobber string // encodes with a value, decodes with a pointer.
|
|||||||
|
|
||||||
// The relevant methods
|
// The relevant methods
|
||||||
|
|
||||||
func (g *ByteStruct) _GobEncode() ([]byte, os.Error) {
|
func (g *ByteStruct) GobEncode() ([]byte, os.Error) {
|
||||||
b := make([]byte, 3)
|
b := make([]byte, 3)
|
||||||
b[0] = g.a
|
b[0] = g.a
|
||||||
b[1] = g.a + 1
|
b[1] = g.a + 1
|
||||||
@ -38,7 +38,7 @@ func (g *ByteStruct) _GobEncode() ([]byte, os.Error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *ByteStruct) _GobDecode(data []byte) os.Error {
|
func (g *ByteStruct) GobDecode(data []byte) os.Error {
|
||||||
if g == nil {
|
if g == nil {
|
||||||
return os.ErrorString("NIL RECEIVER")
|
return os.ErrorString("NIL RECEIVER")
|
||||||
}
|
}
|
||||||
@ -55,11 +55,11 @@ func (g *ByteStruct) _GobDecode(data []byte) os.Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *StringStruct) _GobEncode() ([]byte, os.Error) {
|
func (g *StringStruct) GobEncode() ([]byte, os.Error) {
|
||||||
return []byte(g.s), nil
|
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.
|
// Expect N sequential-valued bytes.
|
||||||
if len(data) == 0 {
|
if len(data) == 0 {
|
||||||
return os.EOF
|
return os.EOF
|
||||||
@ -74,20 +74,20 @@ func (g *StringStruct) _GobDecode(data []byte) os.Error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *Gobber) _GobEncode() ([]byte, os.Error) {
|
func (g *Gobber) GobEncode() ([]byte, os.Error) {
|
||||||
return []byte(fmt.Sprintf("VALUE=%d", *g)), nil
|
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))
|
_, err := fmt.Sscanf(string(data), "VALUE=%d", (*int)(g))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v ValueGobber) _GobEncode() ([]byte, os.Error) {
|
func (v ValueGobber) GobEncode() ([]byte, os.Error) {
|
||||||
return []byte(fmt.Sprintf("VALUE=%s", v)), nil
|
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))
|
_, err := fmt.Sscanf(string(data), "VALUE=%s", (*string)(v))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -232,7 +232,7 @@ func TestGobEncoderFieldTypeError(t *testing.T) {
|
|||||||
x := &GobTest2{}
|
x := &GobTest2{}
|
||||||
err = dec.Decode(x)
|
err = dec.Decode(x)
|
||||||
if err == nil {
|
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 {
|
if strings.Index(err.String(), "type") < 0 {
|
||||||
t.Fatal("expected type error; got", err)
|
t.Fatal("expected type error; got", err)
|
||||||
|
@ -18,8 +18,8 @@ type userTypeInfo struct {
|
|||||||
user reflect.Type // the type the user handed us
|
user reflect.Type // the type the user handed us
|
||||||
base reflect.Type // the base type after all indirections
|
base reflect.Type // the base type after all indirections
|
||||||
indir int // number of indirections to reach the base type
|
indir int // number of indirections to reach the base type
|
||||||
isGobEncoder bool // does the type implement _GobEncoder?
|
isGobEncoder bool // does the type implement GobEncoder?
|
||||||
isGobDecoder bool // does the type implement _GobDecoder?
|
isGobDecoder bool // does the type implement GobDecoder?
|
||||||
encIndir int8 // number of indirections to reach the receiver type; may be negative
|
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
|
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 (
|
const (
|
||||||
gobEncodeMethodName = "_GobEncode"
|
gobEncodeMethodName = "GobEncode"
|
||||||
gobDecodeMethodName = "_GobDecode"
|
gobDecodeMethodName = "GobDecode"
|
||||||
)
|
)
|
||||||
|
|
||||||
// implementsGobEncoder reports whether the type implements the interface. It also
|
// 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.
|
// dereferencing to the base type until we find an implementation.
|
||||||
for {
|
for {
|
||||||
if rt.NumMethod() > 0 { // avoid allocations etc. unless there's some chance
|
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
|
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.
|
// dereferencing to the base type until we find an implementation.
|
||||||
for {
|
for {
|
||||||
if rt.NumMethod() > 0 { // avoid allocations etc. unless there's some chance
|
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
|
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)) }
|
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 {
|
type gobEncoderType struct {
|
||||||
CommonType
|
CommonType
|
||||||
}
|
}
|
||||||
@ -695,12 +695,40 @@ func mustGetTypeInfo(rt reflect.Type) *typeInfo {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
type _GobEncoder interface {
|
// GobEncoder is the interface describing data that provides its own
|
||||||
_GobEncode() ([]byte, os.Error)
|
// representation for encoding values for transmission to a GobDecoder.
|
||||||
} // use _ prefix until we get it working properly
|
// A type that implements GobEncoder and GobDecoder has complete
|
||||||
type _GobDecoder interface {
|
// control over the representation of its data and may therefore
|
||||||
_GobDecode([]byte) os.Error
|
// contain things such as private fields, channels, and functions,
|
||||||
} // use _ prefix until we get it working properly
|
// 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 (
|
var (
|
||||||
nameToConcreteType = make(map[string]reflect.Type)
|
nameToConcreteType = make(map[string]reflect.Type)
|
||||||
|
Loading…
Reference in New Issue
Block a user