discard.go 1.6 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758
  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 proto
  5. import (
  6. "google.golang.org/protobuf/reflect/protoreflect"
  7. )
  8. // DiscardUnknown recursively discards all unknown fields from this message
  9. // and all embedded messages.
  10. //
  11. // When unmarshaling a message with unrecognized fields, the tags and values
  12. // of such fields are preserved in the Message. This allows a later call to
  13. // marshal to be able to produce a message that continues to have those
  14. // unrecognized fields. To avoid this, DiscardUnknown is used to
  15. // explicitly clear the unknown fields after unmarshaling.
  16. func DiscardUnknown(m Message) {
  17. if m != nil {
  18. discardUnknown(MessageReflect(m))
  19. }
  20. }
  21. func discardUnknown(m protoreflect.Message) {
  22. m.Range(func(fd protoreflect.FieldDescriptor, val protoreflect.Value) bool {
  23. switch {
  24. // Handle singular message.
  25. case fd.Cardinality() != protoreflect.Repeated:
  26. if fd.Message() != nil {
  27. discardUnknown(m.Get(fd).Message())
  28. }
  29. // Handle list of messages.
  30. case fd.IsList():
  31. if fd.Message() != nil {
  32. ls := m.Get(fd).List()
  33. for i := 0; i < ls.Len(); i++ {
  34. discardUnknown(ls.Get(i).Message())
  35. }
  36. }
  37. // Handle map of messages.
  38. case fd.IsMap():
  39. if fd.MapValue().Message() != nil {
  40. ms := m.Get(fd).Map()
  41. ms.Range(func(_ protoreflect.MapKey, v protoreflect.Value) bool {
  42. discardUnknown(v.Message())
  43. return true
  44. })
  45. }
  46. }
  47. return true
  48. })
  49. // Discard unknown fields.
  50. if len(m.GetUnknown()) > 0 {
  51. m.SetUnknown(nil)
  52. }
  53. }