diff options
author | David Symonds <dsymonds@golang.org> | 2013-06-20 13:22:17 +1000 |
---|---|---|
committer | David Symonds <dsymonds@golang.org> | 2013-06-20 13:22:17 +1000 |
commit | 2ce8ed485f701935d0375594026a68121faf01f5 (patch) | |
tree | 1294e29ac4af6b6831dd5116c2d9da7d9fb09d2a | |
parent | 6677c3e01836e09b5768997bb132cafed188705d (diff) | |
download | protobuf-2ce8ed485f701935d0375594026a68121faf01f5.tar.gz |
goprotobuf: Use already-allocated nested messages if they exist.
This maintains the semantics that unmarshaling the concatenation of two
encoded messages is equivalent to merging those messages.
R=r
CC=golang-dev
https://codereview.appspot.com/10409046
-rw-r--r-- | proto/all_test.go | 43 | ||||
-rw-r--r-- | proto/decode.go | 19 | ||||
-rw-r--r-- | protoc-gen-go/generator/generator.go | 2 |
3 files changed, 58 insertions, 6 deletions
diff --git a/proto/all_test.go b/proto/all_test.go index 7307b1a..ca765e7 100644 --- a/proto/all_test.go +++ b/proto/all_test.go @@ -1577,6 +1577,49 @@ func TestMessageSetMarshalOrder(t *testing.T) { } } +func TestUnmarshalMergesMessages(t *testing.T) { + // If a nested message occurs twice in the input, + // the fields should be merged when decoding. + a := &OtherMessage{ + Key: Int64(123), + Inner: &InnerMessage{ + Host: String("polhode"), + Port: Int32(1234), + }, + } + aData, err := Marshal(a) + if err != nil { + t.Fatalf("Marshal(a): %v", err) + } + b := &OtherMessage{ + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Connected: Bool(true), + }, + } + bData, err := Marshal(b) + if err != nil { + t.Fatalf("Marshal(b): %v", err) + } + want := &OtherMessage{ + Key: Int64(123), + Weight: Float32(1.2), + Inner: &InnerMessage{ + Host: String("herpolhode"), + Port: Int32(1234), + Connected: Bool(true), + }, + } + got := new(OtherMessage) + if err := Unmarshal(append(aData, bData...), got); err != nil { + t.Fatalf("Unmarshal: %v", err) + } + if !Equal(got, want) { + t.Errorf("\n got %v\nwant %v", got, want) + } +} + func fuzzUnmarshal(t *testing.T, data []byte) { defer func() { if e := recover(); e != nil { diff --git a/proto/decode.go b/proto/decode.go index 9f2eb0f..e0e9445 100644 --- a/proto/decode.go +++ b/proto/decode.go @@ -621,8 +621,12 @@ func (o *Buffer) dec_slice_slice_byte(p *Properties, base structPointer) error { // Decode a group. func (o *Buffer) dec_struct_group(p *Properties, base structPointer) error { - bas := toStructPointer(reflect.New(p.stype)) - structPointer_SetStructPointer(base, p.field, bas) + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } return o.unmarshalType(p.stype, p.sprop, true, bas) } @@ -633,13 +637,16 @@ func (o *Buffer) dec_struct_message(p *Properties, base structPointer) (err erro return e } - v := reflect.New(p.stype) - bas := toStructPointer(v) - structPointer_SetStructPointer(base, p.field, bas) + bas := structPointer_GetStructPointer(base, p.field) + if structPointer_IsNil(bas) { + // allocate new nested message + bas = toStructPointer(reflect.New(p.stype)) + structPointer_SetStructPointer(base, p.field, bas) + } // If the object can unmarshal itself, let it. if p.isMarshaler { - iv := v.Interface() + iv := structPointer_Interface(bas, p.stype) return iv.(Unmarshaler).Unmarshal(raw) } diff --git a/protoc-gen-go/generator/generator.go b/protoc-gen-go/generator/generator.go index c647131..3ad2d13 100644 --- a/protoc-gen-go/generator/generator.go +++ b/protoc-gen-go/generator/generator.go @@ -866,6 +866,8 @@ func (g *Generator) P(str ...interface{}) { g.WriteString(fmt.Sprintf("%d", s)) case *int32: g.WriteString(fmt.Sprintf("%d", *s)) + case *int64: + g.WriteString(fmt.Sprintf("%d", *s)) case float64: g.WriteString(fmt.Sprintf("%g", s)) case *float64: |