// Copyright 2019 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package proto import ( "google.golang.org/protobuf/internal/pragma" "google.golang.org/protobuf/reflect/protoreflect" ) // MergeOptions configures the merger. // // Example usage: // MergeOptions{Shallow: true}.Merge(dst, src) type MergeOptions struct { pragma.NoUnkeyedLiterals // Shallow configures Merge to shallow copy messages, lists, and maps // instead of allocating new ones in the destination if it does not already // have one populated. Scalar bytes are copied by reference. // If true, Merge must be given messages of the same concrete type. // // If false, Merge is guaranteed to produce deep copies of all mutable // objects from the source into the destination. Since scalar bytes are // mutable they are deep copied as a result. // // Invariant: // var dst1, dst2 Message = ... // Equal(dst1, dst2) // assume equal initially // MergeOptions{Shallow: true}.Merge(dst1, src) // MergeOptions{Shallow: false}.Merge(dst2, src) // Equal(dst1, dst2) // equal regardless of whether Shallow is specified Shallow bool } // Clone returns a deep copy of m. // See MergeOptions.Clone for details. func Clone(m Message) Message { return MergeOptions{}.Clone(m) } // Merge merges src into dst, which must be messages with the same descriptor. // See MergeOptions.Merge for details. func Merge(dst, src Message) { MergeOptions{}.Merge(dst, src) } // Clone returns a copy of m. // If Shallow is specified it makes a new message and shallow copies m into it. // If the top-level message is invalid, it returns an invalid message as well. func (o MergeOptions) Clone(m Message) Message { // NOTE: Most usages of Clone assume the following properties: // t := reflect.TypeOf(m) // t == reflect.TypeOf(m.ProtoReflect().New().Interface()) // t == reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()) // // Embedding protobuf messages breaks this since the parent type will have // a forwarded ProtoReflect method, but the Interface method will return // the underlying embedded message type. return o.cloneMessage(m.ProtoReflect()).Interface() } func (o MergeOptions) cloneMessage(src protoreflect.Message) (dst protoreflect.Message) { if !src.IsValid() { return src.Type().Zero() } dst = src.New() o.mergeMessage(dst, src) return dst } // Merge merges src into dst, which must be messages with the same descriptor. // // Populated scalar fields in src are copied to dst, while populated // singular messages in src are merged into dst by recursively calling Merge. // The elements of every list field in src is appended to the corresponded // list fields in dst. The entries of every map field in src is copied into // the corresponding map field in dst, possibly replacing existing entries. // The unknown fields of src are appended to the unknown fields of dst. // // It is semantically equivalent to unmarshaling the encoded form of src // into dst with the UnmarshalOptions.Merge option specified. func (o MergeOptions) Merge(dst, src Message) { dstMsg, srcMsg := dst.ProtoReflect(), src.ProtoReflect() if o.Shallow { if dstMsg.Type() != srcMsg.Type() { panic("type mismatch") } } else { if dstMsg.Descriptor() != srcMsg.Descriptor() { panic("descriptor mismatch") } } o.mergeMessage(dstMsg, srcMsg) } func (o MergeOptions) mergeMessage(dst, src protoreflect.Message) { src.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { switch { case fd.IsList(): if o.Shallow && !dst.Has(fd) { dst.Set(fd, v) } else { o.mergeList(dst.Mutable(fd).List(), v.List(), fd) } case fd.IsMap(): if o.Shallow && !dst.Has(fd) { dst.Set(fd, v) } else { o.mergeMap(dst.Mutable(fd).Map(), v.Map(), fd.MapValue()) } case fd.Message() != nil: if o.Shallow && !dst.Has(fd) { dst.Set(fd, v) } else { o.mergeMessage(dst.Mutable(fd).Message(), v.Message()) } case fd.Kind() == protoreflect.BytesKind: dst.Set(fd, o.cloneBytes(v)) default: dst.Set(fd, v) } return true }) if len(src.GetUnknown()) > 0 { if o.Shallow && dst.GetUnknown() == nil { dst.SetUnknown(src.GetUnknown()) } else { dst.SetUnknown(append(dst.GetUnknown(), src.GetUnknown()...)) } } } func (o MergeOptions) mergeList(dst, src protoreflect.List, fd protoreflect.FieldDescriptor) { // Merge semantics appends to the end of the existing list. for i, n := 0, src.Len(); i < n; i++ { switch v := src.Get(i); { case fd.Message() != nil: if o.Shallow { dst.Append(v) } else { dstv := dst.NewElement() o.mergeMessage(dstv.Message(), v.Message()) dst.Append(dstv) } case fd.Kind() == protoreflect.BytesKind: dst.Append(o.cloneBytes(v)) default: dst.Append(v) } } } func (o MergeOptions) mergeMap(dst, src protoreflect.Map, fd protoreflect.FieldDescriptor) { // Merge semantics replaces, rather than merges into existing entries. src.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { switch { case fd.Message() != nil: if o.Shallow { dst.Set(k, v) } else { dstv := dst.NewValue() o.mergeMessage(dstv.Message(), v.Message()) dst.Set(k, dstv) } case fd.Kind() == protoreflect.BytesKind: dst.Set(k, o.cloneBytes(v)) default: dst.Set(k, v) } return true }) } func (o MergeOptions) cloneBytes(v protoreflect.Value) protoreflect.Value { if o.Shallow { return v } return protoreflect.ValueOfBytes(append([]byte{}, v.Bytes()...)) }