// Copyright 2019 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package proto

import (
	
	
	

	
	
)

// Equal reports whether two messages are equal.
// If two messages marshal to the same bytes under deterministic serialization,
// then Equal is guaranteed to report true.
//
// Two messages are equal if they belong to the same message descriptor,
// have the same set of populated known and extension field values,
// and the same set of unknown fields values. If either of the top-level
// messages are invalid, then Equal reports true only if both are invalid.
//
// Scalar values are compared with the equivalent of the == operator in Go,
// except bytes values which are compared using bytes.Equal and
// floating point values which specially treat NaNs as equal.
// Message values are compared by recursively calling Equal.
// Lists are equal if each element value is also equal.
// Maps are equal if they have the same set of keys, where the pair of values
// for each key is also equal.
func (,  Message) bool {
	if  == nil ||  == nil {
		return  == nil &&  == nil
	}
	if reflect.TypeOf().Kind() == reflect.Ptr &&  ==  {
		// Avoid an expensive comparison if both inputs are identical pointers.
		return true
	}
	 := .ProtoReflect()
	 := .ProtoReflect()
	if .IsValid() != .IsValid() {
		return false
	}
	return equalMessage(, )
}

// equalMessage compares two messages.
func (,  protoreflect.Message) bool {
	if .Descriptor() != .Descriptor() {
		return false
	}

	 := 0
	 := true
	.Range(func( protoreflect.FieldDescriptor,  protoreflect.Value) bool {
		++
		 := .Get()
		 = .Has() && equalField(, , )
		return 
	})
	if ! {
		return false
	}
	 := 0
	.Range(func( protoreflect.FieldDescriptor,  protoreflect.Value) bool {
		++
		return true
	})
	if  !=  {
		return false
	}

	return equalUnknown(.GetUnknown(), .GetUnknown())
}

// equalField compares two fields.
func ( protoreflect.FieldDescriptor, ,  protoreflect.Value) bool {
	switch {
	case .IsList():
		return equalList(, .List(), .List())
	case .IsMap():
		return equalMap(, .Map(), .Map())
	default:
		return equalValue(, , )
	}
}

// equalMap compares two maps.
func ( protoreflect.FieldDescriptor, ,  protoreflect.Map) bool {
	if .Len() != .Len() {
		return false
	}
	 := true
	.Range(func( protoreflect.MapKey,  protoreflect.Value) bool {
		 := .Get()
		 = .Has() && equalValue(.MapValue(), , )
		return 
	})
	return 
}

// equalList compares two lists.
func ( protoreflect.FieldDescriptor, ,  protoreflect.List) bool {
	if .Len() != .Len() {
		return false
	}
	for  := .Len() - 1;  >= 0; -- {
		if !equalValue(, .Get(), .Get()) {
			return false
		}
	}
	return true
}

// equalValue compares two singular values.
func ( protoreflect.FieldDescriptor, ,  protoreflect.Value) bool {
	switch .Kind() {
	case protoreflect.BoolKind:
		return .Bool() == .Bool()
	case protoreflect.EnumKind:
		return .Enum() == .Enum()
	case protoreflect.Int32Kind, protoreflect.Sint32Kind,
		protoreflect.Int64Kind, protoreflect.Sint64Kind,
		protoreflect.Sfixed32Kind, protoreflect.Sfixed64Kind:
		return .Int() == .Int()
	case protoreflect.Uint32Kind, protoreflect.Uint64Kind,
		protoreflect.Fixed32Kind, protoreflect.Fixed64Kind:
		return .Uint() == .Uint()
	case protoreflect.FloatKind, protoreflect.DoubleKind:
		 := .Float()
		 := .Float()
		if math.IsNaN() || math.IsNaN() {
			return math.IsNaN() && math.IsNaN()
		}
		return  == 
	case protoreflect.StringKind:
		return .String() == .String()
	case protoreflect.BytesKind:
		return bytes.Equal(.Bytes(), .Bytes())
	case protoreflect.MessageKind, protoreflect.GroupKind:
		return equalMessage(.Message(), .Message())
	default:
		return .Interface() == .Interface()
	}
}

// equalUnknown compares unknown fields by direct comparison on the raw bytes
// of each individual field number.
func (,  protoreflect.RawFields) bool {
	if len() != len() {
		return false
	}
	if bytes.Equal([]byte(), []byte()) {
		return true
	}

	 := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
	 := make(map[protoreflect.FieldNumber]protoreflect.RawFields)
	for len() > 0 {
		, ,  := protowire.ConsumeField()
		[] = append([], [:]...)
		 = [:]
	}
	for len() > 0 {
		, ,  := protowire.ConsumeField()
		[] = append([], [:]...)
		 = [:]
	}
	return reflect.DeepEqual(, )
}