From: Rob Pike Date: Tue, 29 Jun 2010 00:11:54 +0000 (-0700) Subject: gob: add DecodeValue and EncodeValue X-Git-Tag: weekly.2010-07-01~40 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=12a4d84371d6d60b715d2fca3fe9bb45d5ca7454;p=gostls13.git gob: add DecodeValue and EncodeValue R=rsc CC=golang-dev https://golang.org/cl/1698045 --- diff --git a/src/pkg/gob/codec_test.go b/src/pkg/gob/codec_test.go index 49a13e84d7..2caaaa43f8 100644 --- a/src/pkg/gob/codec_test.go +++ b/src/pkg/gob/codec_test.go @@ -1028,7 +1028,7 @@ func TestInvalidField(t *testing.T) { var bad0 Bad0 bad0.inter = 17 b := new(bytes.Buffer) - err := encode(b, &bad0) + err := encode(b, reflect.NewValue(&bad0)) if err == nil { t.Error("expected error; got none") } else if strings.Index(err.String(), "interface") < 0 { diff --git a/src/pkg/gob/decode.go b/src/pkg/gob/decode.go index 51e4399000..a70799e9a7 100644 --- a/src/pkg/gob/decode.go +++ b/src/pkg/gob/decode.go @@ -918,9 +918,9 @@ func (dec *Decoder) getIgnoreEnginePtr(wireId typeId) (enginePtr **decEngine, er return } -func (dec *Decoder) decode(wireId typeId, e interface{}) os.Error { +func (dec *Decoder) decode(wireId typeId, val reflect.Value) os.Error { // Dereference down to the underlying struct type. - rt, indir := indirect(reflect.Typeof(e)) + rt, indir := indirect(val.Type()) enginePtr, err := dec.getDecEnginePtr(wireId, rt) if err != nil { return err @@ -931,9 +931,9 @@ func (dec *Decoder) decode(wireId typeId, e interface{}) os.Error { name := rt.Name() return os.ErrorString("gob: type mismatch: no fields matched compiling decoder for " + name) } - return decodeStruct(engine, st, dec.state.b, uintptr(reflect.NewValue(e).Addr()), indir) + return decodeStruct(engine, st, dec.state.b, uintptr(val.Addr()), indir) } - return decodeSingle(engine, rt, dec.state.b, uintptr(reflect.NewValue(e).Addr()), indir) + return 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 caec517121..5ba2750d27 100644 --- a/src/pkg/gob/decoder.go +++ b/src/pkg/gob/decoder.go @@ -47,7 +47,7 @@ func (dec *Decoder) recvType(id typeId) { // Type: wire := new(wireType) - dec.state.err = dec.decode(tWireType, wire) + dec.state.err = dec.decode(tWireType, reflect.NewValue(wire)) // Remember we've seen this type. dec.wireType[id] = wire } @@ -55,7 +55,7 @@ func (dec *Decoder) recvType(id typeId) { // Decode reads the next value from the connection and stores // it in the data represented by the empty interface value. // The value underlying e must be the correct type for the next -// data item received. +// data item received, which must be a pointer. func (dec *Decoder) Decode(e interface{}) os.Error { // If e represents a value, the answer won't get back to the // caller. Make sure it's a pointer. @@ -63,7 +63,14 @@ func (dec *Decoder) Decode(e interface{}) os.Error { dec.state.err = os.ErrorString("gob: attempt to decode into a non-pointer") return dec.state.err } + return dec.DecodeValue(reflect.NewValue(e)) +} +// 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() @@ -114,7 +121,7 @@ func (dec *Decoder) Decode(e interface{}) os.Error { dec.state.err = errBadType break } - dec.state.err = dec.decode(id, e) + dec.state.err = dec.decode(id, value) break } return dec.state.err diff --git a/src/pkg/gob/encode.go b/src/pkg/gob/encode.go index a7d44ecc2b..57af146c04 100644 --- a/src/pkg/gob/encode.go +++ b/src/pkg/gob/encode.go @@ -798,12 +798,11 @@ func getEncEngine(rt reflect.Type) (*encEngine, os.Error) { return info.encoder, err } -func encode(b *bytes.Buffer, e interface{}) os.Error { +func encode(b *bytes.Buffer, value reflect.Value) os.Error { // Dereference down to the underlying object. - rt, indir := indirect(reflect.Typeof(e)) - v := reflect.NewValue(e) + rt, indir := indirect(value.Type()) for i := 0; i < indir; i++ { - v = reflect.Indirect(v) + value = reflect.Indirect(value) } typeLock.Lock() engine, err := getEncEngine(rt) @@ -811,8 +810,8 @@ func encode(b *bytes.Buffer, e interface{}) os.Error { if err != nil { return err } - if _, ok := v.(*reflect.StructValue); ok { - return encodeStruct(engine, b, v.Addr()) + if _, ok := value.(*reflect.StructValue); ok { + return encodeStruct(engine, b, value.Addr()) } - return encodeSingle(engine, b, v.Addr()) + return encodeSingle(engine, b, value.Addr()) } diff --git a/src/pkg/gob/encoder.go b/src/pkg/gob/encoder.go index 28cf6f6e0c..aba8d0e5c5 100644 --- a/src/pkg/gob/encoder.go +++ b/src/pkg/gob/encoder.go @@ -115,7 +115,7 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) { // Id: encodeInt(enc.state, -int64(info.id)) // Type: - encode(enc.state.b, info.wire) + encode(enc.state.b, reflect.NewValue(info.wire)) enc.send() if enc.state.err != nil { return @@ -140,13 +140,19 @@ func (enc *Encoder) sendType(origt reflect.Type) (sent bool) { // Encode transmits the data item represented by the empty interface value, // guaranteeing that all necessary type information has been transmitted first. 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(reflect.Typeof(e)) + 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 { @@ -181,7 +187,7 @@ func (enc *Encoder) Encode(e interface{}) os.Error { encodeInt(enc.state, int64(enc.sent[rt])) // Encode the object. - err := encode(enc.state.b, e) + err := encode(enc.state.b, value) if err != nil { enc.setError(err) } else {