1*1c12ee1eSDan Willemsen// Copyright 2022 The Go Authors. All rights reserved. 2*1c12ee1eSDan Willemsen// Use of this source code is governed by a BSD-style 3*1c12ee1eSDan Willemsen// license that can be found in the LICENSE file. 4*1c12ee1eSDan Willemsen 5*1c12ee1eSDan Willemsenpackage protoreflect 6*1c12ee1eSDan Willemsen 7*1c12ee1eSDan Willemsenimport ( 8*1c12ee1eSDan Willemsen "bytes" 9*1c12ee1eSDan Willemsen "fmt" 10*1c12ee1eSDan Willemsen "math" 11*1c12ee1eSDan Willemsen "reflect" 12*1c12ee1eSDan Willemsen 13*1c12ee1eSDan Willemsen "google.golang.org/protobuf/encoding/protowire" 14*1c12ee1eSDan Willemsen) 15*1c12ee1eSDan Willemsen 16*1c12ee1eSDan Willemsen// Equal reports whether v1 and v2 are recursively equal. 17*1c12ee1eSDan Willemsen// 18*1c12ee1eSDan Willemsen// - Values of different types are always unequal. 19*1c12ee1eSDan Willemsen// 20*1c12ee1eSDan Willemsen// - Bytes values are equal if they contain identical bytes. 21*1c12ee1eSDan Willemsen// Empty bytes (regardless of nil-ness) are considered equal. 22*1c12ee1eSDan Willemsen// 23*1c12ee1eSDan Willemsen// - Floating point values are equal if they contain the same value. 24*1c12ee1eSDan Willemsen// Unlike the == operator, a NaN is equal to another NaN. 25*1c12ee1eSDan Willemsen// 26*1c12ee1eSDan Willemsen// - Enums are equal if they contain the same number. 27*1c12ee1eSDan Willemsen// Since Value does not contain an enum descriptor, 28*1c12ee1eSDan Willemsen// enum values do not consider the type of the enum. 29*1c12ee1eSDan Willemsen// 30*1c12ee1eSDan Willemsen// - Other scalar values are equal if they contain the same value. 31*1c12ee1eSDan Willemsen// 32*1c12ee1eSDan Willemsen// - Message values are equal if they belong to the same message descriptor, 33*1c12ee1eSDan Willemsen// have the same set of populated known and extension field values, 34*1c12ee1eSDan Willemsen// and the same set of unknown fields values. 35*1c12ee1eSDan Willemsen// 36*1c12ee1eSDan Willemsen// - Lists are equal if they are the same length and 37*1c12ee1eSDan Willemsen// each corresponding element is equal. 38*1c12ee1eSDan Willemsen// 39*1c12ee1eSDan Willemsen// - Maps are equal if they have the same set of keys and 40*1c12ee1eSDan Willemsen// the corresponding value for each key is equal. 41*1c12ee1eSDan Willemsenfunc (v1 Value) Equal(v2 Value) bool { 42*1c12ee1eSDan Willemsen return equalValue(v1, v2) 43*1c12ee1eSDan Willemsen} 44*1c12ee1eSDan Willemsen 45*1c12ee1eSDan Willemsenfunc equalValue(x, y Value) bool { 46*1c12ee1eSDan Willemsen eqType := x.typ == y.typ 47*1c12ee1eSDan Willemsen switch x.typ { 48*1c12ee1eSDan Willemsen case nilType: 49*1c12ee1eSDan Willemsen return eqType 50*1c12ee1eSDan Willemsen case boolType: 51*1c12ee1eSDan Willemsen return eqType && x.Bool() == y.Bool() 52*1c12ee1eSDan Willemsen case int32Type, int64Type: 53*1c12ee1eSDan Willemsen return eqType && x.Int() == y.Int() 54*1c12ee1eSDan Willemsen case uint32Type, uint64Type: 55*1c12ee1eSDan Willemsen return eqType && x.Uint() == y.Uint() 56*1c12ee1eSDan Willemsen case float32Type, float64Type: 57*1c12ee1eSDan Willemsen return eqType && equalFloat(x.Float(), y.Float()) 58*1c12ee1eSDan Willemsen case stringType: 59*1c12ee1eSDan Willemsen return eqType && x.String() == y.String() 60*1c12ee1eSDan Willemsen case bytesType: 61*1c12ee1eSDan Willemsen return eqType && bytes.Equal(x.Bytes(), y.Bytes()) 62*1c12ee1eSDan Willemsen case enumType: 63*1c12ee1eSDan Willemsen return eqType && x.Enum() == y.Enum() 64*1c12ee1eSDan Willemsen default: 65*1c12ee1eSDan Willemsen switch x := x.Interface().(type) { 66*1c12ee1eSDan Willemsen case Message: 67*1c12ee1eSDan Willemsen y, ok := y.Interface().(Message) 68*1c12ee1eSDan Willemsen return ok && equalMessage(x, y) 69*1c12ee1eSDan Willemsen case List: 70*1c12ee1eSDan Willemsen y, ok := y.Interface().(List) 71*1c12ee1eSDan Willemsen return ok && equalList(x, y) 72*1c12ee1eSDan Willemsen case Map: 73*1c12ee1eSDan Willemsen y, ok := y.Interface().(Map) 74*1c12ee1eSDan Willemsen return ok && equalMap(x, y) 75*1c12ee1eSDan Willemsen default: 76*1c12ee1eSDan Willemsen panic(fmt.Sprintf("unknown type: %T", x)) 77*1c12ee1eSDan Willemsen } 78*1c12ee1eSDan Willemsen } 79*1c12ee1eSDan Willemsen} 80*1c12ee1eSDan Willemsen 81*1c12ee1eSDan Willemsen// equalFloat compares two floats, where NaNs are treated as equal. 82*1c12ee1eSDan Willemsenfunc equalFloat(x, y float64) bool { 83*1c12ee1eSDan Willemsen if math.IsNaN(x) || math.IsNaN(y) { 84*1c12ee1eSDan Willemsen return math.IsNaN(x) && math.IsNaN(y) 85*1c12ee1eSDan Willemsen } 86*1c12ee1eSDan Willemsen return x == y 87*1c12ee1eSDan Willemsen} 88*1c12ee1eSDan Willemsen 89*1c12ee1eSDan Willemsen// equalMessage compares two messages. 90*1c12ee1eSDan Willemsenfunc equalMessage(mx, my Message) bool { 91*1c12ee1eSDan Willemsen if mx.Descriptor() != my.Descriptor() { 92*1c12ee1eSDan Willemsen return false 93*1c12ee1eSDan Willemsen } 94*1c12ee1eSDan Willemsen 95*1c12ee1eSDan Willemsen nx := 0 96*1c12ee1eSDan Willemsen equal := true 97*1c12ee1eSDan Willemsen mx.Range(func(fd FieldDescriptor, vx Value) bool { 98*1c12ee1eSDan Willemsen nx++ 99*1c12ee1eSDan Willemsen vy := my.Get(fd) 100*1c12ee1eSDan Willemsen equal = my.Has(fd) && equalValue(vx, vy) 101*1c12ee1eSDan Willemsen return equal 102*1c12ee1eSDan Willemsen }) 103*1c12ee1eSDan Willemsen if !equal { 104*1c12ee1eSDan Willemsen return false 105*1c12ee1eSDan Willemsen } 106*1c12ee1eSDan Willemsen ny := 0 107*1c12ee1eSDan Willemsen my.Range(func(fd FieldDescriptor, vx Value) bool { 108*1c12ee1eSDan Willemsen ny++ 109*1c12ee1eSDan Willemsen return true 110*1c12ee1eSDan Willemsen }) 111*1c12ee1eSDan Willemsen if nx != ny { 112*1c12ee1eSDan Willemsen return false 113*1c12ee1eSDan Willemsen } 114*1c12ee1eSDan Willemsen 115*1c12ee1eSDan Willemsen return equalUnknown(mx.GetUnknown(), my.GetUnknown()) 116*1c12ee1eSDan Willemsen} 117*1c12ee1eSDan Willemsen 118*1c12ee1eSDan Willemsen// equalList compares two lists. 119*1c12ee1eSDan Willemsenfunc equalList(x, y List) bool { 120*1c12ee1eSDan Willemsen if x.Len() != y.Len() { 121*1c12ee1eSDan Willemsen return false 122*1c12ee1eSDan Willemsen } 123*1c12ee1eSDan Willemsen for i := x.Len() - 1; i >= 0; i-- { 124*1c12ee1eSDan Willemsen if !equalValue(x.Get(i), y.Get(i)) { 125*1c12ee1eSDan Willemsen return false 126*1c12ee1eSDan Willemsen } 127*1c12ee1eSDan Willemsen } 128*1c12ee1eSDan Willemsen return true 129*1c12ee1eSDan Willemsen} 130*1c12ee1eSDan Willemsen 131*1c12ee1eSDan Willemsen// equalMap compares two maps. 132*1c12ee1eSDan Willemsenfunc equalMap(x, y Map) bool { 133*1c12ee1eSDan Willemsen if x.Len() != y.Len() { 134*1c12ee1eSDan Willemsen return false 135*1c12ee1eSDan Willemsen } 136*1c12ee1eSDan Willemsen equal := true 137*1c12ee1eSDan Willemsen x.Range(func(k MapKey, vx Value) bool { 138*1c12ee1eSDan Willemsen vy := y.Get(k) 139*1c12ee1eSDan Willemsen equal = y.Has(k) && equalValue(vx, vy) 140*1c12ee1eSDan Willemsen return equal 141*1c12ee1eSDan Willemsen }) 142*1c12ee1eSDan Willemsen return equal 143*1c12ee1eSDan Willemsen} 144*1c12ee1eSDan Willemsen 145*1c12ee1eSDan Willemsen// equalUnknown compares unknown fields by direct comparison on the raw bytes 146*1c12ee1eSDan Willemsen// of each individual field number. 147*1c12ee1eSDan Willemsenfunc equalUnknown(x, y RawFields) bool { 148*1c12ee1eSDan Willemsen if len(x) != len(y) { 149*1c12ee1eSDan Willemsen return false 150*1c12ee1eSDan Willemsen } 151*1c12ee1eSDan Willemsen if bytes.Equal([]byte(x), []byte(y)) { 152*1c12ee1eSDan Willemsen return true 153*1c12ee1eSDan Willemsen } 154*1c12ee1eSDan Willemsen 155*1c12ee1eSDan Willemsen mx := make(map[FieldNumber]RawFields) 156*1c12ee1eSDan Willemsen my := make(map[FieldNumber]RawFields) 157*1c12ee1eSDan Willemsen for len(x) > 0 { 158*1c12ee1eSDan Willemsen fnum, _, n := protowire.ConsumeField(x) 159*1c12ee1eSDan Willemsen mx[fnum] = append(mx[fnum], x[:n]...) 160*1c12ee1eSDan Willemsen x = x[n:] 161*1c12ee1eSDan Willemsen } 162*1c12ee1eSDan Willemsen for len(y) > 0 { 163*1c12ee1eSDan Willemsen fnum, _, n := protowire.ConsumeField(y) 164*1c12ee1eSDan Willemsen my[fnum] = append(my[fnum], y[:n]...) 165*1c12ee1eSDan Willemsen y = y[n:] 166*1c12ee1eSDan Willemsen } 167*1c12ee1eSDan Willemsen return reflect.DeepEqual(mx, my) 168*1c12ee1eSDan Willemsen} 169