aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Symonds <dsymonds@golang.org>2013-06-20 13:22:17 +1000
committerDavid Symonds <dsymonds@golang.org>2013-06-20 13:22:17 +1000
commit2ce8ed485f701935d0375594026a68121faf01f5 (patch)
tree1294e29ac4af6b6831dd5116c2d9da7d9fb09d2a
parent6677c3e01836e09b5768997bb132cafed188705d (diff)
downloadprotobuf-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.go43
-rw-r--r--proto/decode.go19
-rw-r--r--protoc-gen-go/generator/generator.go2
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: