Last active
August 3, 2016 08:53
-
-
Save dreymonde/46e471fc51f7a232cf72986a24024172 to your computer and use it in GitHub Desktop.
Next generation of Mapper
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
protocol MapperProtocol { | |
associatedtype Key | |
func map<T>(from key: Key) throws -> T | |
func map<T>(arrayFrom key: Key) throws -> [T] | |
} | |
protocol Mappable { | |
init<Mapper: MapperProtocol where Mapper.Key == String>(mapper: Mapper) throws | |
} | |
enum ThatThingOne { | |
case number(Int) | |
case string(String) | |
case array([ThatThingOne]) | |
case dict([String: ThatThingOne]) | |
} | |
struct TTOMapper: MapperProtocol { | |
let thing: ThatThingOne | |
func map<T>(from key: String) throws -> T { | |
if let MappableT = T.self as? Mappable.Type { | |
print("Mappable") | |
guard case let .dict(dict) = thing, let item = dict[key] else { | |
throw Error.notTopLevel | |
} | |
return try MappableT.init(mapper: TTOMapper(thing: item)) as! T | |
} | |
guard case let .dict(dict) = thing else { | |
throw Error.notTopLevel | |
} | |
guard let item = dict[key] else { | |
throw Error.emptyKey | |
} | |
switch item { | |
case .number(let value as T): return value | |
case .string(let value as T): return value | |
case .array(let value as T): return value | |
case .dict(let value as T): return value | |
default: | |
throw Error.wrongType | |
} | |
} | |
func map<T>(arrayFrom key: String) throws -> [T] { | |
return [] | |
} | |
enum Error: ErrorProtocol { | |
case wrongType | |
case notTopLevel | |
case emptyKey | |
} | |
} | |
struct StringAnyMapper: MapperProtocol { | |
private let instance: [String: Any] | |
func map<T>(from key: String) throws -> T { | |
if let MappableT = T.self as? Mappable.Type { | |
print("Mappable SA") | |
guard let node = instance[key] as? [String: Any] else { | |
throw Error.nilNode | |
} | |
return try MappableT.init(mapper: StringAnyMapper(instance: node)) as! T | |
} | |
if let value = instance[key] as? T { | |
return value | |
} else { | |
throw Error.wrongType | |
} | |
} | |
func map<T>(arrayFrom key: String) throws -> [T] { | |
return [] | |
} | |
enum Error: ErrorProtocol { | |
case nilNode | |
case wrongType | |
} | |
} | |
struct YouKnow { | |
let string: String | |
let int: Int | |
} | |
extension YouKnow: Mappable { | |
init<Mapper : MapperProtocol where Mapper.Key == String>(mapper: Mapper) throws { | |
self.string = try mapper.map(from: "string") | |
self.int = try mapper.map(from: "int") | |
} | |
} | |
struct What { | |
let youKnow: YouKnow | |
} | |
extension What: Mappable { | |
init<Mapper : MapperProtocol where Mapper.Key == String>(mapper: Mapper) throws { | |
self.youKnow = try mapper.map(from: "you_know") | |
} | |
} | |
let basicThing = ThatThingOne.dict(["string": .string("Ala"), "int": .number(5)]) | |
let moreComplicated = ThatThingOne.dict(["you_know": basicThing]) | |
let complicatedMapper = TTOMapper(thing: moreComplicated) | |
let whatTO = try What(mapper: complicatedMapper) | |
print(whatTO) | |
// What(youKnow: YouKnow(string: "Ala", int: 5)) | |
let low: [String: Any] = ["string": "Shavua", "int": 5] | |
let stringAny: [String: Any] = ["you_know": low] | |
let stringAnyMapper = StringAnyMapper(instance: stringAny) | |
let whatSA = try What(mapper: stringAnyMapper) | |
print(whatSA) | |
// What(youKnow: YouKnow(string: "Shavua", int: 5)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment