Message.swift 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248
  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. // TODO: I am *temporarily* making this a protocol requirement so that I can replace its
  104. // implementation in generated table-driven messages. That will let me support decoding in all
  105. // of its forms (init a new message, merge into an existing message) by only generating this
  106. // `_merge` method instead of multiple initializers and methods. This will be removed once the
  107. // implementation is far enough along that I can regenerate the WKTs and plugin protos, since
  108. // everything will be moved into the runtime at that point.
  109. mutating func _merge(
  110. rawBuffer body: UnsafeRawBufferPointer,
  111. extensions: (any ExtensionMap)?,
  112. partial: Bool,
  113. options: BinaryDecodingOptions
  114. ) throws
  115. }
  116. extension Message {
  117. /// Generated proto2 messages that contain required fields, nested messages
  118. /// that contain required fields, and/or extensions will provide their own
  119. /// implementation of this property that tests that all required fields are
  120. /// set. Users of the generated code SHOULD NOT override this property.
  121. public var isInitialized: Bool {
  122. // The generated code will include a specialization as needed.
  123. true
  124. }
  125. /// A hash based on the message's full contents.
  126. public func hash(into hasher: inout Hasher) {
  127. var visitor = HashVisitor(hasher)
  128. try? traverse(visitor: &visitor)
  129. hasher = visitor.hasher
  130. }
  131. /// A description generated by recursively visiting all fields in the message,
  132. /// including messages.
  133. public var debugDescription: String {
  134. #if DEBUG
  135. // TODO Ideally there would be something like serializeText() that can
  136. // take a prefix so we could do something like:
  137. // [class name](
  138. // [text format]
  139. // )
  140. let className = String(reflecting: type(of: self))
  141. let header = "\(className):\n"
  142. return header + textFormatString()
  143. #else
  144. return String(reflecting: type(of: self))
  145. #endif
  146. }
  147. /// Creates an instance of the message type on which this method is called,
  148. /// executes the given block passing the message in as its sole `inout`
  149. /// argument, and then returns the message.
  150. ///
  151. /// This method acts essentially as a "builder" in that the initialization of
  152. /// the message is captured within the block, allowing the returned value to
  153. /// be set in an immutable variable. For example,
  154. ///
  155. /// let msg = MyMessage.with { $0.myField = "foo" }
  156. /// msg.myOtherField = 5 // error: msg is immutable
  157. ///
  158. /// - Parameter populator: A block or function that populates the new message,
  159. /// which is passed into the block as an `inout` argument.
  160. /// - Returns: The message after execution of the block.
  161. public static func with(
  162. _ populator: (inout Self) throws -> Void
  163. ) rethrows -> Self {
  164. var message = Self()
  165. try populator(&message)
  166. return message
  167. }
  168. }
  169. /// Implementation base for all messages; not intended for client use.
  170. ///
  171. /// In general, use `SwiftProtobuf.Message` instead when you need a variable or
  172. /// argument that can hold any type of message. Occasionally, you can use
  173. /// `SwiftProtobuf.Message & Equatable` or `SwiftProtobuf.Message & Hashable` as
  174. /// generic constraints if you need to write generic code that can be applied to
  175. /// multiple message types that uses equality tests, puts messages in a `Set`,
  176. /// or uses them as `Dictionary` keys.
  177. @preconcurrency
  178. public protocol _MessageImplementationBase: Message, Hashable {
  179. // This is an implementation detail of the runtime; users should not call it. The return type
  180. // is a class-bound existential because the true SPI type cannot be used in a protocol
  181. // requirement.
  182. func _protobuf_messageStorage(accessToken: _MessageStorageToken) -> AnyObject
  183. // This is an implementation detail of the runtime; users should not call it.
  184. mutating func _protobuf_ensureUniqueStorage(accessToken: _MessageStorageToken)
  185. // Legacy function; no longer used, but left to maintain source compatibility.
  186. func _protobuf_generated_isEqualTo(other: Self) -> Bool
  187. }
  188. extension _MessageImplementationBase {
  189. // TODO: Remove this default implementation once we're generating all the WKTs with the new
  190. // implementation.
  191. public func _protobuf_messageStorage(accessToken: _MessageStorageToken) -> AnyObject {
  192. fatalError()
  193. }
  194. // TODO: Remove this default implementation once we're generating all the WKTs with the new
  195. // implementation.
  196. public mutating func _protobuf_ensureUniqueStorage(accessToken: _MessageStorageToken) {
  197. fatalError()
  198. }
  199. public func isEqualTo(message: any Message) -> Bool {
  200. guard let other = message as? Self else {
  201. return false
  202. }
  203. return self == other
  204. }
  205. // Legacy default implementation that is used by old generated code, current
  206. // versions of the plugin/generator provide this directly, but this is here
  207. // just to avoid breaking source compatibility.
  208. public static func == (lhs: Self, rhs: Self) -> Bool {
  209. lhs._protobuf_generated_isEqualTo(other: rhs)
  210. }
  211. // Legacy function that is generated by old versions of the plugin/generator,
  212. // defaulted to keep things simple without changing the api surface.
  213. public func _protobuf_generated_isEqualTo(other: Self) -> Bool {
  214. self == other
  215. }
  216. }
  217. extension _MessageImplementationBase {
  218. /// Convenience property for the runtime to retrieve the underlying storage for a concretely
  219. /// typed message.
  220. internal var storageForRuntime: _MessageStorage {
  221. unsafeDowncast(_protobuf_messageStorage(accessToken: _MessageStorageToken()), to: _MessageStorage.self)
  222. }
  223. }