damus

nostr ios client
git clone git://jb55.com/damus
Log | Files | Refs | README | LICENSE

AnyDecodable.swift (5900B)


      1 #if canImport(Foundation)
      2 import Foundation
      3 #endif
      4 
      5 /**
      6  A type-erased `Decodable` value.
      7 
      8  The `AnyDecodable` type forwards decoding responsibilities
      9  to an underlying value, hiding its specific underlying type.
     10 
     11  You can decode mixed-type values in dictionaries
     12  and other collections that require `Decodable` conformance
     13  by declaring their contained type to be `AnyDecodable`:
     14 
     15      let json = """
     16      {
     17          "boolean": true,
     18          "integer": 42,
     19          "double": 3.141592653589793,
     20          "string": "string",
     21          "array": [1, 2, 3],
     22          "nested": {
     23              "a": "alpha",
     24              "b": "bravo",
     25              "c": "charlie"
     26          },
     27          "null": null
     28      }
     29      """.data(using: .utf8)!
     30 
     31      let decoder = JSONDecoder()
     32      let dictionary = try! decoder.decode([String: AnyDecodable].self, from: json)
     33  */
     34 @frozen public struct AnyDecodable: Decodable {
     35     public let value: Any
     36 
     37     public init<T>(_ value: T?) {
     38         self.value = value ?? ()
     39     }
     40 }
     41 
     42 @usableFromInline
     43 protocol _AnyDecodable {
     44     var value: Any { get }
     45     init<T>(_ value: T?)
     46 }
     47 
     48 extension AnyDecodable: _AnyDecodable {}
     49 
     50 extension _AnyDecodable {
     51     public init(from decoder: Decoder) throws {
     52         let container = try decoder.singleValueContainer()
     53 
     54         if container.decodeNil() {
     55             #if canImport(Foundation)
     56                 self.init(NSNull())
     57             #else
     58                 self.init(Optional<Self>.none)
     59             #endif
     60         } else if let bool = try? container.decode(Bool.self) {
     61             self.init(bool)
     62         } else if let int = try? container.decode(Int.self) {
     63             self.init(int)
     64         } else if let uint = try? container.decode(UInt.self) {
     65             self.init(uint)
     66         } else if let double = try? container.decode(Double.self) {
     67             self.init(double)
     68         } else if let string = try? container.decode(String.self) {
     69             self.init(string)
     70         } else if let array = try? container.decode([AnyDecodable].self) {
     71             self.init(array.map { $0.value })
     72         } else if let dictionary = try? container.decode([String: AnyDecodable].self) {
     73             self.init(dictionary.mapValues { $0.value })
     74         } else {
     75             throw DecodingError.dataCorruptedError(in: container, debugDescription: "AnyDecodable value cannot be decoded")
     76         }
     77     }
     78 }
     79 
     80 extension AnyDecodable: Equatable {
     81     public static func == (lhs: AnyDecodable, rhs: AnyDecodable) -> Bool {
     82         switch (lhs.value, rhs.value) {
     83 #if canImport(Foundation)
     84         case is (NSNull, NSNull), is (Void, Void):
     85             return true
     86 #endif
     87         case let (lhs as Bool, rhs as Bool):
     88             return lhs == rhs
     89         case let (lhs as Int, rhs as Int):
     90             return lhs == rhs
     91         case let (lhs as Int8, rhs as Int8):
     92             return lhs == rhs
     93         case let (lhs as Int16, rhs as Int16):
     94             return lhs == rhs
     95         case let (lhs as Int32, rhs as Int32):
     96             return lhs == rhs
     97         case let (lhs as Int64, rhs as Int64):
     98             return lhs == rhs
     99         case let (lhs as UInt, rhs as UInt):
    100             return lhs == rhs
    101         case let (lhs as UInt8, rhs as UInt8):
    102             return lhs == rhs
    103         case let (lhs as UInt16, rhs as UInt16):
    104             return lhs == rhs
    105         case let (lhs as UInt32, rhs as UInt32):
    106             return lhs == rhs
    107         case let (lhs as UInt64, rhs as UInt64):
    108             return lhs == rhs
    109         case let (lhs as Float, rhs as Float):
    110             return lhs == rhs
    111         case let (lhs as Double, rhs as Double):
    112             return lhs == rhs
    113         case let (lhs as String, rhs as String):
    114             return lhs == rhs
    115         case let (lhs as [String: AnyDecodable], rhs as [String: AnyDecodable]):
    116             return lhs == rhs
    117         case let (lhs as [AnyDecodable], rhs as [AnyDecodable]):
    118             return lhs == rhs
    119         default:
    120             return false
    121         }
    122     }
    123 }
    124 
    125 extension AnyDecodable: CustomStringConvertible {
    126     public var description: String {
    127         switch value {
    128         case is Void:
    129             return String(describing: nil as Any?)
    130         case let value as CustomStringConvertible:
    131             return value.description
    132         default:
    133             return String(describing: value)
    134         }
    135     }
    136 }
    137 
    138 extension AnyDecodable: CustomDebugStringConvertible {
    139     public var debugDescription: String {
    140         switch value {
    141         case let value as CustomDebugStringConvertible:
    142             return "AnyDecodable(\(value.debugDescription))"
    143         default:
    144             return "AnyDecodable(\(description))"
    145         }
    146     }
    147 }
    148 
    149 extension AnyDecodable: Hashable {
    150     public func hash(into hasher: inout Hasher) {
    151         switch value {
    152         case let value as Bool:
    153             hasher.combine(value)
    154         case let value as Int:
    155             hasher.combine(value)
    156         case let value as Int8:
    157             hasher.combine(value)
    158         case let value as Int16:
    159             hasher.combine(value)
    160         case let value as Int32:
    161             hasher.combine(value)
    162         case let value as Int64:
    163             hasher.combine(value)
    164         case let value as UInt:
    165             hasher.combine(value)
    166         case let value as UInt8:
    167             hasher.combine(value)
    168         case let value as UInt16:
    169             hasher.combine(value)
    170         case let value as UInt32:
    171             hasher.combine(value)
    172         case let value as UInt64:
    173             hasher.combine(value)
    174         case let value as Float:
    175             hasher.combine(value)
    176         case let value as Double:
    177             hasher.combine(value)
    178         case let value as String:
    179             hasher.combine(value)
    180         case let value as [String: AnyDecodable]:
    181             hasher.combine(value)
    182         case let value as [AnyDecodable]:
    183             hasher.combine(value)
    184         default:
    185             break
    186         }
    187     }
    188 }