json/Sources/JSON/Coder/Decoding/_JSONKeyedValueDecoder.swift

132 lines
5.5 KiB
Swift

import Foundation
internal struct _JSONKeyedValueDecoder<K: CodingKey>: KeyedDecodingContainerProtocol {
typealias Key = K
var json: [String: JSON]
var codingPath: [CodingKey]
init(at path: [CodingKey], wrapping json: JSON) {
self.codingPath = path
precondition(json.isObject, "JSON must have an object structure")
guard case let JSON.object(structure) = json else {
fatalError()
}
self.json = structure
}
var allKeys: [Key] {
return json.keys.compactMap ({ return Key(stringValue: $0) })
}
func contains(_ key: Key) -> Bool {
return self.json[key.stringValue] != nil
}
func decodeNil(forKey key: Key) throws -> Bool {
guard let entry = self.json[key.stringValue] else {
throw DecodingError.badKey(key, at: self.codingPath)
}
guard case JSON.null = entry else {
return false
}
return true
}
func _decode<T>(_ type: T.Type, forKey key: Key)throws -> T where T: Decodable {
guard let json = self.json[key.stringValue] else {
throw DecodingError.badKey(key, at: self.codingPath)
}
print("decoding again now: ", type, key)
return try json.value(for: type, at: self.codingPath)
}
func _decode<T>(_ type: T.Type, forKey key: Key)throws -> T where T: Decodable & FixedWidthInteger {
guard let json = self.json[key.stringValue] else {
throw DecodingError.badKey(key, at: self.codingPath)
}
return try json.number(at: self.codingPath, as: type)
}
func decode(_ type: Bool.Type, forKey key: Key) throws -> Bool { return try _decode(type, forKey: key) }
func decode(_ type: Int.Type, forKey key: K) throws -> Int { return try _decode(type, forKey: key) }
func decode(_ type: Float.Type, forKey key: K) throws -> Float { return try _decode(type, forKey: key) }
func decode(_ type: Double.Type, forKey key: K) throws -> Double { return try _decode(type, forKey: key) }
func decode(_ type: String.Type, forKey key: K) throws -> String { return try _decode(type, forKey: key) }
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T : Decodable { return try _decode(type, forKey: key) }
func decode(_ type: Int8.Type, forKey key: K) throws -> Int8 { return try _decode(type, forKey: key) }
func decode(_ type: Int16.Type, forKey key: K) throws -> Int16 { return try _decode(type, forKey: key) }
func decode(_ type: Int32.Type, forKey key: K) throws -> Int32 { return try _decode(type, forKey: key) }
func decode(_ type: Int64.Type, forKey key: K) throws -> Int64 { return try _decode(type, forKey: key) }
func decode(_ type: UInt8.Type, forKey key: K) throws -> UInt8 { return try _decode(type, forKey: key) }
func decode(_ type: UInt16.Type, forKey key: K) throws -> UInt16 { return try _decode(type, forKey: key) }
func decode(_ type: UInt32.Type, forKey key: K) throws -> UInt32 { return try _decode(type, forKey: key) }
private func _superDecoder(forKey key: CodingKey) throws -> Decoder {
let value = self.json[key.stringValue] ?? JSON.null
return _JSONDecoder(codingPath: self.codingPath + [key], json: value)
}
func superDecoder() throws -> Decoder {
return try _superDecoder(forKey: Key(stringValue: "super")!)
}
func superDecoder(forKey key: Key) throws -> Decoder {
return try _superDecoder(forKey: key)
}
func nestedContainer<NestedKey>(keyedBy type: NestedKey.Type, forKey key: Key) throws -> KeyedDecodingContainer<NestedKey> where NestedKey : CodingKey {
guard let value = self.json[key.stringValue] else {
throw DecodingError.keyNotFound(
key,
DecodingError.Context(
codingPath: self.codingPath,
debugDescription: "Cannot get \(KeyedDecodingContainer<NestedKey>.self) -- no value found for key \(key)")
)
}
guard value.isObject else {
throw DecodingError.expectedType([String: JSON].self, at: self.codingPath + [key], from: value)
}
let container = _JSONKeyedValueDecoder<NestedKey>.init(at: self.codingPath + [key], wrapping: value)
return KeyedDecodingContainer(container)
}
func nestedUnkeyedContainer(forKey key: Key) throws -> UnkeyedDecodingContainer {
guard let value = self.json[key.stringValue] else {
throw DecodingError.keyNotFound(
key,
DecodingError.Context(
codingPath: self.codingPath,
debugDescription: "Cannot get UnkeyedDecodingContainer -- no value found for key \(key)")
)
}
guard value.isArray else {
throw DecodingError.typeMismatch(
[JSON].self,
DecodingError.Context(codingPath: self.codingPath + [key], debugDescription: "Cannot create UnkeyedContainer from non-array data structure")
)
}
return _JSONUnkeyedDecoder(at: self.codingPath + [key], wrapping: value)
}
}
extension DecodingError {
static func badKey(_ key: CodingKey, at path: [CodingKey]) -> DecodingError {
return DecodingError.keyNotFound(
key,
DecodingError.Context(
codingPath: path,
debugDescription: "No value associated with key \(key).")
)
}
}