Google_Protobuf_Any.swift 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // ProtobufRuntime/Sources/Protobuf/Google_Protobuf_Any.swift - Well-known Any type
  2. //
  3. // This source file is part of the Swift.org open source project
  4. //
  5. // Copyright (c) 2014 - 2016 Apple Inc. and the Swift project authors
  6. // Licensed under Apache License v2.0 with Runtime Library Exception
  7. //
  8. // See http://swift.org/LICENSE.txt for license information
  9. // See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
  10. //
  11. // -----------------------------------------------------------------------------
  12. ///
  13. /// This is pretty much completely hand-built.
  14. ///
  15. /// Generating it from any.proto -- even just partially -- is
  16. /// probably not feasible.
  17. ///
  18. // -----------------------------------------------------------------------------
  19. import Swift
  20. fileprivate func typeName(fromURL s: String) -> String {
  21. var typeStart = s.startIndex
  22. var i = typeStart
  23. while i < s.endIndex {
  24. let c = s[i]
  25. i = s.index(after: i)
  26. if c == "/" {
  27. typeStart = i
  28. }
  29. }
  30. return s[typeStart..<s.endIndex]
  31. }
  32. fileprivate func typeName(fromMessage message: ProtobufMessage) -> String {
  33. if message.protoPackageName == "" {
  34. return message.protoMessageName
  35. } else {
  36. return "\(message.protoPackageName).\(message.protoMessageName)"
  37. }
  38. }
  39. /// `Any` contains an arbitrary serialized message along with a URL
  40. /// that describes the type of the serialized message.
  41. ///
  42. /// JSON
  43. /// ====
  44. /// The JSON representation of an `Any` value uses the regular
  45. /// representation of the deserialized, embedded message, with an
  46. /// additional field `@type` which contains the type URL. Example:
  47. ///
  48. /// package google.profile;
  49. /// message Person {
  50. /// string first_name = 1;
  51. /// string last_name = 2;
  52. /// }
  53. ///
  54. /// {
  55. /// "@type": "type.googleapis.com/google.profile.Person",
  56. /// "firstName": <string>,
  57. /// "lastName": <string>
  58. /// }
  59. ///
  60. /// If the embedded message type is well-known and has a custom JSON
  61. /// representation, that representation will be embedded adding a field
  62. /// `value` which holds the custom JSON in addition to the the `@type`
  63. /// field. Example (for message [google.protobuf.Duration][google.protobuf.Duration]):
  64. ///
  65. /// {
  66. /// "@type": "type.googleapis.com/google.protobuf.Duration",
  67. /// "value": "1.212s"
  68. /// }
  69. ///
  70. /// Swift implementation details
  71. /// ============================
  72. ///
  73. /// Internally, the Google_Protobuf_Any holds either a
  74. /// message struct, a protobuf-serialized bytes value, or a collection
  75. /// of JSON fields.
  76. ///
  77. /// If you create a Google_Protobuf_Any(message:) then the object will
  78. /// keep a copy of the provided message. When the Any itself is later
  79. /// serialized, the message will be inspected to correctly serialize
  80. /// the Any to protobuf or JSON as appropriate.
  81. ///
  82. /// If you deserialize a Google_Protobuf_Any() from protobuf, then it will
  83. /// contain a protobuf-serialized form of the contained object. This will
  84. /// in turn be deserialized only when you use the unpackTo() method.
  85. ///
  86. /// If you deserialize a Google_Protobuf_Any() from JSON, then it will
  87. /// contain a set of partially-decoded JSON fields. These will
  88. /// be fully deserialized when you use the unpackTo() method.
  89. ///
  90. /// Note that deserializing from protobuf and reserializing back to
  91. /// protobuf (or JSON-to-JSON) is efficient and well-supported.
  92. /// However, deserializing from protobuf and reserializing to JSON
  93. /// (or vice versa) is much more complicated:
  94. /// * Well-known types are automatically detected and handled as
  95. /// if the Any field were deserialized to the in-memory form
  96. /// and then serialized back out again.
  97. /// * You can register your message types via Google_Protobuf_Any.register().
  98. /// Such types will be automatically handled as above.
  99. /// * Someday, there will be a mechanism for you to provide
  100. /// Type descriptors (which might be fetched from a remote server
  101. /// on-demand).
  102. ///
  103. /// In particular, note that it is not possible to decode a google.protobuf.Any
  104. /// field in a protobuf message and then recode to JSON (or vice versa)
  105. /// without having the type information available. This is a basic
  106. /// limitation of Google's spec for google.protobuf.Any.
  107. ///
  108. public struct Google_Protobuf_Any: ProtobufAbstractMessage, Hashable, Equatable, CustomReflectable {
  109. public var swiftClassName: String {return "Google_Protobuf_Any"}
  110. public var protoPackageName: String {return "google.protobuf"}
  111. public var protoMessageName: String {return "Any"}
  112. public var jsonFieldNames: [String:Int] {return ["@type":1,"value":2]}
  113. public var protoFieldNames: [String:Int] {return ["type_url":1,"value":2]}
  114. /// A URL/resource name whose content describes the type of the
  115. /// serialized message.
  116. ///
  117. /// For URLs which use the schema `http`, `https`, or no schema, the
  118. /// following restrictions and interpretations apply:
  119. ///
  120. /// * If no schema is provided, `https` is assumed.
  121. /// * The last segment of the URL's path must represent the fully
  122. /// qualified name of the type (as in `path/google.protobuf.Duration`).
  123. /// * An HTTP GET on the URL must yield a [google.protobuf.Type][google.protobuf.Type]
  124. /// value in binary format, or produce an error.
  125. /// * Applications are allowed to cache lookup results based on the
  126. /// URL, or have them precompiled into a binary to avoid any
  127. /// lookup. Therefore, binary compatibility needs to be preserved
  128. /// on changes to types. (Use versioned type names to manage
  129. /// breaking changes.)
  130. ///
  131. /// Schemas other than `http`, `https` (or the empty schema) might be
  132. /// used with implementation specific semantics.
  133. public var typeURL: String?
  134. /// Must be valid serialized data of the above specified type.
  135. public var value: [UInt8]? {
  136. get {
  137. if let value = _value {
  138. return value
  139. } else if let message = _message {
  140. do {
  141. return try message.serializeProtobuf()
  142. } catch {
  143. return nil
  144. }
  145. } else if let _ = _jsonFields, let typeURL = typeURL {
  146. // Transcode JSON-to-protobuf by decoding/recoding:
  147. // Well-known types are always available:
  148. let encodedTypeName = typeName(fromURL: typeURL)
  149. if let messageType = Google_Protobuf_Any.wellKnownTypes[encodedTypeName] {
  150. do {
  151. let m = try messageType.init(any: self)
  152. return try m.serializeProtobuf()
  153. } catch {
  154. return nil
  155. }
  156. }
  157. // See if the user has registered the type:
  158. if let messageType = Google_Protobuf_Any.knownTypes[encodedTypeName] {
  159. do {
  160. let m = try messageType.init(any: self)
  161. return try m.serializeProtobuf()
  162. } catch {
  163. return nil
  164. }
  165. }
  166. // TODO: Google spec requires a lot more work in the general case:
  167. // let encodedType = ... fetch google.protobuf.Type based on typeURL ...
  168. // let type = Google_Protobuf_Type(protobuf: encodedType)
  169. // return ProtobufDynamic(type: type, any: self)?.serializeProtobuf()
  170. // See the comments in serializeJSON() above for more discussion of what would be needed to fully implement this.
  171. return nil
  172. } else {
  173. return nil
  174. }
  175. }
  176. set {
  177. _value = newValue
  178. _message = nil
  179. _jsonFields = nil
  180. }
  181. }
  182. private var _value: [UInt8]?
  183. private var _message: ProtobufMessage?
  184. private var _jsonFields: [String:[ProtobufJSONToken]]?
  185. static private var wellKnownTypes: [String:ProtobufMessage.Type] = [
  186. "google.protobuf.Any": Google_Protobuf_Any.self,
  187. "google.protobuf.BoolValue": Google_Protobuf_BoolValue.self,
  188. "google.protobuf.BytesValue": Google_Protobuf_BytesValue.self,
  189. "google.protobuf.DoubleValue": Google_Protobuf_DoubleValue.self,
  190. "google.protobuf.Duration": Google_Protobuf_Duration.self,
  191. "google.protobuf.FieldMask": Google_Protobuf_FieldMask.self,
  192. "google.protobuf.FloatValue": Google_Protobuf_FloatValue.self,
  193. "google.protobuf.Int32Value": Google_Protobuf_Int32Value.self,
  194. "google.protobuf.Int64Value": Google_Protobuf_Int64Value.self,
  195. "google.protobuf.ListValue": Google_Protobuf_ListValue.self,
  196. "google.protobuf.StringValue": Google_Protobuf_StringValue.self,
  197. "google.protobuf.Struct": Google_Protobuf_Struct.self,
  198. "google.protobuf.Timestamp": Google_Protobuf_Timestamp.self,
  199. "google.protobuf.UInt32Value": Google_Protobuf_UInt32Value.self,
  200. "google.protobuf.UInt64Value": Google_Protobuf_UInt64Value.self,
  201. "google.protobuf.Value": Google_Protobuf_Value.self,
  202. ]
  203. static private var knownTypes = [String:ProtobufMessage.Type]()
  204. static public func register(messageType: ProtobufMessage.Type) {
  205. let m = messageType.init()
  206. let messageTypeName = typeName(fromMessage: m)
  207. knownTypes[messageTypeName] = messageType
  208. }
  209. public init() {}
  210. public init(message: ProtobufMessage) {
  211. _message = message
  212. typeURL = message.anyTypeURL
  213. }
  214. mutating public func decodeField(setter: inout ProtobufFieldDecoder, protoFieldNumber: Int) throws -> Bool {
  215. switch protoFieldNumber {
  216. case 1: return try setter.decodeOptionalField(fieldType: ProtobufString.self, value: &typeURL)
  217. case 2: return try setter.decodeOptionalField(fieldType: ProtobufBytes.self, value: &_value)
  218. default: return false
  219. }
  220. }
  221. public mutating func decodeFromJSONObject(jsonDecoder: inout ProtobufJSONDecoder) throws {
  222. var key = ""
  223. var state = ProtobufJSONDecoder.ObjectParseState.expectFirstKey
  224. _jsonFields = nil
  225. var jsonFields = [String:[ProtobufJSONToken]]()
  226. while let token = try jsonDecoder.nextToken() {
  227. switch token {
  228. case .string(let s): // This is a key
  229. if state != .expectKey && state != .expectFirstKey {
  230. throw ProtobufDecodingError.malformedJSON
  231. }
  232. key = s
  233. state = .expectColon
  234. case .colon:
  235. if state != .expectColon {
  236. throw ProtobufDecodingError.malformedJSON
  237. }
  238. if key == "@type" {
  239. try jsonDecoder.decodeValue(key: key, message: &self)
  240. } else {
  241. jsonFields[key] = try jsonDecoder.skip()
  242. }
  243. state = .expectComma
  244. case .comma:
  245. if state != .expectComma {
  246. throw ProtobufDecodingError.malformedJSON
  247. }
  248. state = .expectKey
  249. case .endObject:
  250. if state != .expectFirstKey && state != .expectComma {
  251. throw ProtobufDecodingError.malformedJSON
  252. }
  253. _jsonFields = jsonFields
  254. return
  255. default:
  256. throw ProtobufDecodingError.malformedJSON
  257. }
  258. }
  259. throw ProtobufDecodingError.malformedJSON
  260. }
  261. /// Update the provided object from the data in the Any container.
  262. /// This is essentially just a deferred deserialization; the Any
  263. /// may hold protobuf bytes or JSON fields depending on how the Any
  264. /// was itself deserialized.
  265. ///
  266. public func unpackTo<M: ProtobufMessage>(target: inout M) throws {
  267. if typeURL == nil {
  268. throw ProtobufDecodingError.malformedAnyField
  269. }
  270. let encodedType = typeName(fromURL: typeURL!)
  271. if encodedType == "" {
  272. throw ProtobufDecodingError.malformedAnyField
  273. }
  274. let messageType = typeName(fromMessage: target)
  275. if encodedType != messageType {
  276. throw ProtobufDecodingError.malformedAnyField
  277. }
  278. var protobuf: [UInt8]?
  279. if let message = _message {
  280. protobuf = try message.serializeProtobuf()
  281. } else if let value = _value {
  282. protobuf = value
  283. }
  284. if let protobuf = protobuf {
  285. // Decode protobuf from the stored bytes
  286. try protobuf.withUnsafeBufferPointer { (bp) in
  287. var protobufDecoder = ProtobufBinaryDecoder(protobufPointer: bp)
  288. try protobufDecoder.decodeFullObject(message: &target)
  289. }
  290. return
  291. } else if let jsonFields = _jsonFields {
  292. let targetType = typeName(fromMessage: target)
  293. if Google_Protobuf_Any.wellKnownTypes[targetType] != nil {
  294. // If it's a well-known type, the JSON coding must have a single 'value' field
  295. if jsonFields.count != 1 || jsonFields["value"] == nil {
  296. throw ProtobufDecodingError.schemaMismatch
  297. }
  298. var v = jsonFields["value"]!
  299. guard v.count > 0 else {
  300. throw ProtobufDecodingError.schemaMismatch
  301. }
  302. switch v[0] {
  303. case .beginObject:
  304. var decoder = ProtobufJSONDecoder(tokens: v)
  305. let _ = try decoder.nextToken() // Discard {
  306. try target.decodeFromJSONObject(jsonDecoder: &decoder)
  307. if !decoder.complete {
  308. throw ProtobufDecodingError.trailingGarbage
  309. }
  310. case .beginArray:
  311. var decoder = ProtobufJSONDecoder(tokens: v)
  312. let _ = try decoder.nextToken() // Discard [
  313. try target.decodeFromJSONArray(jsonDecoder: &decoder)
  314. case .number(_), .string(_), .boolean(_):
  315. try target.decodeFromJSONToken(token: v[0])
  316. case .null:
  317. if let n = try M.decodeFromJSONNull() {
  318. target = n
  319. } else {
  320. throw ProtobufDecodingError.malformedJSON
  321. }
  322. default:
  323. throw ProtobufDecodingError.malformedJSON
  324. }
  325. } else {
  326. // Decode JSON from the stored tokens for generated messages
  327. for (k,v) in jsonFields {
  328. var decoder = ProtobufJSONDecoder(tokens: v)
  329. try decoder.decodeValue(key: k, message: &target)
  330. if !decoder.complete {
  331. throw ProtobufDecodingError.trailingGarbage
  332. }
  333. }
  334. }
  335. return
  336. }
  337. throw ProtobufDecodingError.malformedAnyField
  338. }
  339. public var isEmpty: Bool {
  340. return (typeURL == nil
  341. && _value == nil
  342. && _message == nil
  343. && (_jsonFields == nil || _jsonFields!.count == 0))
  344. }
  345. public var hashValue: Int {
  346. get {
  347. var hash: Int = 0
  348. if let t = typeURL {
  349. hash = (hash &* 16777619) ^ t.hashValue
  350. }
  351. if let v = _value {
  352. hash = (hash &* 16777619) ^ ProtobufHash(bytes: v)
  353. }
  354. if let m = _message {
  355. hash = (hash &* 16777619) ^ m.hashValue
  356. }
  357. return hash
  358. }
  359. }
  360. public var debugDescription: String {
  361. get {
  362. if let message = _message {
  363. return "Google_Protobuf_Any{" + String(reflecting: message) + "}"
  364. } else if let typeURL = typeURL {
  365. if let value = _value {
  366. return "Google_Protobuf_Any{\(typeURL), \(value)}"
  367. } else {
  368. return "Google_Protobuf_Any{\(typeURL), <JSON>}"
  369. }
  370. } else {
  371. return "Google_Protobuf_Any{}"
  372. }
  373. }
  374. }
  375. public init(any: Google_Protobuf_Any) throws {
  376. try any.unpackTo(target: &self)
  377. }
  378. // Override the traversal-based JSON encoding
  379. // This builds an Any JSON representation from one of:
  380. // * The message we were initialized with,
  381. // * The JSON fields we last deserialized, or
  382. // * The protobuf field we were deserialized from.
  383. // The last case requires locating the type, deserializing
  384. // into an object, then reserializing back to JSON.
  385. public func serializeJSON() throws -> String {
  386. if let message = _message {
  387. return try message.serializeAnyJSON()
  388. } else if let typeURL = typeURL {
  389. if _value != nil {
  390. // Transcode protobuf-to-JSON by decoding and recoding.
  391. // Well-known types are always available:
  392. let messageTypeName = typeName(fromURL: typeURL)
  393. if let messageType = Google_Protobuf_Any.wellKnownTypes[messageTypeName] {
  394. let m = try messageType.init(any: self)
  395. return try m.serializeAnyJSON()
  396. }
  397. // The user may have registered this type:
  398. if let messageType = Google_Protobuf_Any.knownTypes[messageTypeName] {
  399. let m = try messageType.init(any: self)
  400. return try m.serializeAnyJSON()
  401. }
  402. // TODO: Google spec requires more work in the general case:
  403. // let encodedType = ... fetch google.protobuf.Type based on typeURL ...
  404. // let type = Google_Protobuf_Type(protobuf: encodedType)
  405. // return ProtobufDynamicMessage(type: type, any: self)?.serializeAnyJSON()
  406. // The big problem here is fetching the type: Types not in the executable must be fetched from somewhere; Google says we should do an HTTPS fetch against the typeURL, which assumes that everyone will publish all their types and that everyone running this code will have reliable network access. That seems ... optimistic.
  407. // ProtobufDynamicMessage() is non-trivial to write but desirable for other reasons. It's a class that can be instantiated with any protobuf type or descriptor and provides access to protos of the corresponding type. (Not to be confused with ProtobufRaw which can decode any message but does not use a type descriptor and therefore cannot provide fully-typed access to fields.)
  408. throw ProtobufEncodingError.anyTranscodeFailure
  409. } else {
  410. var jsonEncoder = ProtobufJSONEncoder()
  411. jsonEncoder.startObject()
  412. jsonEncoder.startField(name: "@type")
  413. jsonEncoder.putStringValue(value: typeURL)
  414. if let jsonFields = _jsonFields {
  415. // JSON-to-JSON case, just recode the stored tokens
  416. for (k,v) in jsonFields {
  417. jsonEncoder.startField(name: k)
  418. jsonEncoder.appendTokens(tokens: v)
  419. }
  420. }
  421. jsonEncoder.endObject()
  422. return jsonEncoder.result
  423. }
  424. } else {
  425. return "{}"
  426. }
  427. }
  428. public func serializeAnyJSON() throws -> String {
  429. let value = try serializeJSON()
  430. return "{\"@type\":\"\(anyTypeURL)\",\"value\":\(value)}"
  431. }
  432. public func isEqualTo(other: Google_Protobuf_Any) -> Bool {
  433. // TODO: Fix this for case where Any holds a message or jsonFields or the two Any hold different stuff... <ugh> This seems unsolvable in the general case. <ugh>
  434. if ((typeURL != nil && typeURL != "") || (other.typeURL != nil && other.typeURL != "")) && (typeURL == nil || other.typeURL == nil || typeURL! != other.typeURL!) {
  435. return false
  436. }
  437. if ((_value != nil && !_value!.isEmpty) || (other._value != nil && !other._value!.isEmpty)) && (_value == nil || other._value == nil || _value! != other._value!) {
  438. return false
  439. }
  440. return true
  441. }
  442. public func traverse(visitor: inout ProtobufVisitor) throws {
  443. if let typeURL = typeURL {
  444. try visitor.visitSingularField(fieldType: ProtobufString.self, value: typeURL, protoFieldNumber: 1, protoFieldName: "type_url", jsonFieldName: "@type", swiftFieldName: "typeURL")
  445. if let value = value {
  446. try visitor.visitSingularField(fieldType: ProtobufBytes.self, value: value, protoFieldNumber: 2, protoFieldName: "value", jsonFieldName: "value", swiftFieldName: "value")
  447. } else {
  448. throw ProtobufEncodingError.anyTranscodeFailure
  449. }
  450. }
  451. }
  452. }