// Go support for Protocol Buffers - Google's data interchange format
//
// Copyright 2016 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.

package proto

import (
	
	
	
	
	
)

// Merge merges the src message into dst.
// This assumes that dst and src of the same type and are non-nil.
func ( *InternalMessageInfo) (,  Message) {
	 := atomicLoadMergeInfo(&.merge)
	if  == nil {
		 = getMergeInfo(reflect.TypeOf().Elem())
		atomicStoreMergeInfo(&.merge, )
	}
	.merge(toPointer(&), toPointer(&))
}

type mergeInfo struct {
	typ reflect.Type

	initialized int32 // 0: only typ is valid, 1: everything is valid
	lock        sync.Mutex

	fields       []mergeFieldInfo
	unrecognized field // Offset of XXX_unrecognized
}

type mergeFieldInfo struct {
	field field // Offset of field, guaranteed to be valid

	// isPointer reports whether the value in the field is a pointer.
	// This is true for the following situations:
	//	* Pointer to struct
	//	* Pointer to basic type (proto2 only)
	//	* Slice (first value in slice header is a pointer)
	//	* String (first value in string header is a pointer)
	isPointer bool

	// basicWidth reports the width of the field assuming that it is directly
	// embedded in the struct (as is the case for basic types in proto3).
	// The possible values are:
	// 	0: invalid
	//	1: bool
	//	4: int32, uint32, float32
	//	8: int64, uint64, float64
	basicWidth int

	// Where dst and src are pointers to the types being merged.
	merge func(dst, src pointer)
}

var (
	mergeInfoMap  = map[reflect.Type]*mergeInfo{}
	mergeInfoLock sync.Mutex
)

func getMergeInfo( reflect.Type) *mergeInfo {
	mergeInfoLock.Lock()
	defer mergeInfoLock.Unlock()
	 := mergeInfoMap[]
	if  == nil {
		 = &mergeInfo{typ: }
		mergeInfoMap[] = 
	}
	return 
}

// merge merges src into dst assuming they are both of type *mi.typ.
func ( *mergeInfo) (,  pointer) {
	if .isNil() {
		panic("proto: nil destination")
	}
	if .isNil() {
		return // Nothing to do.
	}

	if atomic.LoadInt32(&.initialized) == 0 {
		.computeMergeInfo()
	}

	for ,  := range .fields {
		 := .offset(.field)

		// As an optimization, we can avoid the merge function call cost
		// if we know for sure that the source will have no effect
		// by checking if it is the zero value.
		if unsafeAllowed {
			if .isPointer && .getPointer().isNil() { // Could be slice or string
				continue
			}
			if .basicWidth > 0 {
				switch {
				case .basicWidth == 1 && !*.toBool():
					continue
				case .basicWidth == 4 && *.toUint32() == 0:
					continue
				case .basicWidth == 8 && *.toUint64() == 0:
					continue
				}
			}
		}

		 := .offset(.field)
		.merge(, )
	}

	// TODO: Make this faster?
	 := .asPointerTo(.typ).Elem()
	 := .asPointerTo(.typ).Elem()
	if ,  := extendable(.Addr().Interface());  == nil {
		,  := extendable(.Addr().Interface())
		,  := .extensionsRead()
		if  != nil {
			 := .extensionsWrite()
			.Lock()
			mergeExtension(, )
			.Unlock()
		}
	}

	if .unrecognized.IsValid() {
		if  := *.offset(.unrecognized).toBytes(); len() > 0 {
			*.offset(.unrecognized).toBytes() = append([]byte(nil), ...)
		}
	}
}

func ( *mergeInfo) () {
	.lock.Lock()
	defer .lock.Unlock()
	if .initialized != 0 {
		return
	}
	 := .typ
	 := .NumField()

	 := GetProperties()
	for  := 0;  < ; ++ {
		 := .Field()
		if strings.HasPrefix(.Name, "XXX_") {
			continue
		}

		 := mergeFieldInfo{field: toField(&)}
		 := .Type

		// As an optimization, we can avoid the merge function call cost
		// if we know for sure that the source will have no effect
		// by checking if it is the zero value.
		if unsafeAllowed {
			switch .Kind() {
			case reflect.Ptr, reflect.Slice, reflect.String:
				// As a special case, we assume slices and strings are pointers
				// since we know that the first field in the SliceSlice or
				// StringHeader is a data pointer.
				.isPointer = true
			case reflect.Bool:
				.basicWidth = 1
			case reflect.Int32, reflect.Uint32, reflect.Float32:
				.basicWidth = 4
			case reflect.Int64, reflect.Uint64, reflect.Float64:
				.basicWidth = 8
			}
		}

		// Unwrap tf to get at its most basic type.
		var ,  bool
		if .Kind() == reflect.Slice && .Elem().Kind() != reflect.Uint8 {
			 = true
			 = .Elem()
		}
		if .Kind() == reflect.Ptr {
			 = true
			 = .Elem()
		}
		if  &&  && .Kind() != reflect.Struct {
			panic("both pointer and slice for basic type in " + .Name())
		}

		switch .Kind() {
		case reflect.Int32:
			switch {
			case : // E.g., []int32
				.merge = func(,  pointer) {
					// NOTE: toInt32Slice is not defined (see pointer_reflect.go).
					/*
						sfsp := src.toInt32Slice()
						if *sfsp != nil {
							dfsp := dst.toInt32Slice()
							*dfsp = append(*dfsp, *sfsp...)
							if *dfsp == nil {
								*dfsp = []int64{}
							}
						}
					*/
					 := .getInt32Slice()
					if  != nil {
						 := .getInt32Slice()
						 = append(, ...)
						if  == nil {
							 = []int32{}
						}
						.setInt32Slice()
					}
				}
			case : // E.g., *int32
				.merge = func(,  pointer) {
					// NOTE: toInt32Ptr is not defined (see pointer_reflect.go).
					/*
						sfpp := src.toInt32Ptr()
						if *sfpp != nil {
							dfpp := dst.toInt32Ptr()
							if *dfpp == nil {
								*dfpp = Int32(**sfpp)
							} else {
								**dfpp = **sfpp
							}
						}
					*/
					 := .getInt32Ptr()
					if  != nil {
						 := .getInt32Ptr()
						if  == nil {
							.setInt32Ptr(*)
						} else {
							* = *
						}
					}
				}
			default: // E.g., int32
				.merge = func(,  pointer) {
					if  := *.toInt32();  != 0 {
						*.toInt32() = 
					}
				}
			}
		case reflect.Int64:
			switch {
			case : // E.g., []int64
				.merge = func(,  pointer) {
					 := .toInt64Slice()
					if * != nil {
						 := .toInt64Slice()
						* = append(*, *...)
						if * == nil {
							* = []int64{}
						}
					}
				}
			case : // E.g., *int64
				.merge = func(,  pointer) {
					 := .toInt64Ptr()
					if * != nil {
						 := .toInt64Ptr()
						if * == nil {
							* = Int64(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., int64
				.merge = func(,  pointer) {
					if  := *.toInt64();  != 0 {
						*.toInt64() = 
					}
				}
			}
		case reflect.Uint32:
			switch {
			case : // E.g., []uint32
				.merge = func(,  pointer) {
					 := .toUint32Slice()
					if * != nil {
						 := .toUint32Slice()
						* = append(*, *...)
						if * == nil {
							* = []uint32{}
						}
					}
				}
			case : // E.g., *uint32
				.merge = func(,  pointer) {
					 := .toUint32Ptr()
					if * != nil {
						 := .toUint32Ptr()
						if * == nil {
							* = Uint32(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., uint32
				.merge = func(,  pointer) {
					if  := *.toUint32();  != 0 {
						*.toUint32() = 
					}
				}
			}
		case reflect.Uint64:
			switch {
			case : // E.g., []uint64
				.merge = func(,  pointer) {
					 := .toUint64Slice()
					if * != nil {
						 := .toUint64Slice()
						* = append(*, *...)
						if * == nil {
							* = []uint64{}
						}
					}
				}
			case : // E.g., *uint64
				.merge = func(,  pointer) {
					 := .toUint64Ptr()
					if * != nil {
						 := .toUint64Ptr()
						if * == nil {
							* = Uint64(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., uint64
				.merge = func(,  pointer) {
					if  := *.toUint64();  != 0 {
						*.toUint64() = 
					}
				}
			}
		case reflect.Float32:
			switch {
			case : // E.g., []float32
				.merge = func(,  pointer) {
					 := .toFloat32Slice()
					if * != nil {
						 := .toFloat32Slice()
						* = append(*, *...)
						if * == nil {
							* = []float32{}
						}
					}
				}
			case : // E.g., *float32
				.merge = func(,  pointer) {
					 := .toFloat32Ptr()
					if * != nil {
						 := .toFloat32Ptr()
						if * == nil {
							* = Float32(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., float32
				.merge = func(,  pointer) {
					if  := *.toFloat32();  != 0 {
						*.toFloat32() = 
					}
				}
			}
		case reflect.Float64:
			switch {
			case : // E.g., []float64
				.merge = func(,  pointer) {
					 := .toFloat64Slice()
					if * != nil {
						 := .toFloat64Slice()
						* = append(*, *...)
						if * == nil {
							* = []float64{}
						}
					}
				}
			case : // E.g., *float64
				.merge = func(,  pointer) {
					 := .toFloat64Ptr()
					if * != nil {
						 := .toFloat64Ptr()
						if * == nil {
							* = Float64(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., float64
				.merge = func(,  pointer) {
					if  := *.toFloat64();  != 0 {
						*.toFloat64() = 
					}
				}
			}
		case reflect.Bool:
			switch {
			case : // E.g., []bool
				.merge = func(,  pointer) {
					 := .toBoolSlice()
					if * != nil {
						 := .toBoolSlice()
						* = append(*, *...)
						if * == nil {
							* = []bool{}
						}
					}
				}
			case : // E.g., *bool
				.merge = func(,  pointer) {
					 := .toBoolPtr()
					if * != nil {
						 := .toBoolPtr()
						if * == nil {
							* = Bool(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., bool
				.merge = func(,  pointer) {
					if  := *.toBool();  {
						*.toBool() = 
					}
				}
			}
		case reflect.String:
			switch {
			case : // E.g., []string
				.merge = func(,  pointer) {
					 := .toStringSlice()
					if * != nil {
						 := .toStringSlice()
						* = append(*, *...)
						if * == nil {
							* = []string{}
						}
					}
				}
			case : // E.g., *string
				.merge = func(,  pointer) {
					 := .toStringPtr()
					if * != nil {
						 := .toStringPtr()
						if * == nil {
							* = String(**)
						} else {
							** = **
						}
					}
				}
			default: // E.g., string
				.merge = func(,  pointer) {
					if  := *.toString();  != "" {
						*.toString() = 
					}
				}
			}
		case reflect.Slice:
			 := .Prop[].proto3
			switch {
			case :
				panic("bad pointer in byte slice case in " + .Name())
			case .Elem().Kind() != reflect.Uint8:
				panic("bad element kind in byte slice case in " + .Name())
			case : // E.g., [][]byte
				.merge = func(,  pointer) {
					 := .toBytesSlice()
					if * != nil {
						 := .toBytesSlice()
						for ,  := range * {
							if  == nil {
								* = append(*, nil)
							} else {
								* = append(*, append([]byte{}, ...))
							}
						}
						if * == nil {
							* = [][]byte{}
						}
					}
				}
			default: // E.g., []byte
				.merge = func(,  pointer) {
					 := .toBytes()
					if * != nil {
						 := .toBytes()
						if ! || len(*) > 0 {
							* = append([]byte{}, *...)
						}
					}
				}
			}
		case reflect.Struct:
			switch {
			case  && !: // E.g. []pb.T
				 := getMergeInfo()
				 := reflect.Zero()
				.merge = func(,  pointer) {
					// TODO: Make this faster?
					 := .asPointerTo(.Type)
					 := .Elem()
					 := .asPointerTo(.Type).Elem()
					for  := 0;  < .Len(); ++ {
						 = reflect.Append(, )
						 := .Index().Addr()
						 := .Index(.Len() - 1).Addr()
						.merge(valToPointer(), valToPointer())
					}
					if .IsNil() {
						 = reflect.MakeSlice(.Type, 0, 0)
					}
					.Elem().Set()
				}
			case !:
				 := getMergeInfo()
				.merge = func(,  pointer) {
					.merge(, )
				}
			case : // E.g., []*pb.T
				 := getMergeInfo()
				.merge = func(,  pointer) {
					 := .getPointerSlice()
					if  != nil {
						 := .getPointerSlice()
						for ,  := range  {
							var  pointer
							if !.isNil() {
								 = valToPointer(reflect.New())
								.merge(, )
							}
							 = append(, )
						}
						if  == nil {
							 = []pointer{}
						}
						.setPointerSlice()
					}
				}
			default: // E.g., *pb.T
				 := getMergeInfo()
				.merge = func(,  pointer) {
					 := .getPointer()
					if !.isNil() {
						 := .getPointer()
						if .isNil() {
							 = valToPointer(reflect.New())
							.setPointer()
						}
						.merge(, )
					}
				}
			}
		case reflect.Map:
			switch {
			case  || :
				panic("bad pointer or slice in map case in " + .Name())
			default: // E.g., map[K]V
				.merge = func(,  pointer) {
					 := .asPointerTo().Elem()
					if .Len() == 0 {
						return
					}
					 := .asPointerTo().Elem()
					if .IsNil() {
						.Set(reflect.MakeMap())
					}

					switch .Elem().Kind() {
					case reflect.Ptr: // Proto struct (e.g., *T)
						for ,  := range .MapKeys() {
							 := .MapIndex()
							 = reflect.ValueOf(Clone(.Interface().(Message)))
							.SetMapIndex(, )
						}
					case reflect.Slice: // E.g. Bytes type (e.g., []byte)
						for ,  := range .MapKeys() {
							 := .MapIndex()
							 = reflect.ValueOf(append([]byte{}, .Bytes()...))
							.SetMapIndex(, )
						}
					default: // Basic type (e.g., string)
						for ,  := range .MapKeys() {
							 := .MapIndex()
							.SetMapIndex(, )
						}
					}
				}
			}
		case reflect.Interface:
			// Must be oneof field.
			switch {
			case  || :
				panic("bad pointer or slice in interface case in " + .Name())
			default: // E.g., interface{}
				// TODO: Make this faster?
				.merge = func(,  pointer) {
					 := .asPointerTo().Elem()
					if !.IsNil() {
						 := .asPointerTo().Elem()
						 := .Elem().Type()
						if .IsNil() || .Elem().Type() !=  {
							.Set(reflect.New(.Elem())) // Initialize interface if empty
						}
						 := .Elem().Elem().Field(0)
						if .Kind() == reflect.Ptr && .IsNil() {
							return
						}
						 := .Elem().Elem().Field(0)
						if .Kind() == reflect.Ptr && .IsNil() {
							.Set(reflect.New(.Type().Elem())) // Initialize proto message if empty
						}
						switch .Type().Kind() {
						case reflect.Ptr: // Proto struct (e.g., *T)
							Merge(.Interface().(Message), .Interface().(Message))
						case reflect.Slice: // E.g. Bytes type (e.g., []byte)
							.Set(reflect.ValueOf(append([]byte{}, .Bytes()...)))
						default: // Basic type (e.g., string)
							.Set()
						}
					}
				}
			}
		default:
			panic(fmt.Sprintf("merger not found for type:%s", ))
		}
		.fields = append(.fields, )
	}

	.unrecognized = invalidField
	if ,  := .FieldByName("XXX_unrecognized");  {
		if .Type != reflect.TypeOf([]byte{}) {
			panic("expected XXX_unrecognized to be of type []byte")
		}
		.unrecognized = toField(&)
	}

	atomic.StoreInt32(&.initialized, 1)
}