// 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 comparison.

package proto

import (
	
	
	
	
)

/*
Equal returns true iff protocol buffers a and b are equal.
The arguments must both be pointers to protocol buffer structs.

Equality is defined in this way:
  - Two messages are equal iff they are the same type,
    corresponding fields are equal, unknown field sets
    are equal, and extensions sets are equal.
  - Two set scalar fields are equal iff their values are equal.
    If the fields are of a floating-point type, remember that
    NaN != x for all x, including NaN. If the message is defined
    in a proto3 .proto file, fields are not "set"; specifically,
    zero length proto3 "bytes" fields are equal (nil == {}).
  - Two repeated fields are equal iff their lengths are the same,
    and their corresponding elements are equal. Note a "bytes" field,
    although represented by []byte, is not a repeated field and the
    rule for the scalar fields described above applies.
  - Two unset fields are equal.
  - Two unknown field sets are equal if their current
    encoded state is equal.
  - Two extension sets are equal iff they have corresponding
    elements that are pairwise equal.
  - Two map fields are equal iff their lengths are the same,
    and they contain the same set of elements. Zero-length map
    fields are equal.
  - Every other combination of things are not equal.

The return value is undefined if a and b are not protocol buffers.
*/
func (,  Message) bool {
	if  == nil ||  == nil {
		return  == 
	}
	,  := reflect.ValueOf(), reflect.ValueOf()
	if .Type() != .Type() {
		return false
	}
	if .Kind() == reflect.Ptr {
		if .IsNil() {
			return .IsNil()
		}
		if .IsNil() {
			return false
		}
		,  = .Elem(), .Elem()
	}
	if .Kind() != reflect.Struct {
		return false
	}
	return equalStruct(, )
}

// v1 and v2 are known to have the same type.
func equalStruct(,  reflect.Value) bool {
	 := GetProperties(.Type())
	for  := 0;  < .NumField(); ++ {
		 := .Type().Field()
		if strings.HasPrefix(.Name, "XXX_") {
			continue
		}
		,  := .Field(), .Field()
		if .Type.Kind() == reflect.Ptr {
			if ,  := .IsNil(), .IsNil();  &&  {
				// both unset
				continue
			} else if  !=  {
				// set/unset mismatch
				return false
			}
			,  = .Elem(), .Elem()
		}
		if !equalAny(, , .Prop[]) {
			return false
		}
	}

	if  := .FieldByName("XXX_InternalExtensions"); .IsValid() {
		 := .FieldByName("XXX_InternalExtensions")
		if !equalExtensions(.Type(), .Interface().(XXX_InternalExtensions), .Interface().(XXX_InternalExtensions)) {
			return false
		}
	}

	if  := .FieldByName("XXX_extensions"); .IsValid() {
		 := .FieldByName("XXX_extensions")
		if !equalExtMap(.Type(), .Interface().(map[int32]Extension), .Interface().(map[int32]Extension)) {
			return false
		}
	}

	 := .FieldByName("XXX_unrecognized")
	if !.IsValid() {
		return true
	}

	 := .Bytes()
	 := .FieldByName("XXX_unrecognized").Bytes()
	return bytes.Equal(, )
}

// v1 and v2 are known to have the same type.
// prop may be nil.
func equalAny(,  reflect.Value,  *Properties) bool {
	if .Type() == protoMessageType {
		,  := .Interface().(Message)
		,  := .Interface().(Message)
		return Equal(, )
	}
	switch .Kind() {
	case reflect.Bool:
		return .Bool() == .Bool()
	case reflect.Float32, reflect.Float64:
		return .Float() == .Float()
	case reflect.Int32, reflect.Int64:
		return .Int() == .Int()
	case reflect.Interface:
		// Probably a oneof field; compare the inner values.
		,  := .IsNil(), .IsNil()
		if  ||  {
			return  == 
		}
		,  := .Elem(), .Elem()
		if .Type() != .Type() {
			return false
		}
		return (, , nil)
	case reflect.Map:
		if .Len() != .Len() {
			return false
		}
		for ,  := range .MapKeys() {
			 := .MapIndex()
			if !.IsValid() {
				// This key was not found in the second map.
				return false
			}
			if !(.MapIndex(), , nil) {
				return false
			}
		}
		return true
	case reflect.Ptr:
		// Maps may have nil values in them, so check for nil.
		if .IsNil() && .IsNil() {
			return true
		}
		if .IsNil() != .IsNil() {
			return false
		}
		return (.Elem(), .Elem(), )
	case reflect.Slice:
		if .Type().Elem().Kind() == reflect.Uint8 {
			// short circuit: []byte

			// Edge case: if this is in a proto3 message, a zero length
			// bytes field is considered the zero value.
			if  != nil && .proto3 && .Len() == 0 && .Len() == 0 {
				return true
			}
			if .IsNil() != .IsNil() {
				return false
			}
			return bytes.Equal(.Interface().([]byte), .Interface().([]byte))
		}

		if .Len() != .Len() {
			return false
		}
		for  := 0;  < .Len(); ++ {
			if !(.Index(), .Index(), ) {
				return false
			}
		}
		return true
	case reflect.String:
		return .Interface().(string) == .Interface().(string)
	case reflect.Struct:
		return equalStruct(, )
	case reflect.Uint32, reflect.Uint64:
		return .Uint() == .Uint()
	}

	// unknown type, so not a protocol buffer
	log.Printf("proto: don't know how to compare %v", )
	return false
}

// base is the struct type that the extensions are based on.
// x1 and x2 are InternalExtensions.
func equalExtensions( reflect.Type, ,  XXX_InternalExtensions) bool {
	,  := .extensionsRead()
	,  := .extensionsRead()
	return equalExtMap(, , )
}

func equalExtMap( reflect.Type, ,  map[int32]Extension) bool {
	if len() != len() {
		return false
	}

	for ,  := range  {
		,  := []
		if ! {
			return false
		}

		,  := .value, .value

		if  == nil &&  == nil {
			// Both have only encoded form.
			if bytes.Equal(.enc, .enc) {
				continue
			}
			// The bytes are different, but the extensions might still be
			// equal. We need to decode them to compare.
		}

		if  != nil &&  != nil {
			// Both are unencoded.
			if !equalAny(reflect.ValueOf(), reflect.ValueOf(), nil) {
				return false
			}
			continue
		}

		// At least one is encoded. To do a semantically correct comparison
		// we need to unmarshal them first.
		var  *ExtensionDesc
		if  := extensionMaps[];  != nil {
			 = []
		}
		if  == nil {
			// If both have only encoded form and the bytes are the same,
			// it is handled above. We get here when the bytes are different.
			// We don't know how to decode it, so just compare them as byte
			// slices.
			log.Printf("proto: don't know how to compare extension %d of %v", , )
			return false
		}
		var  error
		if  == nil {
			,  = decodeExtension(.enc, )
		}
		if  == nil &&  == nil {
			,  = decodeExtension(.enc, )
		}
		if  != nil {
			// The encoded form is invalid.
			log.Printf("proto: badly encoded extension %d of %v: %v", , , )
			return false
		}
		if !equalAny(reflect.ValueOf(), reflect.ValueOf(), nil) {
			return false
		}
	}

	return true
}