| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- // Sources/SwiftProtobuf/Google_Protobuf_Any+Extensions.swift - Well-known Any type
- //
- // Copyright (c) 2014 - 2017 Apple Inc. and the project authors
- // Licensed under Apache License v2.0 with Runtime Library Exception
- //
- // See LICENSE.txt for license information:
- // https://github.com/apple/swift-protobuf/blob/main/LICENSE.txt
- //
- // -----------------------------------------------------------------------------
- ///
- /// Extends the `Google_Protobuf_Any` type with various custom behaviors.
- ///
- // -----------------------------------------------------------------------------
- // Explicit import of Foundation is necessary on Linux,
- // don't remove unless obsolete on all platforms
- import Foundation
- public let defaultAnyTypeURLPrefix: String = "type.googleapis.com"
- extension Google_Protobuf_Any {
- /// Initialize an Any object from the provided message.
- ///
- /// This corresponds to the `pack` operation in the C++ API.
- ///
- /// Unlike the C++ implementation, the message is not immediately
- /// serialized; it is merely stored until the Any object itself
- /// needs to be serialized. This design avoids unnecessary
- /// decoding/recoding when writing JSON format.
- ///
- /// - Parameters:
- /// - partial: If `false` (the default), this method will check
- /// ``Message/isInitialized-6abgi`` before encoding to verify that all required
- /// fields are present. If any are missing, this method throws
- /// ``BinaryEncodingError/missingRequiredFields``.
- /// - typePrefix: The prefix to be used when building the `type_url`.
- /// Defaults to "type.googleapis.com".
- /// - Throws: ``BinaryEncodingError/missingRequiredFields`` if
- /// `partial` is false and `message` wasn't fully initialized.
- public init(
- message: any Message,
- partial: Bool = false,
- typePrefix: String = defaultAnyTypeURLPrefix
- ) throws {
- if !partial && !message.isInitialized {
- throw BinaryEncodingError.missingRequiredFields
- }
- self.init()
- typeURL = buildTypeURL(forMessage: message, typePrefix: typePrefix)
- _storage.state = .message(message)
- }
- /// Creates a new `Google_Protobuf_Any` by decoding the given string
- /// containing a serialized message in Protocol Buffer text format.
- ///
- /// - Parameters:
- /// - textFormatString: The text format string to decode.
- /// - extensions: An `ExtensionMap` used to look up and decode any
- /// extensions in this message or messages nested within this message's
- /// fields.
- /// - Throws: an instance of `TextFormatDecodingError` on failure.
- @_disfavoredOverload
- public init(
- textFormatString: String,
- extensions: (any ExtensionMap)? = nil
- ) throws {
- // TODO: Remove this api and default the options instead when we do a major release.
- try self.init(
- textFormatString: textFormatString,
- options: TextFormatDecodingOptions(),
- extensions: extensions
- )
- }
- /// Creates a new `Google_Protobuf_Any` by decoding the given string
- /// containing a serialized message in Protocol Buffer text format.
- ///
- /// - Parameters:
- /// - textFormatString: The text format string to decode.
- /// - options: The ``TextFormatDecodingOptions`` to use.
- /// - extensions: An ``ExtensionMap`` used to look up and decode any
- /// extensions in this message or messages nested within this message's
- /// fields.
- /// - Throws: ``TextFormatDecodingError`` on failure.
- public init(
- textFormatString: String,
- options: TextFormatDecodingOptions = TextFormatDecodingOptions(),
- extensions: (any ExtensionMap)? = nil
- ) throws {
- self.init()
- if !textFormatString.isEmpty {
- if let data = textFormatString.data(using: String.Encoding.utf8) {
- try data.withUnsafeBytes { (body: UnsafeRawBufferPointer) in
- if let baseAddress = body.baseAddress, body.count > 0 {
- var textDecoder = try TextFormatDecoder(
- messageType: Google_Protobuf_Any.self,
- utf8Pointer: baseAddress,
- count: body.count,
- options: options,
- extensions: extensions
- )
- try decodeTextFormat(decoder: &textDecoder)
- if !textDecoder.complete {
- throw TextFormatDecodingError.trailingGarbage
- }
- }
- }
- }
- }
- }
- /// Returns true if this `Google_Protobuf_Any` message contains the given
- /// message type.
- ///
- /// The check is performed by looking at the passed `Message.Type` and the
- /// `typeURL` of this message.
- ///
- /// - Parameter type: The concrete message type.
- /// - Returns: True if the receiver contains the given message type.
- public func isA<M: Message>(_ type: M.Type) -> Bool {
- _storage.isA(type)
- }
- public func hash(into hasher: inout Hasher) {
- _storage.hash(into: &hasher)
- }
- }
- extension Google_Protobuf_Any {
- internal func textTraverse(visitor: inout TextFormatEncodingVisitor) {
- _storage.textTraverse(visitor: &visitor)
- try! unknownFields.traverse(visitor: &visitor)
- }
- }
- extension Google_Protobuf_Any {
- // Custom text format decoding support for Any objects.
- // (Note: This is not a part of any protocol; it's invoked
- // directly from TextFormatDecoder whenever it sees an attempt
- // to decode an Any object)
- internal mutating func decodeTextFormat(
- decoder: inout TextFormatDecoder
- ) throws {
- // First, check if this uses the "verbose" Any encoding.
- // If it does, and we have the type available, we can
- // eagerly decode the contained Message object.
- if let url = try decoder.scanner.nextOptionalAnyURL() {
- try _uniqueStorage().decodeTextFormat(typeURL: url, decoder: &decoder)
- } else {
- // This is not using the specialized encoding, so we can use the
- // standard path to decode the binary value.
- // First, clear the fields so we don't waste time re-serializing
- // the previous contents as this instances get replaced with a
- // new value (can happen when a field name/number is repeated in
- // the TextFormat input).
- self.typeURL = ""
- self.value = Data()
- try decodeMessage(decoder: &decoder)
- }
- }
- }
- extension Google_Protobuf_Any: _CustomJSONCodable {
- internal func encodedJSONString(options: JSONEncodingOptions) throws -> String {
- try _storage.encodedJSONString(options: options)
- }
- internal mutating func decodeJSON(from decoder: inout JSONDecoder) throws {
- try _uniqueStorage().decodeJSON(from: &decoder)
- }
- }
|