// Go support for Protocol Buffers - Google's data interchange format//// Copyright 2011 The Go Authors. All rights reserved.// https://github.com/golang/protobuf//// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following disclaimer// in the documentation and/or other materials provided with the// distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived from// this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.// Protocol buffer deep copy and merge.// TODO: RawMessage.package protoimport ()// Clone returns a deep copy of a protocol buffer.func ( Message) Message { := reflect.ValueOf()if .IsNil() {return } := reflect.New(.Type().Elem()) := .Interface().(Message)Merge(, )return}// Merger is the interface representing objects that can merge messages of the same type.typeMergerinterface {// Merge merges src into this message. // Required and optional fields that are set in src will be set to that value in dst. // Elements of repeated fields will be appended. // // Merge may panic if called with a different argument type than the receiver.Merge(src Message)}// generatedMerger is the custom merge method that generated protos will have.// We must add this method since a generate Merge method will conflict with// many existing protos that have a Merge data field already defined.type generatedMerger interface { XXX_Merge(src Message)}// Merge merges src into dst.// Required and optional fields that are set in src will be set to that value in dst.// Elements of repeated fields will be appended.// Merge panics if src and dst are not the same type, or if dst is nil.func (, Message) {if , := .(Merger); { .Merge()return } := reflect.ValueOf() := reflect.ValueOf()if .IsNil() {panic("proto: nil destination") }if .Type() != .Type() {panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", , )) }if .IsNil() {return// Merge from nil src is a noop }if , := .(generatedMerger); { .XXX_Merge()return }mergeStruct(.Elem(), .Elem())}func mergeStruct(, reflect.Value) { := GetProperties(.Type())for := 0; < .NumField(); ++ { := .Type().Field()ifstrings.HasPrefix(.Name, "XXX_") {continue }mergeAny(.Field(), .Field(), false, .Prop[]) }if , := .Addr().Interface().(extensionsBytes); { := .Addr().Interface().(extensionsBytes) := .GetExtensions() := .GetExtensions() * = append(*, *...) } elseif , := extendable(.Addr().Interface()); == nil { , := extendable(.Addr().Interface()) , := .extensionsRead()if != nil { := .extensionsWrite() .Lock()mergeExtension(, ) .Unlock() } } := .FieldByName("XXX_unrecognized")if !.IsValid() {return } := .Bytes()iflen() > 0 { .FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), ...)) }}// mergeAny performs a merge between two values of the same type.// viaPtr indicates whether the values were indirected through a pointer (implying proto2).// prop is set if this is a struct field (it may be nil).func mergeAny(, reflect.Value, bool, *Properties) {if .Type() == protoMessageType {if !.IsNil() {if .IsNil() { .Set(reflect.ValueOf(Clone(.Interface().(Message)))) } else {Merge(.Interface().(Message), .Interface().(Message)) } }return }switch .Kind() {casereflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,reflect.String, reflect.Uint32, reflect.Uint64:if ! && isProto3Zero() {return } .Set()casereflect.Interface:// Probably a oneof field; copy non-nil values.if .IsNil() {return }// Allocate destination if it is not set, or set to a different type. // Otherwise we will merge as normal.if .IsNil() || .Elem().Type() != .Elem().Type() { .Set(reflect.New(.Elem().Elem().Type())) // interface -> *T -> T -> new(T) } (.Elem(), .Elem(), false, nil)casereflect.Map:if .Len() == 0 {return }if .IsNil() { .Set(reflect.MakeMap(.Type())) }// For maps with value types of *T or []byte we need to deep copy each value. := .Type().Elem().Kind()for , := range .MapKeys() {varreflect.Valueswitch {casereflect.Ptr: = reflect.New(.Type().Elem().Elem()) (, .MapIndex(), false, nil)casereflect.Slice: = .MapIndex() = reflect.ValueOf(append([]byte{}, .Bytes()...))default: = .MapIndex() } .SetMapIndex(, ) }casereflect.Ptr:if .IsNil() {return }if .IsNil() { .Set(reflect.New(.Elem().Type())) } (.Elem(), .Elem(), true, nil)casereflect.Slice:if .IsNil() {return }if .Type().Elem().Kind() == reflect.Uint8 {// []byte is a scalar bytes field, not a repeated field.// Edge case: if this is in a proto3 message, a zero length // bytes field is considered the zero value, and should not // be merged.if != nil && .proto3 && .Len() == 0 {return }// Make a deep copy. // Append to []byte{} instead of []byte(nil) so that we never end up // with a nil result. .SetBytes(append([]byte{}, .Bytes()...))return } := .Len()if .IsNil() { .Set(reflect.MakeSlice(.Type(), 0, )) }switch .Type().Elem().Kind() {casereflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,reflect.String, reflect.Uint32, reflect.Uint64: .Set(reflect.AppendSlice(, ))default:for := 0; < ; ++ { := reflect.Indirect(reflect.New(.Type().Elem())) (, .Index(), false, nil) .Set(reflect.Append(, )) } }casereflect.Struct:mergeStruct(, )default:// unknown type, so not a protocol bufferlog.Printf("proto: don't know how to copy %v", ) }}func mergeExtension(, map[int32]Extension) {for , := range { := Extension{desc: .desc}if .value != nil { := reflect.New(reflect.TypeOf(.value)).Elem()mergeAny(, reflect.ValueOf(.value), false, nil) .value = .Interface() }if .enc != nil { .enc = make([]byte, len(.enc))copy(.enc, .enc) } [] = }}
The pages are generated with Goldsv0.8.2. (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu.
PR and bug reports are welcome and can be submitted to the issue list.
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds.