80 lines
2.5 KiB
Swift
80 lines
2.5 KiB
Swift
import Foundation
|
|
|
|
public class HolderManager {
|
|
public enum Error: Swift.Error {
|
|
case codingKeyNotFound
|
|
case encoderError
|
|
case decoderError
|
|
case decoderErrorModelNotMapped
|
|
}
|
|
fileprivate typealias HoldableDecoder = (SingleValueDecodingContainer) throws -> Holdable
|
|
fileprivate typealias HoldableEncoder = (Holdable, inout SingleValueEncodingContainer) throws -> Void
|
|
fileprivate static var decoders: [String: HoldableDecoder] = [:]
|
|
fileprivate static var encoders: [String: HoldableEncoder] = [:]
|
|
|
|
public static func register<A: Holdable>(_ type: A.Type) {
|
|
decoders[A.identifier] = { container in
|
|
try container.decode(A.self)
|
|
}
|
|
|
|
encoders[A.identifier] = { name, container in
|
|
guard let obj = name as? A else {
|
|
throw HolderManager.Error.encoderError
|
|
}
|
|
try container.encode(obj)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct DynamicKey: CodingKey {
|
|
var stringValue: String
|
|
init?(stringValue: String) {
|
|
self.stringValue = stringValue
|
|
}
|
|
|
|
var intValue: Int? { return nil }
|
|
init?(intValue: Int) { return nil }
|
|
}
|
|
|
|
//MARK: - Holder Extension
|
|
extension Holder {
|
|
|
|
public init(from decoder: Decoder) throws {
|
|
|
|
//get the CodingKey String name that tells the type of holdable
|
|
guard let key = DynamicKey(stringValue: Self.codingKeyName) else {
|
|
throw HolderManager.Error.decoderError
|
|
}
|
|
|
|
//get the type
|
|
let typeContainer = try decoder.container(keyedBy: DynamicKey.self)
|
|
let type = try typeContainer.decode(String.self, forKey: key)
|
|
|
|
//get the container to decode
|
|
let container = try decoder.singleValueContainer()
|
|
|
|
//get the decoder for the type found
|
|
guard let decoder = HolderManager.decoders[type] else {
|
|
throw HolderManager.Error.decoderErrorModelNotMapped
|
|
}
|
|
|
|
//decode the type and ensure it is of HoldableType
|
|
guard let obj = try decoder(container) as? HoldableType else {
|
|
throw HolderManager.Error.decoderError
|
|
}
|
|
|
|
//instantiate Self
|
|
self = Self(name: type, object: obj)
|
|
}
|
|
|
|
public func encode(to encoder: Encoder) throws {
|
|
var container = encoder.singleValueContainer()
|
|
guard let encode = HolderManager.encoders[name],
|
|
let holdable = object as? Holdable else {
|
|
throw HolderManager.Error.encoderError
|
|
}
|
|
try encode(holdable, &container)
|
|
}
|
|
}
|
|
|