AutoCat2/Shared/ThirdParty/GenericJSON/JSON.swift

83 lines
2.5 KiB
Swift

import Foundation
/// A JSON value representation. This is a bit more useful than the naïve `[String:Any]` type
/// for JSON values, since it makes sure only valid JSON values are present & supports `Equatable`
/// and `Codable`, so that you can compare values for equality and code and decode them into data
/// or strings.
@dynamicMemberLookup public enum JSON: Equatable {
case string(String)
case number(Double)
case object([String:JSON])
case array([JSON])
case bool(Bool)
case null
}
extension JSON: Codable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case let .array(array):
try container.encode(array)
case let .object(object):
try container.encode(object)
case let .string(string):
try container.encode(string)
case let .number(number):
try container.encode(number)
case let .bool(bool):
try container.encode(bool)
case .null:
try container.encodeNil()
}
}
public init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let object = try? container.decode([String: JSON].self) {
self = .object(object)
} else if let array = try? container.decode([JSON].self) {
self = .array(array)
} else if let string = try? container.decode(String.self) {
self = .string(string)
} else if let bool = try? container.decode(Bool.self) {
self = .bool(bool)
} else if let number = try? container.decode(Double.self) {
self = .number(number)
} else if container.decodeNil() {
self = .null
} else {
throw DecodingError.dataCorrupted(
.init(codingPath: decoder.codingPath, debugDescription: "Invalid JSON value.")
)
}
}
}
extension JSON: CustomDebugStringConvertible {
public var debugDescription: String {
switch self {
case .string(let str):
return str.debugDescription
case .number(let num):
return num.debugDescription
case .bool(let bool):
return bool.description
case .null:
return "null"
default:
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted]
return try! String(data: encoder.encode(self), encoding: .utf8)!
}
}
}
extension JSON: Hashable {}