1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- // 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/reflect/protoreflect"
- // 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.
- func Merge(dst, src Message) {
- mergeMessage(dst.ProtoReflect(), src.ProtoReflect())
- }
- func mergeMessage(dst, src protoreflect.Message) {
- if dst.Descriptor() != src.Descriptor() {
- panic("descriptor mismatch")
- }
- src.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- switch {
- case fd.IsList():
- mergeList(dst.Mutable(fd).List(), v.List(), fd)
- case fd.IsMap():
- mergeMap(dst.Mutable(fd).Map(), v.Map(), fd.MapValue())
- case fd.Message() != nil:
- mergeMessage(dst.Mutable(fd).Message(), v.Message())
- case fd.Kind() == protoreflect.BytesKind:
- dst.Set(fd, cloneBytes(v))
- default:
- dst.Set(fd, v)
- }
- return true
- })
- if len(src.GetUnknown()) > 0 {
- dst.SetUnknown(append(dst.GetUnknown(), src.GetUnknown()...))
- }
- }
- func mergeList(dst, src protoreflect.List, fd protoreflect.FieldDescriptor) {
- for i, n := 0, src.Len(); i < n; i++ {
- switch v := src.Get(i); {
- case fd.Message() != nil:
- dstv := dst.NewElement()
- mergeMessage(dstv.Message(), v.Message())
- dst.Append(dstv)
- case fd.Kind() == protoreflect.BytesKind:
- dst.Append(cloneBytes(v))
- default:
- dst.Append(v)
- }
- }
- }
- func mergeMap(dst, src protoreflect.Map, fd protoreflect.FieldDescriptor) {
- src.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
- switch {
- case fd.Message() != nil:
- dstv := dst.NewValue()
- mergeMessage(dstv.Message(), v.Message())
- dst.Set(k, dstv) // may replace existing entry
- case fd.Kind() == protoreflect.BytesKind:
- dst.Set(k, cloneBytes(v))
- default:
- dst.Set(k, v)
- }
- return true
- })
- }
- func cloneBytes(v protoreflect.Value) protoreflect.Value {
- return protoreflect.ValueOfBytes(append([]byte{}, v.Bytes()...))
- }
|