| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- #if canImport(Foundation)
- import Foundation
- #endif
- /**
- A type-erased `Decodable` value.
-
- The `AnyDecodable` type forwards decoding responsibilities
- to an underlying value, hiding its specific underlying type.
-
- You can decode mixed-type values in dictionaries
- and other collections that require `Decodable` conformance
- by declaring their contained type to be `AnyDecodable`:
-
- let json = """
- {
- "boolean": true,
- "integer": 42,
- "double": 3.141592653589793,
- "string": "string",
- "array": [1, 2, 3],
- "nested": {
- "a": "alpha",
- "b": "bravo",
- "c": "charlie"
- }
- }
- """.data(using: .utf8)!
-
- let decoder = JSONDecoder()
- let dictionary = try! decoder.decode([String: AnyDecodable].self, from: json)
- */
- #if swift(>=5.1)
- @frozen public struct AnyDecodable: Decodable {
- public let value: Any
- public init<T>(_ value: T?) {
- self.value = value ?? ()
- }
- }
- #else
- public struct AnyDecodable: Decodable {
- public let value: Any
- public init<T>(_ value: T?) {
- self.value = value ?? ()
- }
- }
- #endif
- #if swift(>=4.2)
- public protocol _AnyDecodable {
- var value: Any { get }
- init<T>(_ value: T?)
- }
- #else
- protocol _AnyDecodable {
- var value: Any { get }
- init<T>(_ value: T?)
- }
- #endif
- extension AnyDecodable: _AnyDecodable {}
- public extension _AnyDecodable {
- init(from decoder: Decoder) throws {
- let container = try decoder.singleValueContainer()
- if container.decodeNil() {
- #if canImport(Foundation)
- self.init(NSNull())
- #else
- self.init(Self?.none)
- #endif
- } else if let bool = try? container.decode(Bool.self) {
- self.init(bool)
- } else if let int = try? container.decode(Int.self) {
- self.init(int)
- } else if let uint = try? container.decode(UInt.self) {
- self.init(uint)
- } else if let decimal = try? container.decode(Decimal.self) {
- self.init(decimal)
- } else if let double = try? container.decode(Double.self) {
- self.init(double)
- } else if let string = try? container.decode(String.self) {
- self.init(string)
- } else if let array = try? container.decode([AnyDecodable].self) {
- self.init(array.map(\.value))
- } else if let dictionary = try? container.decode([String: AnyDecodable].self) {
- self.init(dictionary.mapValues { $0.value })
- } else {
- throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyDecodable value cannot be decoded")
- }
- }
- }
- extension AnyDecodable: Equatable {
- public static func == (lhs: AnyDecodable, rhs: AnyDecodable) -> Bool {
- switch (lhs.value, rhs.value) {
- #if canImport(Foundation)
- case is (NSNull, NSNull),
- is (Void, Void):
- return true
- #endif
- case let (lhs as Bool, rhs as Bool):
- return lhs == rhs
- case let (lhs as Int, rhs as Int):
- return lhs == rhs
- case let (lhs as Int8, rhs as Int8):
- return lhs == rhs
- case let (lhs as Int16, rhs as Int16):
- return lhs == rhs
- case let (lhs as Int32, rhs as Int32):
- return lhs == rhs
- case let (lhs as Int64, rhs as Int64):
- return lhs == rhs
- case let (lhs as UInt, rhs as UInt):
- return lhs == rhs
- case let (lhs as UInt8, rhs as UInt8):
- return lhs == rhs
- case let (lhs as UInt16, rhs as UInt16):
- return lhs == rhs
- case let (lhs as UInt32, rhs as UInt32):
- return lhs == rhs
- case let (lhs as UInt64, rhs as UInt64):
- return lhs == rhs
- case let (lhs as Decimal, rhs as Decimal):
- return lhs == rhs
- case let (lhs as Float, rhs as Float):
- return lhs == rhs
- case let (lhs as Double, rhs as Double):
- return lhs == rhs
- case let (lhs as String, rhs as String):
- return lhs == rhs
- case let (lhs as [String: AnyDecodable], rhs as [String: AnyDecodable]):
- return lhs == rhs
- case let (lhs as [AnyDecodable], rhs as [AnyDecodable]):
- return lhs == rhs
- default:
- return false
- }
- }
- }
- extension AnyDecodable: CustomStringConvertible {
- public var description: String {
- switch value {
- case is Void:
- return String(describing: nil as Any?)
- case let value as CustomStringConvertible:
- return value.description
- default:
- return String(describing: value)
- }
- }
- }
- extension AnyDecodable: CustomDebugStringConvertible {
- public var debugDescription: String {
- switch value {
- case let value as CustomDebugStringConvertible:
- return "AnyDecodable(\(value.debugDescription))"
- default:
- return "AnyDecodable(\(description))"
- }
- }
- }
|