Created
October 2, 2019 08:21
-
-
Save loromits/def360941969ad02b9d15090015e14e1 to your computer and use it in GitHub Desktop.
Dynamic member lookup based simplification to access nested dictionary fields
This file contains 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
@dynamicMemberLookup | |
final class JSONContainer { | |
private typealias Dict = [String: Any] | |
private enum Container { | |
case dict(Dict), value(Any), nothing | |
} | |
private let _container: Container | |
init(_ dict: [String: Any]) { | |
_container = .dict(dict) | |
} | |
init(_ value: Any) { | |
_container = (value as? Dict).map(Container.dict) ?? .value(value) | |
} | |
private init() { | |
_container = .nothing | |
} | |
/// Get either dictionary value by field name, or array value by index | |
subscript(dynamicMember member: String) -> JSONContainer { | |
switch _container { | |
case .dict(let dict): | |
if let value = dict[member] { | |
return JSONContainer(value) | |
} | |
case .value(let arr as [Any]): | |
if let index = Int(member), arr.indices.contains(index) { | |
return JSONContainer(arr[index]) | |
} | |
default: | |
break | |
} | |
return JSONContainer() | |
} | |
/// Cast to type | |
func `as`<T>(_ type: T.Type) -> T? { | |
switch _container { | |
case .value(let value as T), .dict(let value as T): | |
return value | |
default: | |
return nil | |
} | |
} | |
/// Substitute to reciever type | |
func sub<T>() -> T? { | |
return `as`(T.self) | |
} | |
} | |
extension Dictionary where Key: CustomStringConvertible { | |
var json: JSONContainer { | |
return JSONContainer(self) | |
} | |
} |
Author
loromits
commented
Oct 2, 2019
•
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment