Home | History | Annotate | Download | only in proto
      1 // Go support for Protocol Buffers - Google's data interchange format
      2 //
      3 // Copyright 2011 The Go Authors.  All rights reserved.
      4 // https://github.com/golang/protobuf
      5 //
      6 // Redistribution and use in source and binary forms, with or without
      7 // modification, are permitted provided that the following conditions are
      8 // met:
      9 //
     10 //     * Redistributions of source code must retain the above copyright
     11 // notice, this list of conditions and the following disclaimer.
     12 //     * Redistributions in binary form must reproduce the above
     13 // copyright notice, this list of conditions and the following disclaimer
     14 // in the documentation and/or other materials provided with the
     15 // distribution.
     16 //     * Neither the name of Google Inc. nor the names of its
     17 // contributors may be used to endorse or promote products derived from
     18 // this software without specific prior written permission.
     19 //
     20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     31 
     32 // Protocol buffer deep copy and merge.
     33 // TODO: RawMessage.
     34 
     35 package proto
     36 
     37 import (
     38 	"fmt"
     39 	"log"
     40 	"reflect"
     41 	"strings"
     42 )
     43 
     44 // Clone returns a deep copy of a protocol buffer.
     45 func Clone(src Message) Message {
     46 	in := reflect.ValueOf(src)
     47 	if in.IsNil() {
     48 		return src
     49 	}
     50 	out := reflect.New(in.Type().Elem())
     51 	dst := out.Interface().(Message)
     52 	Merge(dst, src)
     53 	return dst
     54 }
     55 
     56 // Merger is the interface representing objects that can merge messages of the same type.
     57 type Merger interface {
     58 	// Merge merges src into this message.
     59 	// Required and optional fields that are set in src will be set to that value in dst.
     60 	// Elements of repeated fields will be appended.
     61 	//
     62 	// Merge may panic if called with a different argument type than the receiver.
     63 	Merge(src Message)
     64 }
     65 
     66 // generatedMerger is the custom merge method that generated protos will have.
     67 // We must add this method since a generate Merge method will conflict with
     68 // many existing protos that have a Merge data field already defined.
     69 type generatedMerger interface {
     70 	XXX_Merge(src Message)
     71 }
     72 
     73 // Merge merges src into dst.
     74 // Required and optional fields that are set in src will be set to that value in dst.
     75 // Elements of repeated fields will be appended.
     76 // Merge panics if src and dst are not the same type, or if dst is nil.
     77 func Merge(dst, src Message) {
     78 	if m, ok := dst.(Merger); ok {
     79 		m.Merge(src)
     80 		return
     81 	}
     82 
     83 	in := reflect.ValueOf(src)
     84 	out := reflect.ValueOf(dst)
     85 	if out.IsNil() {
     86 		panic("proto: nil destination")
     87 	}
     88 	if in.Type() != out.Type() {
     89 		panic(fmt.Sprintf("proto.Merge(%T, %T) type mismatch", dst, src))
     90 	}
     91 	if in.IsNil() {
     92 		return // Merge from nil src is a noop
     93 	}
     94 	if m, ok := dst.(generatedMerger); ok {
     95 		m.XXX_Merge(src)
     96 		return
     97 	}
     98 	mergeStruct(out.Elem(), in.Elem())
     99 }
    100 
    101 func mergeStruct(out, in reflect.Value) {
    102 	sprop := GetProperties(in.Type())
    103 	for i := 0; i < in.NumField(); i++ {
    104 		f := in.Type().Field(i)
    105 		if strings.HasPrefix(f.Name, "XXX_") {
    106 			continue
    107 		}
    108 		mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
    109 	}
    110 
    111 	if emIn, err := extendable(in.Addr().Interface()); err == nil {
    112 		emOut, _ := extendable(out.Addr().Interface())
    113 		mIn, muIn := emIn.extensionsRead()
    114 		if mIn != nil {
    115 			mOut := emOut.extensionsWrite()
    116 			muIn.Lock()
    117 			mergeExtension(mOut, mIn)
    118 			muIn.Unlock()
    119 		}
    120 	}
    121 
    122 	uf := in.FieldByName("XXX_unrecognized")
    123 	if !uf.IsValid() {
    124 		return
    125 	}
    126 	uin := uf.Bytes()
    127 	if len(uin) > 0 {
    128 		out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
    129 	}
    130 }
    131 
    132 // mergeAny performs a merge between two values of the same type.
    133 // viaPtr indicates whether the values were indirected through a pointer (implying proto2).
    134 // prop is set if this is a struct field (it may be nil).
    135 func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
    136 	if in.Type() == protoMessageType {
    137 		if !in.IsNil() {
    138 			if out.IsNil() {
    139 				out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
    140 			} else {
    141 				Merge(out.Interface().(Message), in.Interface().(Message))
    142 			}
    143 		}
    144 		return
    145 	}
    146 	switch in.Kind() {
    147 	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
    148 		reflect.String, reflect.Uint32, reflect.Uint64:
    149 		if !viaPtr && isProto3Zero(in) {
    150 			return
    151 		}
    152 		out.Set(in)
    153 	case reflect.Interface:
    154 		// Probably a oneof field; copy non-nil values.
    155 		if in.IsNil() {
    156 			return
    157 		}
    158 		// Allocate destination if it is not set, or set to a different type.
    159 		// Otherwise we will merge as normal.
    160 		if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
    161 			out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
    162 		}
    163 		mergeAny(out.Elem(), in.Elem(), false, nil)
    164 	case reflect.Map:
    165 		if in.Len() == 0 {
    166 			return
    167 		}
    168 		if out.IsNil() {
    169 			out.Set(reflect.MakeMap(in.Type()))
    170 		}
    171 		// For maps with value types of *T or []byte we need to deep copy each value.
    172 		elemKind := in.Type().Elem().Kind()
    173 		for _, key := range in.MapKeys() {
    174 			var val reflect.Value
    175 			switch elemKind {
    176 			case reflect.Ptr:
    177 				val = reflect.New(in.Type().Elem().Elem())
    178 				mergeAny(val, in.MapIndex(key), false, nil)
    179 			case reflect.Slice:
    180 				val = in.MapIndex(key)
    181 				val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
    182 			default:
    183 				val = in.MapIndex(key)
    184 			}
    185 			out.SetMapIndex(key, val)
    186 		}
    187 	case reflect.Ptr:
    188 		if in.IsNil() {
    189 			return
    190 		}
    191 		if out.IsNil() {
    192 			out.Set(reflect.New(in.Elem().Type()))
    193 		}
    194 		mergeAny(out.Elem(), in.Elem(), true, nil)
    195 	case reflect.Slice:
    196 		if in.IsNil() {
    197 			return
    198 		}
    199 		if in.Type().Elem().Kind() == reflect.Uint8 {
    200 			// []byte is a scalar bytes field, not a repeated field.
    201 
    202 			// Edge case: if this is in a proto3 message, a zero length
    203 			// bytes field is considered the zero value, and should not
    204 			// be merged.
    205 			if prop != nil && prop.proto3 && in.Len() == 0 {
    206 				return
    207 			}
    208 
    209 			// Make a deep copy.
    210 			// Append to []byte{} instead of []byte(nil) so that we never end up
    211 			// with a nil result.
    212 			out.SetBytes(append([]byte{}, in.Bytes()...))
    213 			return
    214 		}
    215 		n := in.Len()
    216 		if out.IsNil() {
    217 			out.Set(reflect.MakeSlice(in.Type(), 0, n))
    218 		}
    219 		switch in.Type().Elem().Kind() {
    220 		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
    221 			reflect.String, reflect.Uint32, reflect.Uint64:
    222 			out.Set(reflect.AppendSlice(out, in))
    223 		default:
    224 			for i := 0; i < n; i++ {
    225 				x := reflect.Indirect(reflect.New(in.Type().Elem()))
    226 				mergeAny(x, in.Index(i), false, nil)
    227 				out.Set(reflect.Append(out, x))
    228 			}
    229 		}
    230 	case reflect.Struct:
    231 		mergeStruct(out, in)
    232 	default:
    233 		// unknown type, so not a protocol buffer
    234 		log.Printf("proto: don't know how to copy %v", in)
    235 	}
    236 }
    237 
    238 func mergeExtension(out, in map[int32]Extension) {
    239 	for extNum, eIn := range in {
    240 		eOut := Extension{desc: eIn.desc}
    241 		if eIn.value != nil {
    242 			v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
    243 			mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
    244 			eOut.value = v.Interface()
    245 		}
    246 		if eIn.enc != nil {
    247 			eOut.enc = make([]byte, len(eIn.enc))
    248 			copy(eOut.enc, eIn.enc)
    249 		}
    250 
    251 		out[extNum] = eOut
    252 	}
    253 }
    254