1*1c12ee1eSDan Willemsen// Copyright 2019 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage proto 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "fmt" 9*1c12ee1eSDan Willemsen 10*1c12ee1eSDan Willemsen "google.golang.org/protobuf/reflect/protoreflect" 11*1c12ee1eSDan Willemsen "google.golang.org/protobuf/runtime/protoiface" 12*1c12ee1eSDan Willemsen) 13*1c12ee1eSDan Willemsen 14*1c12ee1eSDan Willemsen// Merge merges src into dst, which must be a message with the same descriptor. 15*1c12ee1eSDan Willemsen// 16*1c12ee1eSDan Willemsen// Populated scalar fields in src are copied to dst, while populated 17*1c12ee1eSDan Willemsen// singular messages in src are merged into dst by recursively calling Merge. 18*1c12ee1eSDan Willemsen// The elements of every list field in src is appended to the corresponded 19*1c12ee1eSDan Willemsen// list fields in dst. The entries of every map field in src is copied into 20*1c12ee1eSDan Willemsen// the corresponding map field in dst, possibly replacing existing entries. 21*1c12ee1eSDan Willemsen// The unknown fields of src are appended to the unknown fields of dst. 22*1c12ee1eSDan Willemsen// 23*1c12ee1eSDan Willemsen// It is semantically equivalent to unmarshaling the encoded form of src 24*1c12ee1eSDan Willemsen// into dst with the UnmarshalOptions.Merge option specified. 25*1c12ee1eSDan Willemsenfunc Merge(dst, src Message) { 26*1c12ee1eSDan Willemsen // TODO: Should nil src be treated as semantically equivalent to a 27*1c12ee1eSDan Willemsen // untyped, read-only, empty message? What about a nil dst? 28*1c12ee1eSDan Willemsen 29*1c12ee1eSDan Willemsen dstMsg, srcMsg := dst.ProtoReflect(), src.ProtoReflect() 30*1c12ee1eSDan Willemsen if dstMsg.Descriptor() != srcMsg.Descriptor() { 31*1c12ee1eSDan Willemsen if got, want := dstMsg.Descriptor().FullName(), srcMsg.Descriptor().FullName(); got != want { 32*1c12ee1eSDan Willemsen panic(fmt.Sprintf("descriptor mismatch: %v != %v", got, want)) 33*1c12ee1eSDan Willemsen } 34*1c12ee1eSDan Willemsen panic("descriptor mismatch") 35*1c12ee1eSDan Willemsen } 36*1c12ee1eSDan Willemsen mergeOptions{}.mergeMessage(dstMsg, srcMsg) 37*1c12ee1eSDan Willemsen} 38*1c12ee1eSDan Willemsen 39*1c12ee1eSDan Willemsen// Clone returns a deep copy of m. 40*1c12ee1eSDan Willemsen// If the top-level message is invalid, it returns an invalid message as well. 41*1c12ee1eSDan Willemsenfunc Clone(m Message) Message { 42*1c12ee1eSDan Willemsen // NOTE: Most usages of Clone assume the following properties: 43*1c12ee1eSDan Willemsen // t := reflect.TypeOf(m) 44*1c12ee1eSDan Willemsen // t == reflect.TypeOf(m.ProtoReflect().New().Interface()) 45*1c12ee1eSDan Willemsen // t == reflect.TypeOf(m.ProtoReflect().Type().Zero().Interface()) 46*1c12ee1eSDan Willemsen // 47*1c12ee1eSDan Willemsen // Embedding protobuf messages breaks this since the parent type will have 48*1c12ee1eSDan Willemsen // a forwarded ProtoReflect method, but the Interface method will return 49*1c12ee1eSDan Willemsen // the underlying embedded message type. 50*1c12ee1eSDan Willemsen if m == nil { 51*1c12ee1eSDan Willemsen return nil 52*1c12ee1eSDan Willemsen } 53*1c12ee1eSDan Willemsen src := m.ProtoReflect() 54*1c12ee1eSDan Willemsen if !src.IsValid() { 55*1c12ee1eSDan Willemsen return src.Type().Zero().Interface() 56*1c12ee1eSDan Willemsen } 57*1c12ee1eSDan Willemsen dst := src.New() 58*1c12ee1eSDan Willemsen mergeOptions{}.mergeMessage(dst, src) 59*1c12ee1eSDan Willemsen return dst.Interface() 60*1c12ee1eSDan Willemsen} 61*1c12ee1eSDan Willemsen 62*1c12ee1eSDan Willemsen// mergeOptions provides a namespace for merge functions, and can be 63*1c12ee1eSDan Willemsen// exported in the future if we add user-visible merge options. 64*1c12ee1eSDan Willemsentype mergeOptions struct{} 65*1c12ee1eSDan Willemsen 66*1c12ee1eSDan Willemsenfunc (o mergeOptions) mergeMessage(dst, src protoreflect.Message) { 67*1c12ee1eSDan Willemsen methods := protoMethods(dst) 68*1c12ee1eSDan Willemsen if methods != nil && methods.Merge != nil { 69*1c12ee1eSDan Willemsen in := protoiface.MergeInput{ 70*1c12ee1eSDan Willemsen Destination: dst, 71*1c12ee1eSDan Willemsen Source: src, 72*1c12ee1eSDan Willemsen } 73*1c12ee1eSDan Willemsen out := methods.Merge(in) 74*1c12ee1eSDan Willemsen if out.Flags&protoiface.MergeComplete != 0 { 75*1c12ee1eSDan Willemsen return 76*1c12ee1eSDan Willemsen } 77*1c12ee1eSDan Willemsen } 78*1c12ee1eSDan Willemsen 79*1c12ee1eSDan Willemsen if !dst.IsValid() { 80*1c12ee1eSDan Willemsen panic(fmt.Sprintf("cannot merge into invalid %v message", dst.Descriptor().FullName())) 81*1c12ee1eSDan Willemsen } 82*1c12ee1eSDan Willemsen 83*1c12ee1eSDan Willemsen src.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool { 84*1c12ee1eSDan Willemsen switch { 85*1c12ee1eSDan Willemsen case fd.IsList(): 86*1c12ee1eSDan Willemsen o.mergeList(dst.Mutable(fd).List(), v.List(), fd) 87*1c12ee1eSDan Willemsen case fd.IsMap(): 88*1c12ee1eSDan Willemsen o.mergeMap(dst.Mutable(fd).Map(), v.Map(), fd.MapValue()) 89*1c12ee1eSDan Willemsen case fd.Message() != nil: 90*1c12ee1eSDan Willemsen o.mergeMessage(dst.Mutable(fd).Message(), v.Message()) 91*1c12ee1eSDan Willemsen case fd.Kind() == protoreflect.BytesKind: 92*1c12ee1eSDan Willemsen dst.Set(fd, o.cloneBytes(v)) 93*1c12ee1eSDan Willemsen default: 94*1c12ee1eSDan Willemsen dst.Set(fd, v) 95*1c12ee1eSDan Willemsen } 96*1c12ee1eSDan Willemsen return true 97*1c12ee1eSDan Willemsen }) 98*1c12ee1eSDan Willemsen 99*1c12ee1eSDan Willemsen if len(src.GetUnknown()) > 0 { 100*1c12ee1eSDan Willemsen dst.SetUnknown(append(dst.GetUnknown(), src.GetUnknown()...)) 101*1c12ee1eSDan Willemsen } 102*1c12ee1eSDan Willemsen} 103*1c12ee1eSDan Willemsen 104*1c12ee1eSDan Willemsenfunc (o mergeOptions) mergeList(dst, src protoreflect.List, fd protoreflect.FieldDescriptor) { 105*1c12ee1eSDan Willemsen // Merge semantics appends to the end of the existing list. 106*1c12ee1eSDan Willemsen for i, n := 0, src.Len(); i < n; i++ { 107*1c12ee1eSDan Willemsen switch v := src.Get(i); { 108*1c12ee1eSDan Willemsen case fd.Message() != nil: 109*1c12ee1eSDan Willemsen dstv := dst.NewElement() 110*1c12ee1eSDan Willemsen o.mergeMessage(dstv.Message(), v.Message()) 111*1c12ee1eSDan Willemsen dst.Append(dstv) 112*1c12ee1eSDan Willemsen case fd.Kind() == protoreflect.BytesKind: 113*1c12ee1eSDan Willemsen dst.Append(o.cloneBytes(v)) 114*1c12ee1eSDan Willemsen default: 115*1c12ee1eSDan Willemsen dst.Append(v) 116*1c12ee1eSDan Willemsen } 117*1c12ee1eSDan Willemsen } 118*1c12ee1eSDan Willemsen} 119*1c12ee1eSDan Willemsen 120*1c12ee1eSDan Willemsenfunc (o mergeOptions) mergeMap(dst, src protoreflect.Map, fd protoreflect.FieldDescriptor) { 121*1c12ee1eSDan Willemsen // Merge semantics replaces, rather than merges into existing entries. 122*1c12ee1eSDan Willemsen src.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool { 123*1c12ee1eSDan Willemsen switch { 124*1c12ee1eSDan Willemsen case fd.Message() != nil: 125*1c12ee1eSDan Willemsen dstv := dst.NewValue() 126*1c12ee1eSDan Willemsen o.mergeMessage(dstv.Message(), v.Message()) 127*1c12ee1eSDan Willemsen dst.Set(k, dstv) 128*1c12ee1eSDan Willemsen case fd.Kind() == protoreflect.BytesKind: 129*1c12ee1eSDan Willemsen dst.Set(k, o.cloneBytes(v)) 130*1c12ee1eSDan Willemsen default: 131*1c12ee1eSDan Willemsen dst.Set(k, v) 132*1c12ee1eSDan Willemsen } 133*1c12ee1eSDan Willemsen return true 134*1c12ee1eSDan Willemsen }) 135*1c12ee1eSDan Willemsen} 136*1c12ee1eSDan Willemsen 137*1c12ee1eSDan Willemsenfunc (o mergeOptions) cloneBytes(v protoreflect.Value) protoreflect.Value { 138*1c12ee1eSDan Willemsen return protoreflect.ValueOfBytes(append([]byte{}, v.Bytes()...)) 139*1c12ee1eSDan Willemsen} 140