discard.go 2.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475
  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. "github.com/golang/protobuf/internal/wire"
  7. pref "google.golang.org/protobuf/reflect/protoreflect"
  8. "google.golang.org/protobuf/runtime/protoimpl"
  9. )
  10. // DiscardUnknown recursively discards all unknown fields from this message
  11. // and all embedded messages.
  12. //
  13. // When unmarshaling a message with unrecognized fields, the tags and values
  14. // of such fields are preserved in the Message. This allows a later call to
  15. // marshal to be able to produce a message that continues to have those
  16. // unrecognized fields. To avoid this, DiscardUnknown is used to
  17. // explicitly clear the unknown fields after unmarshaling.
  18. //
  19. // For proto2 messages, the unknown fields of message extensions are only
  20. // discarded from messages that have been accessed via GetExtension.
  21. func DiscardUnknown(m Message) {
  22. if m == nil {
  23. return
  24. }
  25. discardUnknown(protoimpl.X.MessageOf(m))
  26. }
  27. func discardUnknown(m pref.Message) {
  28. m.Range(func(fd pref.FieldDescriptor, val pref.Value) bool {
  29. switch {
  30. // Handle singular message.
  31. case fd.Cardinality() != pref.Repeated:
  32. if fd.Message() != nil {
  33. discardUnknown(m.Get(fd).Message())
  34. }
  35. // Handle list of messages.
  36. case fd.IsList():
  37. if fd.Message() != nil {
  38. ls := m.Get(fd).List()
  39. for i := 0; i < ls.Len(); i++ {
  40. discardUnknown(ls.Get(i).Message())
  41. }
  42. }
  43. // Handle map of messages.
  44. case fd.IsMap():
  45. if fd.MapValue().Message() != nil {
  46. ms := m.Get(fd).Map()
  47. ms.Range(func(_ pref.MapKey, v pref.Value) bool {
  48. discardUnknown(v.Message())
  49. return true
  50. })
  51. }
  52. }
  53. return true
  54. })
  55. // Discard unknown fields.
  56. var bo pref.RawFields
  57. extRanges := m.Descriptor().ExtensionRanges()
  58. for bi := m.GetUnknown(); len(bi) > 0; {
  59. // NOTE: Historically, this function did not discard unknown fields
  60. // that were within the extension field ranges.
  61. num, _, n := wire.ConsumeField(bi)
  62. if extRanges.Has(num) {
  63. bo = append(bo, bi[:n]...)
  64. }
  65. bi = bi[n:]
  66. }
  67. if bi := m.GetUnknown(); len(bi) != len(bo) {
  68. m.SetUnknown(bo)
  69. }
  70. }