AnyDecodable.swift 5.1 KB

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