1// 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 protocmp
6
7import (
8	"bytes"
9	"fmt"
10	"math"
11	"reflect"
12	"strings"
13
14	"github.com/google/go-cmp/cmp"
15	"github.com/google/go-cmp/cmp/cmpopts"
16
17	"google.golang.org/protobuf/proto"
18	"google.golang.org/protobuf/reflect/protoreflect"
19)
20
21var (
22	enumReflectType    = reflect.TypeOf(Enum{})
23	messageReflectType = reflect.TypeOf(Message{})
24)
25
26// FilterEnum filters opt to only be applicable on standalone Enums,
27// singular fields of enums, list fields of enums, or map fields of enum values,
28// where the enum is the same type as the specified enum.
29//
30// The Go type of the last path step may be an:
31//	• Enum for singular fields, elements of a repeated field,
32//	values of a map field, or standalone Enums
33//	• []Enum for list fields
34//	• map[K]Enum for map fields
35//	• interface{} for a Message map entry value
36//
37// This must be used in conjunction with Transform.
38func FilterEnum(enum protoreflect.Enum, opt cmp.Option) cmp.Option {
39	return FilterDescriptor(enum.Descriptor(), opt)
40}
41
42// FilterMessage filters opt to only be applicable on standalone Messages,
43// singular fields of messages, list fields of messages, or map fields of
44// message values, where the message is the same type as the specified message.
45//
46// The Go type of the last path step may be an:
47//	• Message for singular fields, elements of a repeated field,
48//	values of a map field, or standalone Messages
49//	• []Message for list fields
50//	• map[K]Message for map fields
51//	• interface{} for a Message map entry value
52//
53// This must be used in conjunction with Transform.
54func FilterMessage(message proto.Message, opt cmp.Option) cmp.Option {
55	return FilterDescriptor(message.ProtoReflect().Descriptor(), opt)
56}
57
58// FilterField filters opt to only be applicable on the specified field
59// in the message. It panics if a field of the given name does not exist.
60//
61// The Go type of the last path step may be an:
62//	• T for singular fields
63//	• []T for list fields
64//	• map[K]T for map fields
65//	• interface{} for a Message map entry value
66//
67// This must be used in conjunction with Transform.
68func FilterField(message proto.Message, name protoreflect.Name, opt cmp.Option) cmp.Option {
69	md := message.ProtoReflect().Descriptor()
70	return FilterDescriptor(mustFindFieldDescriptor(md, name), opt)
71}
72
73// FilterOneof filters opt to only be applicable on all fields within the
74// specified oneof in the message. It panics if a oneof of the given name
75// does not exist.
76//
77// The Go type of the last path step may be an:
78//	• T for singular fields
79//	• []T for list fields
80//	• map[K]T for map fields
81//	• interface{} for a Message map entry value
82//
83// This must be used in conjunction with Transform.
84func FilterOneof(message proto.Message, name protoreflect.Name, opt cmp.Option) cmp.Option {
85	md := message.ProtoReflect().Descriptor()
86	return FilterDescriptor(mustFindOneofDescriptor(md, name), opt)
87}
88
89// FilterDescriptor ignores the specified descriptor.
90//
91// The following descriptor types may be specified:
92//	• protoreflect.EnumDescriptor
93//	• protoreflect.MessageDescriptor
94//	• protoreflect.FieldDescriptor
95//	• protoreflect.OneofDescriptor
96//
97// For the behavior of each, see the corresponding filter function.
98// Since this filter accepts a protoreflect.FieldDescriptor, it can be used
99// to also filter for extension fields as a protoreflect.ExtensionDescriptor
100// is just an alias to protoreflect.FieldDescriptor.
101//
102// This must be used in conjunction with Transform.
103func FilterDescriptor(desc protoreflect.Descriptor, opt cmp.Option) cmp.Option {
104	f := newNameFilters(desc)
105	return cmp.FilterPath(f.Filter, opt)
106}
107
108// IgnoreEnums ignores all enums of the specified types.
109// It is equivalent to FilterEnum(enum, cmp.Ignore()) for each enum.
110//
111// This must be used in conjunction with Transform.
112func IgnoreEnums(enums ...protoreflect.Enum) cmp.Option {
113	var ds []protoreflect.Descriptor
114	for _, e := range enums {
115		ds = append(ds, e.Descriptor())
116	}
117	return IgnoreDescriptors(ds...)
118}
119
120// IgnoreMessages ignores all messages of the specified types.
121// It is equivalent to FilterMessage(message, cmp.Ignore()) for each message.
122//
123// This must be used in conjunction with Transform.
124func IgnoreMessages(messages ...proto.Message) cmp.Option {
125	var ds []protoreflect.Descriptor
126	for _, m := range messages {
127		ds = append(ds, m.ProtoReflect().Descriptor())
128	}
129	return IgnoreDescriptors(ds...)
130}
131
132// IgnoreFields ignores the specified fields in the specified message.
133// It is equivalent to FilterField(message, name, cmp.Ignore()) for each field
134// in the message.
135//
136// This must be used in conjunction with Transform.
137func IgnoreFields(message proto.Message, names ...protoreflect.Name) cmp.Option {
138	var ds []protoreflect.Descriptor
139	md := message.ProtoReflect().Descriptor()
140	for _, s := range names {
141		ds = append(ds, mustFindFieldDescriptor(md, s))
142	}
143	return IgnoreDescriptors(ds...)
144}
145
146// IgnoreOneofs ignores fields of the specified oneofs in the specified message.
147// It is equivalent to FilterOneof(message, name, cmp.Ignore()) for each oneof
148// in the message.
149//
150// This must be used in conjunction with Transform.
151func IgnoreOneofs(message proto.Message, names ...protoreflect.Name) cmp.Option {
152	var ds []protoreflect.Descriptor
153	md := message.ProtoReflect().Descriptor()
154	for _, s := range names {
155		ds = append(ds, mustFindOneofDescriptor(md, s))
156	}
157	return IgnoreDescriptors(ds...)
158}
159
160// IgnoreDescriptors ignores the specified set of descriptors.
161// It is equivalent to FilterDescriptor(desc, cmp.Ignore()) for each descriptor.
162//
163// This must be used in conjunction with Transform.
164func IgnoreDescriptors(descs ...protoreflect.Descriptor) cmp.Option {
165	return cmp.FilterPath(newNameFilters(descs...).Filter, cmp.Ignore())
166}
167
168func mustFindFieldDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.FieldDescriptor {
169	d := findDescriptor(md, s)
170	if fd, ok := d.(protoreflect.FieldDescriptor); ok && fd.Name() == s {
171		return fd
172	}
173
174	var suggestion string
175	switch d.(type) {
176	case protoreflect.FieldDescriptor:
177		suggestion = fmt.Sprintf("; consider specifying field %q instead", d.Name())
178	case protoreflect.OneofDescriptor:
179		suggestion = fmt.Sprintf("; consider specifying oneof %q with IgnoreOneofs instead", d.Name())
180	}
181	panic(fmt.Sprintf("message %q has no field %q%s", md.FullName(), s, suggestion))
182}
183
184func mustFindOneofDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.OneofDescriptor {
185	d := findDescriptor(md, s)
186	if od, ok := d.(protoreflect.OneofDescriptor); ok && d.Name() == s {
187		return od
188	}
189
190	var suggestion string
191	switch d.(type) {
192	case protoreflect.OneofDescriptor:
193		suggestion = fmt.Sprintf("; consider specifying oneof %q instead", d.Name())
194	case protoreflect.FieldDescriptor:
195		suggestion = fmt.Sprintf("; consider specifying field %q with IgnoreFields instead", d.Name())
196	}
197	panic(fmt.Sprintf("message %q has no oneof %q%s", md.FullName(), s, suggestion))
198}
199
200func findDescriptor(md protoreflect.MessageDescriptor, s protoreflect.Name) protoreflect.Descriptor {
201	// Exact match.
202	if fd := md.Fields().ByName(s); fd != nil {
203		return fd
204	}
205	if od := md.Oneofs().ByName(s); od != nil {
206		return od
207	}
208
209	// Best-effort match.
210	//
211	// It's a common user mistake to use the CameCased field name as it appears
212	// in the generated Go struct. Instead of complaining that it doesn't exist,
213	// suggest the real protobuf name that the user may have desired.
214	normalize := func(s protoreflect.Name) string {
215		return strings.Replace(strings.ToLower(string(s)), "_", "", -1)
216	}
217	for i := 0; i < md.Fields().Len(); i++ {
218		if fd := md.Fields().Get(i); normalize(fd.Name()) == normalize(s) {
219			return fd
220		}
221	}
222	for i := 0; i < md.Oneofs().Len(); i++ {
223		if od := md.Oneofs().Get(i); normalize(od.Name()) == normalize(s) {
224			return od
225		}
226	}
227	return nil
228}
229
230type nameFilters struct {
231	names map[protoreflect.FullName]bool
232}
233
234func newNameFilters(descs ...protoreflect.Descriptor) *nameFilters {
235	f := &nameFilters{names: make(map[protoreflect.FullName]bool)}
236	for _, d := range descs {
237		switch d := d.(type) {
238		case protoreflect.EnumDescriptor:
239			f.names[d.FullName()] = true
240		case protoreflect.MessageDescriptor:
241			f.names[d.FullName()] = true
242		case protoreflect.FieldDescriptor:
243			f.names[d.FullName()] = true
244		case protoreflect.OneofDescriptor:
245			for i := 0; i < d.Fields().Len(); i++ {
246				f.names[d.Fields().Get(i).FullName()] = true
247			}
248		default:
249			panic("invalid descriptor type")
250		}
251	}
252	return f
253}
254
255func (f *nameFilters) Filter(p cmp.Path) bool {
256	vx, vy := p.Last().Values()
257	return (f.filterValue(vx) && f.filterValue(vy)) || f.filterFields(p)
258}
259
260func (f *nameFilters) filterFields(p cmp.Path) bool {
261	// Trim off trailing type-assertions so that the filter can match on the
262	// concrete value held within an interface value.
263	if _, ok := p.Last().(cmp.TypeAssertion); ok {
264		p = p[:len(p)-1]
265	}
266
267	// Filter for Message maps.
268	mi, ok := p.Index(-1).(cmp.MapIndex)
269	if !ok {
270		return false
271	}
272	ps := p.Index(-2)
273	if ps.Type() != messageReflectType {
274		return false
275	}
276
277	// Check field name.
278	vx, vy := ps.Values()
279	mx := vx.Interface().(Message)
280	my := vy.Interface().(Message)
281	k := mi.Key().String()
282	if f.filterFieldName(mx, k) && f.filterFieldName(my, k) {
283		return true
284	}
285
286	// Check field value.
287	vx, vy = mi.Values()
288	if f.filterFieldValue(vx) && f.filterFieldValue(vy) {
289		return true
290	}
291
292	return false
293}
294
295func (f *nameFilters) filterFieldName(m Message, k string) bool {
296	if md := m.Descriptor(); md != nil {
297		switch {
298		case protoreflect.Name(k).IsValid():
299			return f.names[md.Fields().ByName(protoreflect.Name(k)).FullName()]
300		case strings.HasPrefix(k, "[") && strings.HasSuffix(k, "]"):
301			return f.names[protoreflect.FullName(k[1:len(k)-1])]
302		}
303	}
304	return false
305}
306
307func (f *nameFilters) filterFieldValue(v reflect.Value) bool {
308	if !v.IsValid() {
309		return true // implies missing slice element or map entry
310	}
311	v = v.Elem() // map entries are always populated values
312	switch t := v.Type(); {
313	case t == enumReflectType || t == messageReflectType:
314		// Check for singular message or enum field.
315		return f.filterValue(v)
316	case t.Kind() == reflect.Slice && (t.Elem() == enumReflectType || t.Elem() == messageReflectType):
317		// Check for list field of enum or message type.
318		return f.filterValue(v.Index(0))
319	case t.Kind() == reflect.Map && (t.Elem() == enumReflectType || t.Elem() == messageReflectType):
320		// Check for map field of enum or message type.
321		return f.filterValue(v.MapIndex(v.MapKeys()[0]))
322	}
323	return false
324}
325
326func (f *nameFilters) filterValue(v reflect.Value) bool {
327	if !v.IsValid() {
328		return true // implies missing slice element or map entry
329	}
330	if !v.CanInterface() {
331		return false // implies unexported struct field
332	}
333	switch v := v.Interface().(type) {
334	case Enum:
335		return v.Descriptor() != nil && f.names[v.Descriptor().FullName()]
336	case Message:
337		return v.Descriptor() != nil && f.names[v.Descriptor().FullName()]
338	}
339	return false
340}
341
342// IgnoreDefaultScalars ignores singular scalars that are unpopulated or
343// explicitly set to the default value.
344// This option does not effect elements in a list or entries in a map.
345//
346// This must be used in conjunction with Transform.
347func IgnoreDefaultScalars() cmp.Option {
348	return cmp.FilterPath(func(p cmp.Path) bool {
349		// Filter for Message maps.
350		mi, ok := p.Index(-1).(cmp.MapIndex)
351		if !ok {
352			return false
353		}
354		ps := p.Index(-2)
355		if ps.Type() != messageReflectType {
356			return false
357		}
358
359		// Check whether both fields are default or unpopulated scalars.
360		vx, vy := ps.Values()
361		mx := vx.Interface().(Message)
362		my := vy.Interface().(Message)
363		k := mi.Key().String()
364		return isDefaultScalar(mx, k) && isDefaultScalar(my, k)
365	}, cmp.Ignore())
366}
367
368func isDefaultScalar(m Message, k string) bool {
369	if _, ok := m[k]; !ok {
370		return true
371	}
372
373	var fd protoreflect.FieldDescriptor
374	switch mt := m[messageTypeKey].(messageType); {
375	case protoreflect.Name(k).IsValid():
376		fd = mt.md.Fields().ByName(protoreflect.Name(k))
377	case strings.HasPrefix(k, "[") && strings.HasSuffix(k, "]"):
378		fd = mt.xds[protoreflect.FullName(k[1:len(k)-1])]
379	}
380	if fd == nil || !fd.Default().IsValid() {
381		return false
382	}
383	switch fd.Kind() {
384	case protoreflect.BytesKind:
385		v, ok := m[k].([]byte)
386		return ok && bytes.Equal(fd.Default().Bytes(), v)
387	case protoreflect.FloatKind:
388		v, ok := m[k].(float32)
389		return ok && equalFloat64(fd.Default().Float(), float64(v))
390	case protoreflect.DoubleKind:
391		v, ok := m[k].(float64)
392		return ok && equalFloat64(fd.Default().Float(), float64(v))
393	case protoreflect.EnumKind:
394		v, ok := m[k].(Enum)
395		return ok && fd.Default().Enum() == v.Number()
396	default:
397		return reflect.DeepEqual(fd.Default().Interface(), m[k])
398	}
399}
400
401func equalFloat64(x, y float64) bool {
402	return x == y || (math.IsNaN(x) && math.IsNaN(y))
403}
404
405// IgnoreEmptyMessages ignores messages that are empty or unpopulated.
406// It applies to standalone Messages, singular message fields,
407// list fields of messages, and map fields of message values.
408//
409// This must be used in conjunction with Transform.
410func IgnoreEmptyMessages() cmp.Option {
411	return cmp.FilterPath(func(p cmp.Path) bool {
412		vx, vy := p.Last().Values()
413		return (isEmptyMessage(vx) && isEmptyMessage(vy)) || isEmptyMessageFields(p)
414	}, cmp.Ignore())
415}
416
417func isEmptyMessageFields(p cmp.Path) bool {
418	// Filter for Message maps.
419	mi, ok := p.Index(-1).(cmp.MapIndex)
420	if !ok {
421		return false
422	}
423	ps := p.Index(-2)
424	if ps.Type() != messageReflectType {
425		return false
426	}
427
428	// Check field value.
429	vx, vy := mi.Values()
430	if isEmptyMessageFieldValue(vx) && isEmptyMessageFieldValue(vy) {
431		return true
432	}
433
434	return false
435}
436
437func isEmptyMessageFieldValue(v reflect.Value) bool {
438	if !v.IsValid() {
439		return true // implies missing slice element or map entry
440	}
441	v = v.Elem() // map entries are always populated values
442	switch t := v.Type(); {
443	case t == messageReflectType:
444		// Check singular field for empty message.
445		if !isEmptyMessage(v) {
446			return false
447		}
448	case t.Kind() == reflect.Slice && t.Elem() == messageReflectType:
449		// Check list field for all empty message elements.
450		for i := 0; i < v.Len(); i++ {
451			if !isEmptyMessage(v.Index(i)) {
452				return false
453			}
454		}
455	case t.Kind() == reflect.Map && t.Elem() == messageReflectType:
456		// Check map field for all empty message values.
457		for _, k := range v.MapKeys() {
458			if !isEmptyMessage(v.MapIndex(k)) {
459				return false
460			}
461		}
462	default:
463		return false
464	}
465	return true
466}
467
468func isEmptyMessage(v reflect.Value) bool {
469	if !v.IsValid() {
470		return true // implies missing slice element or map entry
471	}
472	if !v.CanInterface() {
473		return false // implies unexported struct field
474	}
475	if m, ok := v.Interface().(Message); ok {
476		for k := range m {
477			if k != messageTypeKey && k != messageInvalidKey {
478				return false
479			}
480		}
481		return true
482	}
483	return false
484}
485
486// IgnoreUnknown ignores unknown fields in all messages.
487//
488// This must be used in conjunction with Transform.
489func IgnoreUnknown() cmp.Option {
490	return cmp.FilterPath(func(p cmp.Path) bool {
491		// Filter for Message maps.
492		mi, ok := p.Index(-1).(cmp.MapIndex)
493		if !ok {
494			return false
495		}
496		ps := p.Index(-2)
497		if ps.Type() != messageReflectType {
498			return false
499		}
500
501		// Filter for unknown fields (which always have a numeric map key).
502		return strings.Trim(mi.Key().String(), "0123456789") == ""
503	}, cmp.Ignore())
504}
505
506// SortRepeated sorts repeated fields of the specified element type.
507// The less function must be of the form "func(T, T) bool" where T is the
508// Go element type for the repeated field kind.
509//
510// The element type T can be one of the following:
511//	• Go type for a protobuf scalar kind except for an enum
512//	  (i.e., bool, int32, int64, uint32, uint64, float32, float64, string, and []byte)
513//	• E where E is a concrete enum type that implements protoreflect.Enum
514//	• M where M is a concrete message type that implement proto.Message
515//
516// This option only applies to repeated fields within a protobuf message.
517// It does not operate on higher-order Go types that seem like a repeated field.
518// For example, a []T outside the context of a protobuf message will not be
519// handled by this option. To sort Go slices that are not repeated fields,
520// consider using "github.com/google/go-cmp/cmp/cmpopts".SortSlices instead.
521//
522// This must be used in conjunction with Transform.
523func SortRepeated(lessFunc interface{}) cmp.Option {
524	t, ok := checkTTBFunc(lessFunc)
525	if !ok {
526		panic(fmt.Sprintf("invalid less function: %T", lessFunc))
527	}
528
529	var opt cmp.Option
530	var sliceType reflect.Type
531	switch vf := reflect.ValueOf(lessFunc); {
532	case t.Implements(enumV2Type):
533		et := reflect.Zero(t).Interface().(protoreflect.Enum).Type()
534		lessFunc = func(x, y Enum) bool {
535			vx := reflect.ValueOf(et.New(x.Number()))
536			vy := reflect.ValueOf(et.New(y.Number()))
537			return vf.Call([]reflect.Value{vx, vy})[0].Bool()
538		}
539		opt = FilterDescriptor(et.Descriptor(), cmpopts.SortSlices(lessFunc))
540		sliceType = reflect.SliceOf(enumReflectType)
541	case t.Implements(messageV2Type):
542		mt := reflect.Zero(t).Interface().(protoreflect.ProtoMessage).ProtoReflect().Type()
543		lessFunc = func(x, y Message) bool {
544			mx := mt.New().Interface()
545			my := mt.New().Interface()
546			proto.Merge(mx, x)
547			proto.Merge(my, y)
548			vx := reflect.ValueOf(mx)
549			vy := reflect.ValueOf(my)
550			return vf.Call([]reflect.Value{vx, vy})[0].Bool()
551		}
552		opt = FilterDescriptor(mt.Descriptor(), cmpopts.SortSlices(lessFunc))
553		sliceType = reflect.SliceOf(messageReflectType)
554	default:
555		switch t {
556		case reflect.TypeOf(bool(false)):
557		case reflect.TypeOf(int32(0)):
558		case reflect.TypeOf(int64(0)):
559		case reflect.TypeOf(uint32(0)):
560		case reflect.TypeOf(uint64(0)):
561		case reflect.TypeOf(float32(0)):
562		case reflect.TypeOf(float64(0)):
563		case reflect.TypeOf(string("")):
564		case reflect.TypeOf([]byte(nil)):
565		default:
566			panic(fmt.Sprintf("invalid element type: %v", t))
567		}
568		opt = cmpopts.SortSlices(lessFunc)
569		sliceType = reflect.SliceOf(t)
570	}
571
572	return cmp.FilterPath(func(p cmp.Path) bool {
573		// Filter to only apply to repeated fields within a message.
574		if t := p.Index(-1).Type(); t == nil || t != sliceType {
575			return false
576		}
577		if t := p.Index(-2).Type(); t == nil || t.Kind() != reflect.Interface {
578			return false
579		}
580		if t := p.Index(-3).Type(); t == nil || t != messageReflectType {
581			return false
582		}
583		return true
584	}, opt)
585}
586
587func checkTTBFunc(lessFunc interface{}) (reflect.Type, bool) {
588	switch t := reflect.TypeOf(lessFunc); {
589	case t == nil:
590		return nil, false
591	case t.NumIn() != 2 || t.In(0) != t.In(1) || t.IsVariadic():
592		return nil, false
593	case t.NumOut() != 1 || t.Out(0) != reflect.TypeOf(false):
594		return nil, false
595	default:
596		return t.In(0), true
597	}
598}
599
600// SortRepeatedFields sorts the specified repeated fields.
601// Sorting a repeated field is useful for treating the list as a multiset
602// (i.e., a set where each value can appear multiple times).
603// It panics if the field does not exist or is not a repeated field.
604//
605// The sort ordering is as follows:
606//	• Booleans are sorted where false is sorted before true.
607//	• Integers are sorted in ascending order.
608//	• Floating-point numbers are sorted in ascending order according to
609//	  the total ordering defined by IEEE-754 (section 5.10).
610//	• Strings and bytes are sorted lexicographically in ascending order.
611//	• Enums are sorted in ascending order based on its numeric value.
612//	• Messages are sorted according to some arbitrary ordering
613//	  which is undefined and may change in future implementations.
614//
615// The ordering chosen for repeated messages is unlikely to be aesthetically
616// preferred by humans. Consider using a custom sort function:
617//
618//	FilterField(m, "foo_field", SortRepeated(func(x, y *foopb.MyMessage) bool {
619//	    ... // user-provided definition for less
620//	}))
621//
622// This must be used in conjunction with Transform.
623func SortRepeatedFields(message proto.Message, names ...protoreflect.Name) cmp.Option {
624	var opts cmp.Options
625	md := message.ProtoReflect().Descriptor()
626	for _, name := range names {
627		fd := mustFindFieldDescriptor(md, name)
628		if !fd.IsList() {
629			panic(fmt.Sprintf("message field %q is not repeated", fd.FullName()))
630		}
631
632		var lessFunc interface{}
633		switch fd.Kind() {
634		case protoreflect.BoolKind:
635			lessFunc = func(x, y bool) bool { return !x && y }
636		case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
637			lessFunc = func(x, y int32) bool { return x < y }
638		case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
639			lessFunc = func(x, y int64) bool { return x < y }
640		case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
641			lessFunc = func(x, y uint32) bool { return x < y }
642		case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
643			lessFunc = func(x, y uint64) bool { return x < y }
644		case protoreflect.FloatKind:
645			lessFunc = lessF32
646		case protoreflect.DoubleKind:
647			lessFunc = lessF64
648		case protoreflect.StringKind:
649			lessFunc = func(x, y string) bool { return x < y }
650		case protoreflect.BytesKind:
651			lessFunc = func(x, y []byte) bool { return bytes.Compare(x, y) < 0 }
652		case protoreflect.EnumKind:
653			lessFunc = func(x, y Enum) bool { return x.Number() < y.Number() }
654		case protoreflect.MessageKind, protoreflect.GroupKind:
655			lessFunc = func(x, y Message) bool { return x.String() < y.String() }
656		default:
657			panic(fmt.Sprintf("invalid kind: %v", fd.Kind()))
658		}
659		opts = append(opts, FilterDescriptor(fd, cmpopts.SortSlices(lessFunc)))
660	}
661	return opts
662}
663
664func lessF32(x, y float32) bool {
665	// Bit-wise implementation of IEEE-754, section 5.10.
666	xi := int32(math.Float32bits(x))
667	yi := int32(math.Float32bits(y))
668	xi ^= int32(uint32(xi>>31) >> 1)
669	yi ^= int32(uint32(yi>>31) >> 1)
670	return xi < yi
671}
672func lessF64(x, y float64) bool {
673	// Bit-wise implementation of IEEE-754, section 5.10.
674	xi := int64(math.Float64bits(x))
675	yi := int64(math.Float64bits(y))
676	xi ^= int64(uint64(xi>>63) >> 1)
677	yi ^= int64(uint64(yi>>63) >> 1)
678	return xi < yi
679}
680