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 	"log"
     39 	"reflect"
     40 	"strings"
     41 )
     42 
     43 // Clone returns a deep copy of a protocol buffer.
     44 func Clone(pb Message) Message {
     45 	in := reflect.ValueOf(pb)
     46 	if in.IsNil() {
     47 		return pb
     48 	}
     49 
     50 	out := reflect.New(in.Type().Elem())
     51 	// out is empty so a merge is a deep copy.
     52 	mergeStruct(out.Elem(), in.Elem())
     53 	return out.Interface().(Message)
     54 }
     55 
     56 // Merge merges src into dst.
     57 // Required and optional fields that are set in src will be set to that value in dst.
     58 // Elements of repeated fields will be appended.
     59 // Merge panics if src and dst are not the same type, or if dst is nil.
     60 func Merge(dst, src Message) {
     61 	in := reflect.ValueOf(src)
     62 	out := reflect.ValueOf(dst)
     63 	if out.IsNil() {
     64 		panic("proto: nil destination")
     65 	}
     66 	if in.Type() != out.Type() {
     67 		// Explicit test prior to mergeStruct so that mistyped nils will fail
     68 		panic("proto: type mismatch")
     69 	}
     70 	if in.IsNil() {
     71 		// Merging nil into non-nil is a quiet no-op
     72 		return
     73 	}
     74 	mergeStruct(out.Elem(), in.Elem())
     75 }
     76 
     77 func mergeStruct(out, in reflect.Value) {
     78 	sprop := GetProperties(in.Type())
     79 	for i := 0; i < in.NumField(); i++ {
     80 		f := in.Type().Field(i)
     81 		if strings.HasPrefix(f.Name, "XXX_") {
     82 			continue
     83 		}
     84 		mergeAny(out.Field(i), in.Field(i), false, sprop.Prop[i])
     85 	}
     86 
     87 	if emIn, ok := extendable(in.Addr().Interface()); ok {
     88 		emOut, _ := extendable(out.Addr().Interface())
     89 		mIn, muIn := emIn.extensionsRead()
     90 		if mIn != nil {
     91 			mOut := emOut.extensionsWrite()
     92 			muIn.Lock()
     93 			mergeExtension(mOut, mIn)
     94 			muIn.Unlock()
     95 		}
     96 	}
     97 
     98 	uf := in.FieldByName("XXX_unrecognized")
     99 	if !uf.IsValid() {
    100 		return
    101 	}
    102 	uin := uf.Bytes()
    103 	if len(uin) > 0 {
    104 		out.FieldByName("XXX_unrecognized").SetBytes(append([]byte(nil), uin...))
    105 	}
    106 }
    107 
    108 // mergeAny performs a merge between two values of the same type.
    109 // viaPtr indicates whether the values were indirected through a pointer (implying proto2).
    110 // prop is set if this is a struct field (it may be nil).
    111 func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
    112 	if in.Type() == protoMessageType {
    113 		if !in.IsNil() {
    114 			if out.IsNil() {
    115 				out.Set(reflect.ValueOf(Clone(in.Interface().(Message))))
    116 			} else {
    117 				Merge(out.Interface().(Message), in.Interface().(Message))
    118 			}
    119 		}
    120 		return
    121 	}
    122 	switch in.Kind() {
    123 	case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
    124 		reflect.String, reflect.Uint32, reflect.Uint64:
    125 		if !viaPtr && isProto3Zero(in) {
    126 			return
    127 		}
    128 		out.Set(in)
    129 	case reflect.Interface:
    130 		// Probably a oneof field; copy non-nil values.
    131 		if in.IsNil() {
    132 			return
    133 		}
    134 		// Allocate destination if it is not set, or set to a different type.
    135 		// Otherwise we will merge as normal.
    136 		if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
    137 			out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
    138 		}
    139 		mergeAny(out.Elem(), in.Elem(), false, nil)
    140 	case reflect.Map:
    141 		if in.Len() == 0 {
    142 			return
    143 		}
    144 		if out.IsNil() {
    145 			out.Set(reflect.MakeMap(in.Type()))
    146 		}
    147 		// For maps with value types of *T or []byte we need to deep copy each value.
    148 		elemKind := in.Type().Elem().Kind()
    149 		for _, key := range in.MapKeys() {
    150 			var val reflect.Value
    151 			switch elemKind {
    152 			case reflect.Ptr:
    153 				val = reflect.New(in.Type().Elem().Elem())
    154 				mergeAny(val, in.MapIndex(key), false, nil)
    155 			case reflect.Slice:
    156 				val = in.MapIndex(key)
    157 				val = reflect.ValueOf(append([]byte{}, val.Bytes()...))
    158 			default:
    159 				val = in.MapIndex(key)
    160 			}
    161 			out.SetMapIndex(key, val)
    162 		}
    163 	case reflect.Ptr:
    164 		if in.IsNil() {
    165 			return
    166 		}
    167 		if out.IsNil() {
    168 			out.Set(reflect.New(in.Elem().Type()))
    169 		}
    170 		mergeAny(out.Elem(), in.Elem(), true, nil)
    171 	case reflect.Slice:
    172 		if in.IsNil() {
    173 			return
    174 		}
    175 		if in.Type().Elem().Kind() == reflect.Uint8 {
    176 			// []byte is a scalar bytes field, not a repeated field.
    177 
    178 			// Edge case: if this is in a proto3 message, a zero length
    179 			// bytes field is considered the zero value, and should not
    180 			// be merged.
    181 			if prop != nil && prop.proto3 && in.Len() == 0 {
    182 				return
    183 			}
    184 
    185 			// Make a deep copy.
    186 			// Append to []byte{} instead of []byte(nil) so that we never end up
    187 			// with a nil result.
    188 			out.SetBytes(append([]byte{}, in.Bytes()...))
    189 			return
    190 		}
    191 		n := in.Len()
    192 		if out.IsNil() {
    193 			out.Set(reflect.MakeSlice(in.Type(), 0, n))
    194 		}
    195 		switch in.Type().Elem().Kind() {
    196 		case reflect.Bool, reflect.Float32, reflect.Float64, reflect.Int32, reflect.Int64,
    197 			reflect.String, reflect.Uint32, reflect.Uint64:
    198 			out.Set(reflect.AppendSlice(out, in))
    199 		default:
    200 			for i := 0; i < n; i++ {
    201 				x := reflect.Indirect(reflect.New(in.Type().Elem()))
    202 				mergeAny(x, in.Index(i), false, nil)
    203 				out.Set(reflect.Append(out, x))
    204 			}
    205 		}
    206 	case reflect.Struct:
    207 		mergeStruct(out, in)
    208 	default:
    209 		// unknown type, so not a protocol buffer
    210 		log.Printf("proto: don't know how to copy %v", in)
    211 	}
    212 }
    213 
    214 func mergeExtension(out, in map[int32]Extension) {
    215 	for extNum, eIn := range in {
    216 		eOut := Extension{desc: eIn.desc}
    217 		if eIn.value != nil {
    218 			v := reflect.New(reflect.TypeOf(eIn.value)).Elem()
    219 			mergeAny(v, reflect.ValueOf(eIn.value), false, nil)
    220 			eOut.value = v.Interface()
    221 		}
    222 		if eIn.enc != nil {
    223 			eOut.enc = make([]byte, len(eIn.enc))
    224 			copy(eOut.enc, eIn.enc)
    225 		}
    226 
    227 		out[extNum] = eOut
    228 	}
    229 }
    230