Просмотр исходного кода

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
David Symonds 12 лет назад
Родитель
Сommit
2ce8ed485f
3 измененных файлов с 58 добавлено и 6 удалено
  1. 43 0
      proto/all_test.go
  2. 13 6
      proto/decode.go
  3. 2 0
      protoc-gen-go/generator/generator.go

+ 43 - 0
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 {

+ 13 - 6
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)
 	}
 

+ 2 - 0
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: