2022-03-04 13:28:00 -08:00
|
|
|
//
|
|
|
|
|
// Copyright RevenueCat Inc. All Rights Reserved.
|
|
|
|
|
//
|
|
|
|
|
// Licensed under the MIT License (the "License");
|
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
|
//
|
|
|
|
|
// https://opensource.org/licenses/MIT
|
|
|
|
|
//
|
|
|
|
|
// AnyEncodable.swift
|
|
|
|
|
//
|
|
|
|
|
// Created by Nacho Soto on 3/2/22.
|
|
|
|
|
|
|
|
|
|
import Foundation
|
|
|
|
|
|
|
|
|
|
// Inspired by https://github.com/Flight-School/AnyCodable
|
|
|
|
|
|
|
|
|
|
struct AnyEncodable {
|
|
|
|
|
|
|
|
|
|
let value: Any
|
|
|
|
|
|
|
|
|
|
init<T>(_ value: T?) { self.value = value ?? () }
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-07 15:18:24 -07:00
|
|
|
// swiftlint:disable cyclomatic_complexity
|
|
|
|
|
|
2022-03-04 13:28:00 -08:00
|
|
|
extension AnyEncodable: Encodable {
|
|
|
|
|
|
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
|
|
|
var container = encoder.singleValueContainer()
|
|
|
|
|
|
|
|
|
|
switch self.value {
|
|
|
|
|
case is NSNull:
|
|
|
|
|
try container.encodeNil()
|
|
|
|
|
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 uint as UInt:
|
|
|
|
|
try container.encode(uint)
|
|
|
|
|
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(AnyEncodable.init))
|
|
|
|
|
case let dictionary as [String: Any?]:
|
|
|
|
|
try container.encode(dictionary.mapValues(AnyEncodable.init))
|
|
|
|
|
case let encodable as Encodable:
|
|
|
|
|
try encodable.encode(to: encoder)
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
throw EncodingError.invalidValue(
|
|
|
|
|
self.value,
|
|
|
|
|
.init(
|
|
|
|
|
codingPath: container.codingPath,
|
|
|
|
|
debugDescription: "AnyEncodable value cannot be encoded"
|
|
|
|
|
)
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
2023-07-07 15:18:24 -07:00
|
|
|
|
|
|
|
|
/// `AnyEncodable` can also be decoded
|
|
|
|
|
extension AnyEncodable: Decodable {
|
|
|
|
|
|
|
|
|
|
init(from decoder: Decoder) throws {
|
|
|
|
|
let container = try decoder.singleValueContainer()
|
|
|
|
|
|
|
|
|
|
if container.decodeNil() {
|
|
|
|
|
self.value = ()
|
|
|
|
|
} else if let bool = try? container.decode(Bool.self) {
|
|
|
|
|
self.value = bool
|
|
|
|
|
} else if let int = try? container.decode(Int.self) {
|
|
|
|
|
self.value = int
|
|
|
|
|
} else if let uint = try? container.decode(UInt.self) {
|
|
|
|
|
self.value = uint
|
|
|
|
|
} else if let float = try? container.decode(Float.self) {
|
|
|
|
|
self.value = float
|
|
|
|
|
} else if let double = try? container.decode(Double.self) {
|
|
|
|
|
self.value = double
|
|
|
|
|
} else if let string = try? container.decode(String.self) {
|
|
|
|
|
self.value = string
|
|
|
|
|
} else if let date = try? container.decode(Date.self) {
|
|
|
|
|
self.value = date
|
|
|
|
|
} else if let url = try? container.decode(URL.self) {
|
|
|
|
|
self.value = url
|
|
|
|
|
} else if let array = try? container.decode([AnyEncodable].self) {
|
|
|
|
|
self.value = array.map { $0.value }
|
|
|
|
|
} else if let dictionary = try? container.decode([String: AnyEncodable].self) {
|
|
|
|
|
self.value = dictionary.mapValues { $0.value }
|
|
|
|
|
} else {
|
|
|
|
|
throw DecodingError.dataCorruptedError(
|
|
|
|
|
in: container,
|
|
|
|
|
debugDescription: "AnyEncodable value cannot be decoded"
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// swiftlint:enable cyclomatic_complexity
|