go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/common/proto/reflectutil/shallow_copy.go (about) 1 // Copyright 2022 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package reflectutil 16 17 import ( 18 "google.golang.org/protobuf/proto" 19 "google.golang.org/protobuf/reflect/protoreflect" 20 ) 21 22 // ShallowCopy returns a new, shallow copy of `msg`. 23 // 24 // This is a safe alterative to the "obvious" implementation: 25 // 26 // tmp := *underlyingMsgValue 27 // return &tmp 28 // 29 // Unfortunately, protobuf holds many internal structures which are 30 // unsafe to shallow copy, and `go vet` has been hinted to complain 31 // about this. 32 // 33 // If `msg` is invalid (typically a nil *SomeMessage), this returns `msg` 34 // as-is. 35 // 36 // This implementation also copies unknown fields. 37 func ShallowCopy(msg proto.Message) proto.Message { 38 msgr := msg.ProtoReflect() 39 if !msgr.IsValid() { 40 return msg 41 } 42 43 ret := msgr.New() 44 msgr.Range(func(field protoreflect.FieldDescriptor, value protoreflect.Value) bool { 45 ret.Set(field, value) 46 return true 47 }) 48 ret.SetUnknown(msgr.GetUnknown()) 49 50 return ret.Interface() 51 }