Skip to content

Instantly share code, notes, and snippets.

@NikolaiRuhe
Created October 15, 2018 20:44
Show Gist options
  • Save NikolaiRuhe/f9d37ed8e23012f46be48290f8a95319 to your computer and use it in GitHub Desktop.
Save NikolaiRuhe/f9d37ed8e23012f46be48290f8a95319 to your computer and use it in GitHub Desktop.
JSON DOM Swift implementation
import Foundation
/// A JSONValue is a generic DOM representation of decoded JSON.
enum JSONValue {
case null
case boolean(Bool)
case number(Double)
case string(String)
case array(JSONArray)
case object(JSONObject)
typealias JSONArray = Array<JSONValue>
typealias JSONObject = Dictionary<String, JSONValue>
}
extension JSONValue : Codable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if (try? decoder.unkeyedContainer()) != nil {
self = .array(try container.decode(JSONArray.self))
return
}
enum AnyKey: CodingKey {}
if (try? decoder.container(keyedBy: AnyKey.self)) != nil {
self = .object(try container.decode(JSONObject.self))
return
}
guard !container.decodeNil() else {
self = .null
return
}
do {
self = .boolean(try container.decode(Bool.self))
return
} catch {}
do {
self = .number(try container.decode(Double.self))
return
} catch {}
self = .string(try container.decode(String.self))
}
func encode(to encoder: Encoder) throws {
var encoder = encoder.singleValueContainer()
switch self {
case .null: try encoder.encodeNil()
case .boolean(let value): try encoder.encode(value)
case .number (let value): try encoder.encode(value)
case .string (let value): try encoder.encode(value)
case .array (let value): try encoder.encode(value)
case .object (let value): try encoder.encode(value)
}
}
}
extension JSONValue : CustomStringConvertible {
var description: String {
let data = try! JSONEncoder().encode([self])
let string = String(data: data, encoding: .utf8)!
return String(string.dropFirst().dropLast())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment