blob: 6f644344a562c9b0a06697efc08bb005c83f20a0 [file] [log] [blame]
Damien Neile6f060f2019-04-23 17:11:02 -07001// Copyright 2019 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5package proto
6
7import (
8 "bytes"
Joe Tsai378c1322019-04-25 23:48:08 -07009 "reflect"
Damien Neile6f060f2019-04-23 17:11:02 -070010
Joe Tsai378c1322019-04-25 23:48:08 -070011 "google.golang.org/protobuf/internal/encoding/wire"
Damien Neile89e6242019-05-13 23:55:40 -070012 pref "google.golang.org/protobuf/reflect/protoreflect"
Damien Neile6f060f2019-04-23 17:11:02 -070013)
14
Joe Tsai378c1322019-04-25 23:48:08 -070015// Equal reports whether two messages are equal.
Damien Neile6f060f2019-04-23 17:11:02 -070016//
Joe Tsai378c1322019-04-25 23:48:08 -070017// Two messages are equal if they belong to the same message descriptor,
18// have the same set of populated known and extension field values,
19// and the same set of unknown fields values.
20//
21// Scalar values are compared with the equivalent of the == operator in Go,
22// except bytes values which are compared using bytes.Equal.
23// Note that this means that floating point NaNs are considered inequal.
24// Message values are compared by recursively calling Equal.
25// Lists are equal if each element value is also equal.
26// Maps are equal if they have the same set of keys, where the pair of values
27// for each key is also equal.
28func Equal(x, y Message) bool {
29 return equalMessage(x.ProtoReflect(), y.ProtoReflect())
Damien Neile6f060f2019-04-23 17:11:02 -070030}
31
32// equalMessage compares two messages.
Joe Tsai378c1322019-04-25 23:48:08 -070033func equalMessage(mx, my pref.Message) bool {
34 if mx.Descriptor() != my.Descriptor() {
Damien Neile6f060f2019-04-23 17:11:02 -070035 return false
36 }
37
Joe Tsai378c1322019-04-25 23:48:08 -070038 if mx.Len() != my.Len() {
39 return false
Damien Neile6f060f2019-04-23 17:11:02 -070040 }
41 equal := true
Joe Tsai378c1322019-04-25 23:48:08 -070042 mx.Range(func(fd pref.FieldDescriptor, vx pref.Value) bool {
43 vy := my.Get(fd)
44 equal = my.Has(fd) && equalField(fd, vx, vy)
45 return equal
Damien Neile6f060f2019-04-23 17:11:02 -070046 })
47 if !equal {
48 return false
49 }
50
Joe Tsai378c1322019-04-25 23:48:08 -070051 return equalUnknown(mx.GetUnknown(), my.GetUnknown())
Damien Neile6f060f2019-04-23 17:11:02 -070052}
53
Joe Tsai378c1322019-04-25 23:48:08 -070054// equalField compares two fields.
55func equalField(fd pref.FieldDescriptor, x, y pref.Value) bool {
Damien Neile6f060f2019-04-23 17:11:02 -070056 switch {
Joe Tsaiac31a352019-05-13 14:32:56 -070057 case fd.IsList():
Joe Tsai378c1322019-04-25 23:48:08 -070058 return equalList(fd, x.List(), y.List())
Damien Neile6f060f2019-04-23 17:11:02 -070059 case fd.IsMap():
Joe Tsai378c1322019-04-25 23:48:08 -070060 return equalMap(fd, x.Map(), y.Map())
Damien Neile6f060f2019-04-23 17:11:02 -070061 default:
Joe Tsai378c1322019-04-25 23:48:08 -070062 return equalValue(fd, x, y)
Damien Neile6f060f2019-04-23 17:11:02 -070063 }
64}
65
Joe Tsai378c1322019-04-25 23:48:08 -070066// equalMap compares two maps.
67func equalMap(fd pref.FieldDescriptor, x, y pref.Map) bool {
68 if x.Len() != y.Len() {
Damien Neile6f060f2019-04-23 17:11:02 -070069 return false
70 }
71 equal := true
Joe Tsai378c1322019-04-25 23:48:08 -070072 x.Range(func(k pref.MapKey, vx pref.Value) bool {
73 vy := y.Get(k)
74 equal = y.Has(k) && equalValue(fd.MapValue(), vx, vy)
75 return equal
Damien Neile6f060f2019-04-23 17:11:02 -070076 })
77 return equal
78}
79
Joe Tsai378c1322019-04-25 23:48:08 -070080// equalList compares two lists.
81func equalList(fd pref.FieldDescriptor, x, y pref.List) bool {
82 if x.Len() != y.Len() {
Damien Neile6f060f2019-04-23 17:11:02 -070083 return false
84 }
Joe Tsai378c1322019-04-25 23:48:08 -070085 for i := x.Len() - 1; i >= 0; i-- {
86 if !equalValue(fd, x.Get(i), y.Get(i)) {
Damien Neile6f060f2019-04-23 17:11:02 -070087 return false
88 }
89 }
90 return true
91}
92
Joe Tsai378c1322019-04-25 23:48:08 -070093// equalValue compares two singular values.
94func equalValue(fd pref.FieldDescriptor, x, y pref.Value) bool {
Damien Neile6f060f2019-04-23 17:11:02 -070095 switch {
96 case fd.Message() != nil:
Joe Tsai378c1322019-04-25 23:48:08 -070097 return equalMessage(x.Message(), y.Message())
Damien Neile6f060f2019-04-23 17:11:02 -070098 case fd.Kind() == pref.BytesKind:
Joe Tsai378c1322019-04-25 23:48:08 -070099 return bytes.Equal(x.Bytes(), y.Bytes())
Damien Neile6f060f2019-04-23 17:11:02 -0700100 default:
Joe Tsai378c1322019-04-25 23:48:08 -0700101 return x.Interface() == y.Interface()
Damien Neile6f060f2019-04-23 17:11:02 -0700102 }
103}
Joe Tsai378c1322019-04-25 23:48:08 -0700104
105// equalUnknown compares unknown fields by direct comparison on the raw bytes
106// of each individual field number.
107func equalUnknown(x, y pref.RawFields) bool {
108 if len(x) != len(y) {
109 return false
110 }
111 if bytes.Equal([]byte(x), []byte(y)) {
112 return true
113 }
114
115 mx := make(map[pref.FieldNumber]pref.RawFields)
116 my := make(map[pref.FieldNumber]pref.RawFields)
117 for len(x) > 0 {
118 fnum, _, n := wire.ConsumeField(x)
119 mx[fnum] = append(mx[fnum], x[:n]...)
120 x = x[n:]
121 }
122 for len(y) > 0 {
123 fnum, _, n := wire.ConsumeField(y)
124 my[fnum] = append(my[fnum], y[:n]...)
125 y = y[n:]
126 }
127 return reflect.DeepEqual(mx, my)
128}