AnyEncodable.swift 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. #if canImport(Foundation)
  2. import Foundation
  3. #endif
  4. /**
  5. A type-erased `Encodable` value.
  6. The `AnyEncodable` type forwards encoding responsibilities
  7. to an underlying value, hiding its specific underlying type.
  8. You can encode mixed-type values in dictionaries
  9. and other collections that require `Encodable` conformance
  10. by declaring their contained type to be `AnyEncodable`:
  11. let dictionary: [String: AnyEncodable] = [
  12. "boolean": true,
  13. "integer": 42,
  14. "double": 3.141592653589793,
  15. "string": "string",
  16. "array": [1, 2, 3],
  17. "nested": [
  18. "a": "alpha",
  19. "b": "bravo",
  20. "c": "charlie"
  21. ]
  22. ]
  23. let encoder = JSONEncoder()
  24. let json = try! encoder.encode(dictionary)
  25. */
  26. #if swift(>=5.1)
  27. @frozen public struct AnyEncodable: Encodable {
  28. public let value: Any
  29. public init<T>(_ value: T?) {
  30. self.value = value ?? ()
  31. }
  32. }
  33. #else
  34. public struct AnyEncodable: Encodable {
  35. public let value: Any
  36. public init<T>(_ value: T?) {
  37. self.value = value ?? ()
  38. }
  39. }
  40. #endif
  41. #if swift(>=4.2)
  42. public protocol _AnyEncodable {
  43. var value: Any { get }
  44. init<T>(_ value: T?)
  45. }
  46. #else
  47. protocol _AnyEncodable {
  48. var value: Any { get }
  49. init<T>(_ value: T?)
  50. }
  51. #endif
  52. extension AnyEncodable: _AnyEncodable {}
  53. // MARK: - Encodable
  54. extension _AnyEncodable {
  55. public func encode(to encoder: Encoder) throws {
  56. var container = encoder.singleValueContainer()
  57. switch value {
  58. #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
  59. case let number as NSNumber:
  60. try encode(nsnumber: number, into: &container)
  61. #endif
  62. #if canImport(Foundation)
  63. case is NSNull:
  64. try container.encodeNil()
  65. #endif
  66. case is Void:
  67. try container.encodeNil()
  68. case let bool as Bool:
  69. try container.encode(bool)
  70. case let int as Int:
  71. try container.encode(int)
  72. case let int8 as Int8:
  73. try container.encode(int8)
  74. case let int16 as Int16:
  75. try container.encode(int16)
  76. case let int32 as Int32:
  77. try container.encode(int32)
  78. case let int64 as Int64:
  79. try container.encode(int64)
  80. case let uint as UInt:
  81. try container.encode(uint)
  82. case let uint8 as UInt8:
  83. try container.encode(uint8)
  84. case let uint16 as UInt16:
  85. try container.encode(uint16)
  86. case let uint32 as UInt32:
  87. try container.encode(uint32)
  88. case let uint64 as UInt64:
  89. try container.encode(uint64)
  90. case let decimal as Decimal:
  91. try container.encode(decimal)
  92. case let float as Float:
  93. try container.encode(float)
  94. case let double as Double:
  95. try container.encode(double)
  96. case let string as String:
  97. try container.encode(string)
  98. #if canImport(Foundation)
  99. case let date as Date:
  100. try container.encode(date)
  101. case let url as URL:
  102. try container.encode(url)
  103. #endif
  104. case let array as [Any?]:
  105. try container.encode(array.map { AnyEncodable($0) })
  106. case let dictionary as [String: Any?]:
  107. try container.encode(dictionary.mapValues { AnyEncodable($0) })
  108. default:
  109. let context = EncodingError.Context(
  110. codingPath: container.codingPath,
  111. debugDescription: "AnyEncodable value cannot be encoded"
  112. )
  113. throw EncodingError.invalidValue(value, context)
  114. }
  115. }
  116. #if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
  117. private func encode(nsnumber: NSNumber, into container: inout SingleValueEncodingContainer) throws {
  118. switch CFNumberGetType(nsnumber) {
  119. case .charType:
  120. try container.encode(nsnumber.boolValue)
  121. case .sInt8Type:
  122. try container.encode(nsnumber.int8Value)
  123. case .sInt16Type:
  124. try container.encode(nsnumber.int16Value)
  125. case .sInt32Type:
  126. try container.encode(nsnumber.int32Value)
  127. case .sInt64Type:
  128. try container.encode(nsnumber.int64Value)
  129. case .shortType:
  130. try container.encode(nsnumber.uint16Value)
  131. case .longType:
  132. try container.encode(nsnumber.uint32Value)
  133. case .longLongType:
  134. try container.encode(nsnumber.uint64Value)
  135. case .cfIndexType,
  136. .intType,
  137. .nsIntegerType:
  138. try container.encode(nsnumber.intValue)
  139. case .float32Type,
  140. .floatType:
  141. try container.encode(nsnumber.floatValue)
  142. case .cgFloatType,
  143. .doubleType,
  144. .float64Type:
  145. try container.encode(nsnumber.doubleValue)
  146. #if swift(>=5.0)
  147. @unknown default:
  148. let context = EncodingError.Context(
  149. codingPath: container.codingPath,
  150. debugDescription: "NSNumber cannot be encoded because its type is not handled"
  151. )
  152. throw EncodingError.invalidValue(nsnumber, context)
  153. #endif
  154. }
  155. }
  156. #endif
  157. }
  158. extension AnyEncodable: Equatable {
  159. public static func == (lhs: AnyEncodable, rhs: AnyEncodable) -> Bool {
  160. switch (lhs.value, rhs.value) {
  161. case is (Void, Void):
  162. return true
  163. case let (lhs as Bool, rhs as Bool):
  164. return lhs == rhs
  165. case let (lhs as Int, rhs as Int):
  166. return lhs == rhs
  167. case let (lhs as Int8, rhs as Int8):
  168. return lhs == rhs
  169. case let (lhs as Int16, rhs as Int16):
  170. return lhs == rhs
  171. case let (lhs as Int32, rhs as Int32):
  172. return lhs == rhs
  173. case let (lhs as Int64, rhs as Int64):
  174. return lhs == rhs
  175. case let (lhs as UInt, rhs as UInt):
  176. return lhs == rhs
  177. case let (lhs as UInt8, rhs as UInt8):
  178. return lhs == rhs
  179. case let (lhs as UInt16, rhs as UInt16):
  180. return lhs == rhs
  181. case let (lhs as UInt32, rhs as UInt32):
  182. return lhs == rhs
  183. case let (lhs as UInt64, rhs as UInt64):
  184. return lhs == rhs
  185. case let (lhs as Decimal, rhs as Decimal):
  186. return lhs == rhs
  187. case let (lhs as Float, rhs as Float):
  188. return lhs == rhs
  189. case let (lhs as Double, rhs as Double):
  190. return lhs == rhs
  191. case let (lhs as String, rhs as String):
  192. return lhs == rhs
  193. case let (lhs as [String: AnyEncodable], rhs as [String: AnyEncodable]):
  194. return lhs == rhs
  195. case let (lhs as [AnyEncodable], rhs as [AnyEncodable]):
  196. return lhs == rhs
  197. default:
  198. return false
  199. }
  200. }
  201. }
  202. extension AnyEncodable: CustomStringConvertible {
  203. public var description: String {
  204. switch value {
  205. case is Void:
  206. return String(describing: nil as Any?)
  207. case let value as CustomStringConvertible:
  208. return value.description
  209. default:
  210. return String(describing: value)
  211. }
  212. }
  213. }
  214. extension AnyEncodable: CustomDebugStringConvertible {
  215. public var debugDescription: String {
  216. switch value {
  217. case let value as CustomDebugStringConvertible:
  218. return "AnyEncodable(\(value.debugDescription))"
  219. default:
  220. return "AnyEncodable(\(description))"
  221. }
  222. }
  223. }
  224. extension AnyEncodable: ExpressibleByNilLiteral {}
  225. extension AnyEncodable: ExpressibleByBooleanLiteral {}
  226. extension AnyEncodable: ExpressibleByIntegerLiteral {}
  227. extension AnyEncodable: ExpressibleByFloatLiteral {}
  228. extension AnyEncodable: ExpressibleByStringLiteral {}
  229. #if swift(>=5.0)
  230. extension AnyEncodable: ExpressibleByStringInterpolation {}
  231. #endif
  232. extension AnyEncodable: ExpressibleByArrayLiteral {}
  233. extension AnyEncodable: ExpressibleByDictionaryLiteral {}
  234. public extension _AnyEncodable {
  235. init(nilLiteral _: ()) {
  236. self.init(nil as Any?)
  237. }
  238. init(booleanLiteral value: Bool) {
  239. self.init(value)
  240. }
  241. init(integerLiteral value: Int) {
  242. self.init(value)
  243. }
  244. init(floatLiteral value: Double) {
  245. self.init(value)
  246. }
  247. init(extendedGraphemeClusterLiteral value: String) {
  248. self.init(value)
  249. }
  250. init(stringLiteral value: String) {
  251. self.init(value)
  252. }
  253. init(arrayLiteral elements: Any...) {
  254. self.init(elements)
  255. }
  256. init(dictionaryLiteral elements: (AnyHashable, Any)...) {
  257. self.init([AnyHashable: Any](elements, uniquingKeysWith: { first, _ in first }))
  258. }
  259. }