Skip to content

Instantly share code, notes, and snippets.

@cfr
Last active August 29, 2015 14:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save cfr/a28ede6e0b71331947ec to your computer and use it in GitHub Desktop.
Save cfr/a28ede6e0b71331947ec to your computer and use it in GitHub Desktop.
import Foundation
public protocol JSONEncodable {
var json: [String : AnyObject] { get }
var Name: String { get }
}
public protocol JSONDecodable {
init?(json: [String : AnyObject])
}
// JSON mapping operators
typealias JSON = [String : AnyObject]
infix operator ~~ { associativity left }
infix operator ~~? { associativity left }
func ~~ <A, B, C>(t: (A -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a = json[key] as? A { return (con(a), json) }
else { return nil }
}
func ~~ <A: JSONDecodable, B, C>(t: ([A] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsons = json[key] as? [JSON] {
var array = [A](); for json in jsons { if let a = A(json: json) { array.append(a) } }
return (con(array), json)
} else { return nil }
}
func ~~ <A: JSONDecodable, B, C>(t: ([String : A] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsons = json[key] as? [String : JSON] {
var dict = [String : A](); for (key, json) in jsons { if let a = A(json: json) { dict[key] = a } }
return (con(dict), json)
} else { return nil }
}
func ~~ <A, B>(t: (A -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a = json[key] as? A { return con(a) }
else { return nil }
}
func ~~ <A: JSONDecodable, B>(t: ([A] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsons = json[key] as? [JSON] {
var array = [A](); for json in jsons { if let a = A(json: json) { array.append(a) } }
return con(array)
} else { return nil }
}
func ~~ <A: JSONDecodable, B>(t: ([String : A] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsons = json[key] as? [String : JSON] {
var dict = [String : A](); for (key, json) in jsons { if let a = A(json: json) { dict[key] = a } }
return con(dict)
} else { return nil }
}
func ~~? <A, B, C>(t: (A? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key] as? A), json) }
else { return nil }
}
func ~~? <A: JSONDecodable, B, C>(t: (A? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t {
if let ajson = json[key] as? JSON { return (con(A(json: ajson)), json) }
else { return (con(nil), json) }
} else { return nil }
}
func ~~? <A: JSONDecodable, B, C>(t: ([A]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t {
if let jsons = json[key] as? [JSON] {
var array = [A](); for json in jsons { if let a = A(json: json) { array.append(a) } }
return (con(array), json)
} else { return (con(nil), json) }
} else { return nil }
}
func ~~? <A: JSONDecodable, B, C>(t: ([String : A]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { if let jsons = json[key] as? [String : JSON] {
var dict = [String : A](); for (key, json) in jsons { if let a = A(json: json) { dict[key] = a } }
return (con(dict), json)
} else { return (con(nil), json) }
} else { return nil }
}
func ~~? <A, B>(t: (A? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key] as? A) }
else { return nil }
}
func ~~? <A: JSONDecodable, B>(t: (A? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t {
if let ajson = json[key] as? JSON { return con(A(json: ajson)) }
else { return con(nil) }
} else { return nil }
}
func ~~? <A: JSONDecodable, B>(t: ([A]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { if let jsons = json[key] as? [JSON] {
var array = [A](); for json in jsons { if let a = A(json: json) { array.append(a) } }
return con(array)
} else { return con(nil) }
} else { return nil }
}
func ~~? <A: JSONDecodable, B>(t: ([String : A]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { if let jsons = json[key] as? [String : JSON] {
var dict = [String : A](); for (key, json) in jsons { if let a = A(json: json) { dict[key] = a } }
return con(dict)
} else { return con(nil) }
} else { return nil }
}
// Dynamicity Shield
func ~~ <B, C>(t: (String -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a: AnyObject = json[key] { return (con(toString(a)), json) }
else { return nil }
}
func ~~ <B>(t: (String -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a: AnyObject = json[key] { return con(toString(a)) }
else { return nil }
}
func ~~? <B, C>(t: (String? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map(toString)), json) }
else { return nil }
}
func ~~? <B>(t: (String? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map(toString)) }
else { return nil }
}
func ~~ <B, C>(t: ([String] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return (con(a.map(toString)), json) }
else { return nil }
}
func ~~ <B>(t: ([String] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return con(a.map(toString)) }
else { return nil }
}
func ~~? <B, C>(t: ([String]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toString)} else { return [] } })), json) }
else { return nil }
}
func ~~? <B>(t: ([String]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toString)} else { return [] } })) }
else { return nil }
}
func ~~ <B, C>(t: ([String : String] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : String](); for (key, val) in jsond { dict[key] = toString(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~ <B>(t: ([String : String] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : String](); for (key, val) in jsond { dict[key] = toString(val) }
return con(dict)
}
else { return nil }
}
func ~~? <B, C>(t: ([String : String]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : String](); for (key, val) in jsond { dict[key] = toString(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~? <B>(t: ([String : String]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : String](); for (key, val) in jsond { dict[key] = toString(val) }
return con(dict)
}
else { return nil }
}
func toInt(o: AnyObject) -> Int {
if let o = o as? Int { return o }
if let o = o as? Bool { return Int(o) }
if let o = o as? String { return o.toInt() ?? 0 }
if let o = o as? Float { return Int(o) }
if let o = o as? NSNumber { return o.integerValue }
return 0
}
func ~~ <B, C>(t: (Int -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a: AnyObject = json[key] { return (con(toInt(a)), json) }
else { return nil }
}
func ~~ <B>(t: (Int -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a: AnyObject = json[key] { return con(toInt(a)) }
else { return nil }
}
func ~~? <B, C>(t: (Int? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map(toInt)), json) }
else { return nil }
}
func ~~? <B>(t: (Int? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map(toInt)) }
else { return nil }
}
func ~~ <B, C>(t: ([Int] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return (con(a.map(toInt)), json) }
else { return nil }
}
func ~~ <B>(t: ([Int] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return con(a.map(toInt)) }
else { return nil }
}
func ~~? <B, C>(t: ([Int]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toInt)} else { return [] } })), json) }
else { return nil }
}
func ~~? <B>(t: ([Int]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toInt)} else { return [] } })) }
else { return nil }
}
func ~~ <B, C>(t: ([String : Int] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Int](); for (key, val) in jsond { dict[key] = toInt(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~ <B>(t: ([String : Int] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Int](); for (key, val) in jsond { dict[key] = toInt(val) }
return con(dict)
}
else { return nil }
}
func ~~? <B, C>(t: ([String : Int]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Int](); for (key, val) in jsond { dict[key] = toInt(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~? <B>(t: ([String : Int]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Int](); for (key, val) in jsond { dict[key] = toInt(val) }
return con(dict)
}
else { return nil }
}
func toBool(o: AnyObject) -> Bool {
if let o = o as? Bool { return o }
if let o = o as? String { switch o.lowercaseString {
case "true", "yes", "1": return true
default: return false }
}
if let o = o as? Int { return o > 0 }
if let o = o as? NSNumber { return o.boolValue }
return false
}
func ~~ <B, C>(t: (Bool -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a: AnyObject = json[key] { return (con(toBool(a)), json) }
else { return nil }
}
func ~~ <B>(t: (Bool -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a: AnyObject = json[key] { return con(toBool(a)) }
else { return nil }
}
func ~~? <B, C>(t: (Bool? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map(toBool)), json) }
else { return nil }
}
func ~~? <B>(t: (Bool? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map(toBool)) }
else { return nil }
}
func ~~ <B, C>(t: ([Bool] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return (con(a.map(toBool)), json) }
else { return nil }
}
func ~~ <B>(t: ([Bool] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, a = json[key] as? [AnyObject] { return con(a.map(toBool)) }
else { return nil }
}
func ~~? <B, C>(t: ([Bool]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t { return (con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toBool)} else { return [] } })), json) }
else { return nil }
}
func ~~? <B>(t: ([Bool]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t { return con(json[key].map({ if let arr = $0 as? [AnyObject] { return arr.map(toBool)} else { return [] } })) }
else { return nil }
}
func ~~ <B, C>(t: ([String : Bool] -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Bool](); for (key, val) in jsond { dict[key] = toBool(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~ <B>(t: ([String : Bool] -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Bool](); for (key, val) in jsond { dict[key] = toBool(val) }
return con(dict)
}
else { return nil }
}
func ~~? <B, C>(t: ([String : Bool]? -> B -> C, JSON)?, key: String) -> (B -> C, JSON)? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Bool](); for (key, val) in jsond { dict[key] = toBool(val) }
return (con(dict), json)
}
else { return nil }
}
func ~~? <B>(t: ([String : Bool]? -> B, JSON)?, key: String) -> B? {
if let (con, json) = t, jsond = json[key] as? [String : AnyObject] {
var dict = [String : Bool](); for (key, val) in jsond { dict[key] = toBool(val) }
return con(dict)
}
else { return nil }
}
// Examples
struct User: JSONDecodable {
let id: String
let task: Task?
let friends: [String : User]?
static func create(id: String)(task: Task?)(friends: [String : User]?) -> User {
return User(id: id, task: task, friends: friends)
}
init(id: String, task: Task?, friends: [String : User]?) {
self.id = id; self.task = task; self.friends = friends
}
init?(json: [String : AnyObject]) {
if let u = (User.create, json) ~~ "id" ~~? "task" ~~? "friends" {
self = u
} else {
return nil
}
}
}
struct Task: JSONDecodable {
let done: [String : Bool]
let projects: [String]?
static func create(done: [String : Bool])(projects: [String]?) -> Task {
return Task(done: done, projects: projects)
}
init(done: [String : Bool], projects: [String]?) {
self.done = done; self.projects = projects
}
init?(json: [String : AnyObject]) {
if let t = (Task.create, json) ~~ "done" ~~? "projects" {
self = t
} else {
return nil
}
}
}
let phpArray: [AnyObject] = ["1" as AnyObject, 2 as AnyObject]
let task1JSON: JSON = ["done": ["sub": "yes"], "projects": phpArray, "err": 10]
let user2JSON: [String : AnyObject] = ["id": 2, "task": task1JSON, "friends": [:]]
let user1 = User(json: ["id": "1", "friends": ["2": user2JSON]])
user1?.friends?.values.first?.task // ⇒ {["sub": true], {["1", "2"]}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment