Message.swift 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. // Sources/SwiftProtobuf/Message.swift - Message 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. /// The protocol which all generated protobuf messages implement.
  10. /// `Message` is the protocol type you should use whenever
  11. /// you need an argument or variable which holds "some message".
  12. ///
  13. /// Generated messages also implement `Hashable`, and thus `Equatable`.
  14. /// However, the protocol conformance is declared on a different protocol.
  15. /// This allows you to use `Message` as a type directly:
  16. ///
  17. /// func consume(message: Message) { ... }
  18. ///
  19. /// Instead of needing to use it as a type constraint on a generic declaration:
  20. ///
  21. /// func consume<M: Message>(message: M) { ... }
  22. ///
  23. /// If you need to convince the compiler that your message is `Hashable` so
  24. /// you can insert it into a `Set` or use it as a `Dictionary` key, use
  25. /// a generic declaration with a type constraint:
  26. ///
  27. /// func insertIntoSet<M: Message & Hashable>(message: M) {
  28. /// mySet.insert(message)
  29. /// }
  30. ///
  31. /// The actual functionality is implemented either in the generated code or in
  32. /// default implementations of the below methods and properties.
  33. @preconcurrency
  34. public protocol Message: Sendable, CustomDebugStringConvertible {
  35. /// Creates a new message with all of its fields initialized to their default
  36. /// values.
  37. init()
  38. // Metadata
  39. // Basic facts about this class and the proto message it was generated from
  40. // Used by various encoders and decoders
  41. /// The fully-scoped name of the message from the original .proto file,
  42. /// including any relevant package name.
  43. static var protoMessageName: String { get }
  44. /// True if all required fields (if any) on this message and any nested
  45. /// messages (recursively) have values set; otherwise, false.
  46. var isInitialized: Bool { get }
  47. /// Some formats include enough information to transport fields that were
  48. /// not known at generation time. When encountered, they are stored here.
  49. var unknownFields: UnknownStorage { get set }
  50. //
  51. // General serialization/deserialization machinery
  52. //
  53. /// Decode all of the fields from the given decoder.
  54. ///
  55. /// This is a simple loop that repeatedly gets the next field number
  56. /// from `decoder.nextFieldNumber()` and then uses the number returned
  57. /// and the type information from the original .proto file to decide
  58. /// what type of data should be decoded for that field. The corresponding
  59. /// method on the decoder is then called to get the field value.
  60. ///
  61. /// This is the core method used by the deserialization machinery. It is
  62. /// `public` to enable users to implement their own encoding formats by
  63. /// conforming to `Decoder`; it should not be called otherwise.
  64. ///
  65. /// Note that this is not specific to binary encodng; formats that use
  66. /// textual identifiers translate those to field numbers and also go
  67. /// through this to decode messages.
  68. ///
  69. /// - Parameters:
  70. /// - decoder: a `Decoder`; the `Message` will call the method
  71. /// corresponding to the type of this field.
  72. /// - Throws: an error on failure or type mismatch. The type of error
  73. /// thrown depends on which decoder is used.
  74. mutating func decodeMessage<D: Decoder>(decoder: inout D) throws
  75. /// Traverses the fields of the message, calling the appropriate methods
  76. /// of the passed `Visitor` object.
  77. ///
  78. /// This is used internally by:
  79. ///
  80. /// * Protobuf binary serialization
  81. /// * JSON serialization (with some twists to account for specialty JSON)
  82. /// * Protobuf Text serialization
  83. /// * `Hashable` computation
  84. ///
  85. /// Conceptually, serializers create visitor objects that are
  86. /// then passed recursively to every message and field via generated
  87. /// `traverse` methods. The details get a little involved due to
  88. /// the need to allow particular messages to override particular
  89. /// behaviors for specific encodings, but the general idea is quite simple.
  90. func traverse<V: Visitor>(visitor: inout V) throws
  91. // Standard utility properties and methods.
  92. // Most of these are simple wrappers on top of the visitor machinery.
  93. // They are implemented in the protocol, not in the generated structs,
  94. // so can be overridden in user code by defining custom extensions to
  95. // the generated struct.
  96. /// An implementation of hash(into:) to provide conformance with the
  97. /// `Hashable` protocol.
  98. func hash(into hasher: inout Hasher)
  99. /// Helper to compare `Message`s when not having a specific type to use
  100. /// normal `Equatable`. `Equatable` is provided with specific generated
  101. /// types.
  102. func isEqualTo(message: any Message) -> Bool
  103. }
  104. extension Message {
  105. /// Generated proto2 messages that contain required fields, nested messages
  106. /// that contain required fields, and/or extensions will provide their own
  107. /// implementation of this property that tests that all required fields are
  108. /// set. Users of the generated code SHOULD NOT override this property.
  109. public var isInitialized: Bool {
  110. // The generated code will include a specialization as needed.
  111. true
  112. }
  113. /// A hash based on the message's full contents.
  114. public func hash(into hasher: inout Hasher) {
  115. var visitor = HashVisitor(hasher)
  116. try? traverse(visitor: &visitor)
  117. hasher = visitor.hasher
  118. }
  119. /// A description generated by recursively visiting all fields in the message,
  120. /// including messages.
  121. public var debugDescription: String {
  122. #if DEBUG
  123. // TODO Ideally there would be something like serializeText() that can
  124. // take a prefix so we could do something like:
  125. // [class name](
  126. // [text format]
  127. // )
  128. let className = String(reflecting: type(of: self))
  129. let header = "\(className):\n"
  130. return header + textFormatString()
  131. #else
  132. return String(reflecting: type(of: self))
  133. #endif
  134. }
  135. /// Creates an instance of the message type on which this method is called,
  136. /// executes the given block passing the message in as its sole `inout`
  137. /// argument, and then returns the message.
  138. ///
  139. /// This method acts essentially as a "builder" in that the initialization of
  140. /// the message is captured within the block, allowing the returned value to
  141. /// be set in an immutable variable. For example,
  142. ///
  143. /// let msg = MyMessage.with { $0.myField = "foo" }
  144. /// msg.myOtherField = 5 // error: msg is immutable
  145. ///
  146. /// - Parameter populator: A block or function that populates the new message,
  147. /// which is passed into the block as an `inout` argument.
  148. /// - Returns: The message after execution of the block.
  149. public static func with(
  150. _ populator: (inout Self) throws -> Void
  151. ) rethrows -> Self {
  152. var message = Self()
  153. try populator(&message)
  154. return message
  155. }
  156. }
  157. /// Implementation base for all messages; not intended for client use.
  158. ///
  159. /// In general, use `SwiftProtobuf.Message` instead when you need a variable or
  160. /// argument that can hold any type of message. Occasionally, you can use
  161. /// `SwiftProtobuf.Message & Equatable` or `SwiftProtobuf.Message & Hashable` as
  162. /// generic constraints if you need to write generic code that can be applied to
  163. /// multiple message types that uses equality tests, puts messages in a `Set`,
  164. /// or uses them as `Dictionary` keys.
  165. @preconcurrency
  166. public protocol _MessageImplementationBase: Message, Hashable {
  167. // Legacy function; no longer used, but left to maintain source compatibility.
  168. func _protobuf_generated_isEqualTo(other: Self) -> Bool
  169. }
  170. extension _MessageImplementationBase {
  171. public func isEqualTo(message: any Message) -> Bool {
  172. guard let other = message as? Self else {
  173. return false
  174. }
  175. return self == other
  176. }
  177. // Legacy default implementation that is used by old generated code, current
  178. // versions of the plugin/generator provide this directly, but this is here
  179. // just to avoid breaking source compatibility.
  180. public static func == (lhs: Self, rhs: Self) -> Bool {
  181. lhs._protobuf_generated_isEqualTo(other: rhs)
  182. }
  183. // Legacy function that is generated by old versions of the plugin/generator,
  184. // defaulted to keep things simple without changing the api surface.
  185. public func _protobuf_generated_isEqualTo(other: Self) -> Bool {
  186. self == other
  187. }
  188. }