Last active
August 29, 2015 14:14
-
-
Save hisui/47f170a9e193168dc946 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
public class UDKey<T> { | |
let key: String | |
let map: BiMap<AnyObject, T> | |
public init(_ key: String, _ map: BiMap<AnyObject, T>) { | |
self.key = key | |
self.map = map | |
} | |
} | |
public class UserDefaults { | |
private let src: NSUserDefaults | |
public init(_ src: NSUserDefaults) { | |
self.src = src | |
} | |
public func get<T>(key: UDKey<T>) -> T? { | |
return src.objectForKey(key.key) >>== { key.map.AtoB($0) } | |
} | |
public func set<T>(key: UDKey<T>, _ value: T?) { | |
if let o = value { | |
src.setObject(key.map.BtoA(o), forKey: key.key) | |
} | |
else { | |
src.removeObjectForKey(key.key) | |
} | |
} | |
} | |
infix operator >>== { associativity left } | |
func >>== <A, B>(ma: A?, f: A -> B?) -> B? { | |
if let a = ma { | |
return f(a) | |
} | |
else { | |
return nil | |
} | |
} | |
func sequence<A>(a: [A?]) -> [A]? { | |
return reduce(a, .Some([])) { acc, e in acc >>== { x in map(e) { x + [$0] } } } | |
} | |
public class ClosureBiMap<A, B>: BiMap<A, B> { | |
let atob: A -> B? | |
let btoa: B -> A? | |
init(atob: A -> B?, btoa: B -> A?) { | |
self.atob = atob | |
self.btoa = btoa | |
} | |
public override func AtoB(a: A) -> B? { return atob(a) } | |
public override func BtoA(b: B) -> A? { return btoa(b) } | |
} | |
public class BiMap<A, B> { | |
public func AtoB(a: A) -> B? { assert(false, "abstract") } | |
public func BtoA(b: B) -> A? { assert(false, "abstract") } | |
public func compose<C>(rhs: BiMap<B, C>) -> BiMap<A, C> { | |
let lhs = self | |
return ClosureBiMap( | |
atob: { lhs.AtoB($0) >>== rhs.AtoB }, | |
btoa: { rhs.BtoA($0) >>== lhs.BtoA }) | |
} | |
} | |
public class Caster<T: AnyObject>: BiMap<AnyObject, T> { | |
override public func AtoB(o: AnyObject) -> T? { | |
return o as? T | |
} | |
override public func BtoA(o: T) -> AnyObject? { | |
return o | |
} | |
} | |
public class array<E>: BiMap<AnyObject, [E]> { | |
private let elem: BiMap<AnyObject, E> | |
public init(_ elem: BiMap<AnyObject, E>) { | |
self.elem = elem | |
} | |
override public func BtoA(a: [E]) -> AnyObject? { | |
return sequence(a.map { self.elem.BtoA($0) }) | |
} | |
override public func AtoB(o: AnyObject) -> [E]? { | |
if let a = o as? [AnyObject] { | |
return sequence(a.map(elem.AtoB)) | |
} | |
return nil | |
} | |
} | |
public class dictionary<K: Hashable, V>: BiMap<AnyObject, [K: V]> { | |
private let keyMap: BiMap<AnyObject, K> | |
private let valMap: BiMap<AnyObject, V> | |
public init(_ keyMap: BiMap<AnyObject, K>, _ valMap: BiMap<AnyObject, V>) { | |
self.keyMap = keyMap | |
self.valMap = valMap | |
} | |
override public func BtoA(value: [K: V]) -> AnyObject? { | |
var out = NSMutableDictionary() | |
for (k, v) in value { | |
if let k2: AnyObject = keyMap.BtoA(k) { | |
if let v2: AnyObject = valMap.BtoA(v) { | |
out.setObject(v2, forKey: k2 as NSCopying) // <(^_^;) | |
continue | |
}} | |
return nil | |
} | |
return out | |
} | |
override public func AtoB(o: AnyObject) -> [K: V]? { | |
if let dic = o as? NSDictionary { | |
var out = [K: V]() | |
for (k, v) in dic { | |
if let k2 = keyMap.AtoB(k) { | |
if let v2 = valMap.AtoB(v) { | |
out[k2] = v2 | |
continue | |
}} | |
return nil | |
} | |
return out | |
} | |
return nil | |
} | |
} | |
public class coding<T: NSCoding>: BiMap<AnyObject, T> { | |
override public func BtoA(value: T) -> AnyObject? { | |
return NSKeyedArchiver.archivedDataWithRootObject(value) | |
} | |
override public func AtoB(o: AnyObject) -> T? { | |
return o as? NSData >>== { NSKeyedUnarchiver.unarchiveObjectWithData($0) as T? } | |
} | |
} | |
public let object = Caster<AnyObject>() | |
public let number = Caster<NSNumber>() | |
public let string = Caster<NSString>() | |
.compose(ClosureBiMap( | |
atob: { $0 as String }, | |
btoa: { $0 as NSString })) | |
public let data = Caster<NSData>() | |
public let date = Caster<NSDate>() | |
public let integer = number | |
.compose(ClosureBiMap( | |
atob: { $0 as? Int }, | |
btoa: { $0 as NSNumber })) | |
public let double = number | |
.compose(ClosureBiMap( | |
atob: { $0 as? Double }, | |
btoa: { $0 as NSNumber })) | |
func optional<B>(map: BiMap<AnyObject, B>) -> BiMap<AnyObject, B?> { | |
return ClosureBiMap( | |
atob: { o in | |
switch (o) { | |
case _ as NSNull: | |
return .Some(nil) | |
default: | |
return map.AtoB(o) | |
} | |
}, | |
btoa: { | |
if let o = $0 { | |
return map.BtoA(o) | |
} | |
else { | |
return NSNull() | |
} | |
}) | |
} | |
func tuple<A, B>(a: BiMap<AnyObject, A>, b: BiMap<AnyObject, B>) -> BiMap<AnyObject, (A, B)> { | |
return array(object).compose(ClosureBiMap( | |
atob: { o in | |
if o.count == 2 { | |
if let a_ = a.AtoB(o[0]) { | |
if let b_ = b.AtoB(o[1]) { | |
return .Some((a_, b_)) | |
}} | |
} | |
return nil | |
}, | |
btoa: { sequence([a.BtoA($0.0), b.BtoA($0.1)]) })) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment