util.go 22 KB

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