Skip to content

Instantly share code, notes, and snippets.

@jarsen
Created June 15, 2015 21:28
Show Gist options
  • Save jarsen/10150c39301834da398f to your computer and use it in GitHub Desktop.
Save jarsen/10150c39301834da398f to your computer and use it in GitHub Desktop.
//: Playground - noun: a place where people can play
import UIKit
struct Address {
var street: String
}
struct Person {
var name: String
var age: Int
var dutch: Bool
var address: Address?
}
extension MirrorType {
var children: [(String, MirrorType)] {
var result: [(String, MirrorType)] = []
for i in 0..<self.count {
result.append(self[i])
}
return result
}
}
typealias JSONObject = [String:AnyObject]
protocol JSONCodable {
func toJSON() throws -> AnyObject?
static func fromJSON(value: AnyObject) throws -> Self
static func fromJSON(object: JSONObject, key: String) throws -> Self
}
enum JSONError : ErrorType {
case NotSerializable(source: Any, type: MirrorType)
case NoValueForKey(String)
case TypeMismatch(expected: MirrorType, got: MirrorType)
}
extension JSONCodable {
func toJSON() throws -> AnyObject? {
let mirror = reflect(self)
if mirror.count > 0 {
var result: [String:AnyObject] = [:]
for (key, child) in mirror.children {
if let value = child.value as? JSONCodable {
result[key] = try value.toJSON()
} else {
throw JSONError.NotSerializable(source: self, type: child)
}
}
return result
}
return self as? AnyObject
}
static func fromJSON(object: JSONObject, key: String) throws -> Self {
if let value = object[key] {
return try self.fromJSON(value)
}
throw JSONError.NoValueForKey(key)
}
}
extension Int: JSONCodable {
static func fromJSON(value: AnyObject) throws -> Int {
if let x = value as? Int {
return x
}
throw JSONError.TypeMismatch(expected: reflect(Int), got: reflect(value))
}
}
extension String: JSONCodable {
static func fromJSON(value: AnyObject) throws -> String {
if let x = value as? String {
return x
}
throw JSONError.TypeMismatch(expected: reflect(String), got: reflect(value))
}
}
extension Bool: JSONCodable {
static func fromJSON(value: AnyObject) throws -> Bool {
if let x = value as? Bool {
return x
}
throw JSONError.TypeMismatch(expected: reflect(Bool), got: reflect(value))
}
}
extension Address: JSONCodable {
static func fromJSON(value: AnyObject) throws -> Address {
if let object = value as? JSONObject {
let street = try String.fromJSON(object, key: "street")
return Address(street: street)
}
throw JSONError.TypeMismatch(expected: reflect(Bool), got: reflect(value))
}
}
extension Person: JSONCodable {
static func fromJSON(value: AnyObject) throws -> Person {
if let object = value as? JSONObject {
let name = try String.fromJSON(object, key: "name")
let age = try Int.fromJSON(object, key: "age")
let dutch = try Bool.fromJSON(object, key: "dutch")
let address = try Address?.fromJSON(object, key: "address")
return Person(name: name, age: age, dutch: dutch, address: address)
}
throw JSONError.TypeMismatch(expected: reflect(Person), got: reflect(value))
}
}
extension Optional: JSONCodable {
func toJSON() throws -> AnyObject? {
if let x = self {
if let value = x as? JSONCodable {
return try value.toJSON()
}
throw JSONError.NotSerializable(source: x, type: reflect(x))
}
return nil
}
static func fromJSON(value: AnyObject) throws -> T? {
return .Some(try (T.self as! JSONCodable).dynamicType.fromJSON(value) as! T)
if T.self is JSONCodable {
return .Some(try (T.self as! JSONCodable).dynamicType.fromJSON(value) as! T)
}
throw JSONError.NotSerializable(source: value, type: reflect(value))
}
static func fromJSON(object: JSONObject, key: String) throws -> T? {
if let value = object[key] {
value
print(value)
return try self.fromJSON(value)!
}
return .None
}
}
do {
// let person = try Person.fromJSON(["name": "Jason", "age": 27, "dutch": false])
let person = try Person.fromJSON(["name": "Jason", "age": 27, "address": ["street" : "A Street"], "dutch": false])
let object2 = try person.toJSON()
}
catch let JSONError.NoValueForKey(key) {
print(key)
}
catch let JSONError.TypeMismatch(expected: a, got: b) {
print(a)
print(b)
}
catch {
print(error)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment