1
0
mirror of https://github.com/golang/go synced 2024-11-22 01:04:40 -07:00

gob: allow Decode(nil) and have it just discard the next value.

Fixes #1489.

R=rsc
CC=golang-dev
https://golang.org/cl/4187046
This commit is contained in:
Rob Pike 2011-02-12 18:03:54 -08:00
parent bab5536af6
commit ea46bda72b
2 changed files with 63 additions and 3 deletions

View File

@ -153,9 +153,13 @@ func (dec *Decoder) decodeTypeSequence(isInterface bool) typeId {
// Decode reads the next value from the connection and stores // Decode reads the next value from the connection and stores
// it in the data represented by the empty interface value. // it in the data represented by the empty interface value.
// The value underlying e must be the correct type for the next // If e is nil, the value will be discarded. Otherwise,
// the value underlying e must either be the correct type for the next
// data item received, and must be a pointer. // data item received, and must be a pointer.
func (dec *Decoder) Decode(e interface{}) os.Error { func (dec *Decoder) Decode(e interface{}) os.Error {
if e == nil {
return dec.DecodeValue(nil)
}
value := reflect.NewValue(e) value := reflect.NewValue(e)
// If e represents a value as opposed to a pointer, the answer won't // 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. // get back to the caller. Make sure it's a pointer.
@ -169,7 +173,8 @@ func (dec *Decoder) Decode(e interface{}) os.Error {
// DecodeValue reads the next value from the connection and stores // DecodeValue reads the next value from the connection and stores
// it in the data represented by the reflection value. // it in the data represented by the reflection value.
// The value must be the correct type for the next // The value must be the correct type for the next
// data item received. // data item received, or it may be nil, which means the
// value will be discarded.
func (dec *Decoder) DecodeValue(value reflect.Value) os.Error { func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
// Make sure we're single-threaded through here. // Make sure we're single-threaded through here.
dec.mutex.Lock() dec.mutex.Lock()
@ -179,8 +184,12 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
dec.err = nil dec.err = nil
id := dec.decodeTypeSequence(false) id := dec.decodeTypeSequence(false)
if id >= 0 { if id >= 0 {
// A nil value means "ignore the data". Since it's already read into
// the decoder's buffer, all we need to do is not bother to decode it.
if value != nil {
dec.err = dec.decodeValue(id, value) dec.err = dec.decodeValue(id, value)
} }
}
return dec.err return dec.err
} }

View File

@ -384,6 +384,57 @@ func TestInterfaceIndirect(t *testing.T) {
} }
} }
func TestDecodeIntoEmptyStruct(t *testing.T) {
type Empty struct{}
empty := &Empty{}
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(&struct{ A int }{23})
if err != nil {
t.Fatal("encode error:", err)
}
dec := NewDecoder(b)
err = dec.Decode(empty)
if err != nil {
t.Fatal("encode error:", err)
}
}
func TestStructDecodeIntoNil(t *testing.T) {
nonempty := &struct{ A int }{23}
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode(nonempty)
if err != nil {
t.Fatal("encode error:", err)
}
dec := NewDecoder(b)
err = dec.Decode(nil)
if err != nil {
t.Fatal("encode error:", err)
}
if b.Len() != 0 {
t.Fatalf("%d bytes remain after decode", b.Len())
}
}
func TestSingletonDecodeIntoNil(t *testing.T) {
b := new(bytes.Buffer)
enc := NewEncoder(b)
err := enc.Encode("hello world")
if err != nil {
t.Fatal("encode error:", err)
}
dec := NewDecoder(b)
err = dec.Decode(nil)
if err != nil {
t.Fatal("encode error:", err)
}
if b.Len() != 0 {
t.Fatalf("%d bytes remain after decode", b.Len())
}
}
// Another bug from golang-nuts, involving nested interfaces. // Another bug from golang-nuts, involving nested interfaces.
type Bug0Outer struct { type Bug0Outer struct {
Bug0Field interface{} Bug0Field interface{}