|
|
@@ -75,12 +75,13 @@ func Merge(dst, src Message) {
|
|
|
}
|
|
|
|
|
|
func mergeStruct(out, in reflect.Value) {
|
|
|
+ sprop := GetProperties(in.Type())
|
|
|
for i := 0; i < in.NumField(); i++ {
|
|
|
f := in.Type().Field(i)
|
|
|
if strings.HasPrefix(f.Name, "XXX_") {
|
|
|
continue
|
|
|
}
|
|
|
- mergeAny(out.Field(i), in.Field(i))
|
|
|
+ mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
|
|
|
}
|
|
|
|
|
|
if emIn, ok := in.Addr().Interface().(extendableProto); ok {
|
|
|
@@ -98,7 +99,10 @@ func mergeStruct(out, in reflect.Value) {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-func mergeAny(out, in reflect.Value) {
|
|
|
+// mergeAny performs a merge between two values of the same type.
|
|
|
+// viaPtr indicates whether the values were indirected through a pointer (implying proto2).
|
|
|
+// prop is set if this is a struct field (it may be nil).
|
|
|
+func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
|
|
|
if in.Type() == protoMessageType {
|
|
|
if !in.IsNil() {
|
|
|
if out.IsNil() {
|
|
|
@@ -112,6 +116,9 @@ func mergeAny(out, in reflect.Value) {
|
|
|
switch in.Kind() {
|
|
|
case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
|
|
|
reflect.String, reflect.Uint32, reflect.Uint64:
|
|
|
+ if !viaPtr && isProto3Zero(in) {
|
|
|
+ return
|
|
|
+ }
|
|
|
out.Set(in)
|
|
|
case reflect.Map:
|
|
|
if in.Len() == 0 {
|
|
|
@@ -127,7 +134,7 @@ func mergeAny(out, in reflect.Value) {
|
|
|
switch elemKind {
|
|
|
case reflect.Ptr:
|
|
|
val = reflect.New(in.Type().Elem().Elem())
|
|
|
- mergeAny(val, in.MapIndex(key))
|
|
|
+ mergeAny(val, in.MapIndex(key), false, nil)
|
|
|
case reflect.Slice:
|
|
|
val = in.MapIndex(key)
|
|
|
val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
|
|
|
@@ -143,13 +150,21 @@ func mergeAny(out, in reflect.Value) {
|
|
|
if out.IsNil() {
|
|
|
out.Set(reflect.New(in.Elem().Type()))
|
|
|
}
|
|
|
- mergeAny(out.Elem(), in.Elem())
|
|
|
+ mergeAny(out.Elem(), in.Elem(), true, nil)
|
|
|
case reflect.Slice:
|
|
|
if in.IsNil() {
|
|
|
return
|
|
|
}
|
|
|
if in.Type().Elem().Kind() == reflect.Uint8 {
|
|
|
// []byte is a scalar bytes field, not a repeated field.
|
|
|
+
|
|
|
+ // Edge case: if this is in a proto3 message, a zero length
|
|
|
+ // bytes field is considered the zero value, and should not
|
|
|
+ // be merged.
|
|
|
+ if prop != nil && prop.proto3 && in.Len() == 0 {
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
// Make a deep copy.
|
|
|
// Append to []byte{} instead of []byte(nil) so that we never end up
|
|
|
// with a nil result.
|
|
|
@@ -167,7 +182,7 @@ func mergeAny(out, in reflect.Value) {
|
|
|
default:
|
|
|
for i := 0; i < n; i++ {
|
|
|
x := reflect.Indirect(reflect.New(in.Type().Elem()))
|
|
|
- mergeAny(x, in.Index(i))
|
|
|
+ mergeAny(x, in.Index(i), false, nil)
|
|
|
out.Set(reflect.Append(out, x))
|
|
|
}
|
|
|
}
|
|
|
@@ -184,7 +199,7 @@ func mergeExtension(out, in map[int32]Extension) {
|
|
|
eOut := Extension{desc: eIn.desc}
|
|
|
if eIn.value != nil {
|
|
|
v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
|
|
|
- mergeAny(v, reflect.ValueOf(eIn.value))
|
|
|
+ mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
|
|
|
eOut.value = v.Interface()
|
|
|
}
|
|
|
if eIn.enc != nil {
|