ExtensionFieldValueSet.swift 3.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. // Sources/SwiftProtobuf/ExtensionFieldValueSet.swift - Extension support
  2. //
  3. // Copyright (c) 2014 - 2016 Apple Inc. and the project authors
  4. // Licensed under Apache License v2.0 with Runtime Library Exception
  5. //
  6. // See LICENSE.txt for license information:
  7. // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
  8. //
  9. // -----------------------------------------------------------------------------
  10. ///
  11. /// A collection of extension field values on a particular object.
  12. /// This is only used within messages to manage the values of extension fields;
  13. /// it does not need to be very sophisticated.
  14. ///
  15. // -----------------------------------------------------------------------------
  16. public struct ExtensionFieldValueSet: Hashable, Sendable {
  17. fileprivate var values = [Int: any AnyExtensionField]()
  18. public static func == (
  19. lhs: ExtensionFieldValueSet,
  20. rhs: ExtensionFieldValueSet
  21. ) -> Bool {
  22. guard lhs.values.count == rhs.values.count else {
  23. return false
  24. }
  25. for (index, l) in lhs.values {
  26. if let r = rhs.values[index] {
  27. if type(of: l) != type(of: r) {
  28. return false
  29. }
  30. if !l.isEqual(other: r) {
  31. return false
  32. }
  33. } else {
  34. return false
  35. }
  36. }
  37. return true
  38. }
  39. public init() {}
  40. public func hash(into hasher: inout Hasher) {
  41. // AnyExtensionField is not Hashable, and the Self constraint that would
  42. // add breaks some of the uses of it; so the only choice is to manually
  43. // mix things in. However, one must remember to do things in an order
  44. // independent manner.
  45. var hash = 16_777_619
  46. for (fieldNumber, v) in values {
  47. var localHasher = hasher
  48. localHasher.combine(fieldNumber)
  49. v.hash(into: &localHasher)
  50. hash = hash &+ localHasher.finalize()
  51. }
  52. hasher.combine(hash)
  53. }
  54. public func traverse<V: Visitor>(visitor: inout V, start: Int, end: Int) throws {
  55. let validIndexes = values.keys.filter { $0 >= start && $0 < end }
  56. for i in validIndexes.sorted() {
  57. let value = values[i]!
  58. try value.traverse(visitor: &visitor)
  59. }
  60. }
  61. public subscript(index: Int) -> (any AnyExtensionField)? {
  62. get { values[index] }
  63. set { values[index] = newValue }
  64. }
  65. mutating func modify<ReturnType>(
  66. index: Int,
  67. _ modifier: (inout (any AnyExtensionField)?) throws -> ReturnType
  68. ) rethrows -> ReturnType {
  69. // This internal helper exists to invoke the _modify accessor on Dictionary for the given operation, which can avoid CoWs
  70. // during the modification operation.
  71. try modifier(&values[index])
  72. }
  73. public var isInitialized: Bool {
  74. for (_, v) in values {
  75. if !v.isInitialized {
  76. return false
  77. }
  78. }
  79. return true
  80. }
  81. }