123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- package proto
- import (
- "fmt"
- "google.golang.org/protobuf/reflect/protoreflect"
- "google.golang.org/protobuf/runtime/protoiface"
- )
- func Merge(dst, src Message) {
-
-
- dstMsg, srcMsg := dst.ProtoReflect(), src.ProtoReflect()
- if dstMsg.Descriptor() != srcMsg.Descriptor() {
- if got, want := dstMsg.Descriptor().FullName(), srcMsg.Descriptor().FullName(); got != want {
- panic(fmt.Sprintf("descriptor mismatch: %v != %v", got, want))
- }
- panic("descriptor mismatch")
- }
- mergeOptions{}.mergeMessage(dstMsg, srcMsg)
- }
- func Clone(m Message) Message {
-
-
-
-
-
-
-
-
- if m == nil {
- return nil
- }
- src := m.ProtoReflect()
- if !src.IsValid() {
- return src.Type().Zero().Interface()
- }
- dst := src.New()
- mergeOptions{}.mergeMessage(dst, src)
- return dst.Interface()
- }
- type mergeOptions struct{}
- func (o mergeOptions) mergeMessage(dst, src protoreflect.Message) {
- methods := protoMethods(dst)
- if methods != nil && methods.Merge != nil {
- in := protoiface.MergeInput{
- Destination: dst,
- Source: src,
- }
- out := methods.Merge(in)
- if out.Flags&protoiface.MergeComplete != 0 {
- return
- }
- }
- if !dst.IsValid() {
- panic(fmt.Sprintf("cannot merge into invalid %v message", dst.Descriptor().FullName()))
- }
- src.Range(func(fd protoreflect.FieldDescriptor, v protoreflect.Value) bool {
- switch {
- case fd.IsList():
- o.mergeList(dst.Mutable(fd).List(), v.List(), fd)
- case fd.IsMap():
- o.mergeMap(dst.Mutable(fd).Map(), v.Map(), fd.MapValue())
- case fd.Message() != nil:
- 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 {
- dst.SetUnknown(append(dst.GetUnknown(), src.GetUnknown()...))
- }
- }
- func (o mergeOptions) 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()
- 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) {
-
- src.Range(func(k protoreflect.MapKey, v protoreflect.Value) bool {
- switch {
- case fd.Message() != nil:
- 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 {
- return protoreflect.ValueOfBytes(append([]byte{}, v.Bytes()...))
- }
|