Skip to content

Instantly share code, notes, and snippets.

@dreymonde
Last active August 3, 2016 08:53
Show Gist options
  • Save dreymonde/46e471fc51f7a232cf72986a24024172 to your computer and use it in GitHub Desktop.
Save dreymonde/46e471fc51f7a232cf72986a24024172 to your computer and use it in GitHub Desktop.
Next generation of Mapper
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