 /// Represents objects that can type-safely be interacted with DefaultStoreType
 public protocol DefaultConvertible {
     
+    static var key: String { get }
+    
     /// Desirialize AnyObject to adopted object.
     /// The argument "object" is intended to be passed from DefaultStoreType
     init?(_ object: AnyObject)

// MARK: -

public final class AnyStore<D: DefaultConvertible>: DefaultStoreType {
    public typealias Default = D
    
    public let key: String
    
    private let _set: Default -> ()
    private let _get: () -> Default?
    private let _remove: () -> ()
    
    public init<Inner: DefaultStoreType where Inner.Default == D>(_ inner: Inner) {
        self.key = inner.key
        
        _set = inner.set
        _get = inner.get
        _remove = inner.remove

// MARK: -

public final class DefaultsStore<Default: DefaultConvertible>: DefaultStoreType {
    
    private let defaults = NSUserDefaults.standardUserDefaults()
    
    public func set(value: Default) {
        let obj = value.serialize()
        defaults.setObject(obj, forKey: Default.key)
    }
    
    public func get() -> Default? {
        guard let obj = defaults.objectForKey(Default.key) else { return nil }
        return Default(obj)
    }
    
    public func remove() {
        defaults.removeObjectForKey(Default.key)
    }
}

// MARK: -

public final class DictionaryStore<Default: DefaultConvertible>: DefaultStoreType {
    
    private var dictionary: [String: AnyObject] = [:]
    
    public func set(value: Default) {
        let obj = value.serialize()
        dictionary[Default.key] = obj
    }
    
    public func get() -> Default? {
        guard let obj = dictionary[Default.key] else { return nil }
        return Default(obj)
    }
    
    public func remove() {
        dictionary[Default.key] = nil
    }
}
