| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213 |
- /**
- * AnyCodable
- * Copyright (c) Morten Bjerg Gregersen 2020
- * MIT license, see LICENSE file for details
- */
- import Foundation
- /**
- A type-erased `Encodable` value.
- Heavily inspired by: https://github.com/Flight-School/AnyCodable
- The above can't be used as a dependency, as it triggers linker errors
- when Fluxor and FluxorTestSupport is used in a test target.
- */
- public struct AnyCodable {
- public let value: Any
- public init<T>(_ value: T?) {
- if let dictionary = value as? [String: AnyCodable] {
- self.value = dictionary as [AnyHashable: AnyCodable]
- } else if let dictionary = value as? [String: Any] {
- self.value = dictionary.mapValues(AnyCodable.init) as [AnyHashable: AnyCodable]
- } else if let array = value as? [Any], !(array is [AnyCodable]) {
- self.value = array.map(AnyCodable.init)
- } else {
- self.value = value ?? ()
- }
- }
- }
- extension AnyCodable: Encodable {
- // swiftlint:disable:next cyclomatic_complexity function_body_length
- public func encode(to encoder: Encoder) throws {
- var container = encoder.singleValueContainer()
- switch value {
- case is Void:
- try container.encodeNil()
- case let bool as Bool:
- try container.encode(bool)
- case let int as Int:
- try container.encode(int)
- case let int8 as Int8:
- try container.encode(int8)
- case let int16 as Int16:
- try container.encode(int16)
- case let int32 as Int32:
- try container.encode(int32)
- case let int64 as Int64:
- try container.encode(int64)
- case let uint as UInt:
- try container.encode(uint)
- case let uint8 as UInt8:
- try container.encode(uint8)
- case let uint16 as UInt16:
- try container.encode(uint16)
- case let uint32 as UInt32:
- try container.encode(uint32)
- case let uint64 as UInt64:
- try container.encode(uint64)
- case let float as Float:
- try container.encode(float)
- case let double as Double:
- try container.encode(double)
- case let string as String:
- try container.encode(string)
- case let date as Date:
- try container.encode(date)
- case let url as URL:
- try container.encode(url)
- case let array as [Any?]:
- try container.encode(array.map { AnyCodable($0) })
- case let dictionary as [String: Any?]:
- try container.encode(dictionary.mapValues { AnyCodable($0) })
- case let encodable as Encodable:
- try encodable.encode(to: encoder)
- default:
- let debugDescription = "Value cannot be encoded"
- let context = EncodingError.Context(codingPath: container.codingPath, debugDescription: debugDescription)
- throw EncodingError.invalidValue(value, context)
- }
- }
- }
- extension AnyCodable: Decodable {
- public init(from decoder: Decoder) throws {
- let container = try decoder.singleValueContainer()
- if container.decodeNil() {
- self.init(())
- } 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 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([AnyCodable].self) {
- self.init(array)
- } else if let dictionary = try? container.decode([String: AnyCodable].self) {
- self.init(dictionary)
- } else {
- throw DecodingError.dataCorruptedError(in: container, debugDescription: "Value cannot be decoded")
- }
- }
- }
- extension AnyCodable: Equatable {
- // swiftlint:disable:next cyclomatic_complexity
- public static func == (lhs: AnyCodable, rhs: AnyCodable) -> Bool {
- switch (lhs.value, rhs.value) {
- case is (Void, Void):
- return true
- 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 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 [AnyHashable: AnyCodable], rhs as [AnyHashable: AnyCodable]):
- return lhs == rhs
- case let (lhs as [AnyCodable], rhs as [AnyCodable]):
- return lhs == rhs
- default:
- return false
- }
- }
- }
- extension AnyCodable: 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 AnyCodable: CustomDebugStringConvertible {
- public var debugDescription: String {
- switch value {
- case let value as CustomDebugStringConvertible:
- return "AnyCodable(\(value.debugDescription))"
- default:
- return "AnyCodable(\(description))"
- }
- }
- }
- extension AnyCodable: ExpressibleByNilLiteral {}
- extension AnyCodable: ExpressibleByBooleanLiteral {}
- extension AnyCodable: ExpressibleByIntegerLiteral {}
- extension AnyCodable: ExpressibleByFloatLiteral {}
- extension AnyCodable: ExpressibleByExtendedGraphemeClusterLiteral {}
- extension AnyCodable: ExpressibleByStringLiteral {}
- extension AnyCodable: ExpressibleByArrayLiteral {}
- extension AnyCodable: ExpressibleByDictionaryLiteral {}
- public extension AnyCodable {
- init(nilLiteral _: ()) {
- self.init(nil as Any?)
- }
- init(booleanLiteral value: Bool) {
- self.init(value)
- }
- init(integerLiteral value: Int) {
- self.init(value)
- }
- init(floatLiteral value: Double) {
- self.init(value)
- }
- init(stringLiteral value: String) {
- self.init(value)
- }
- init(arrayLiteral elements: Any...) {
- self.init(elements)
- }
- init(dictionaryLiteral elements: (AnyHashable, Any)...) {
- self.init([AnyHashable: Any](elements, uniquingKeysWith: { first, _ in first }))
- }
- }
|