Last active
November 4, 2016 19:15
-
-
Save aryaxt/339547363e5caae9dcd9ef6b67a55724 to your computer and use it in GitHub Desktop.
Swift auto object serialization
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
public protocol Serializable { | |
func serialize() -> [String: Any] | |
} | |
extension Serializable { | |
public func serialize() -> [String: Any] { | |
return Self.makeSerialized(serializable: self) | |
} | |
public static func makeSerialized(serializable: Self) -> [String: Any] { | |
return serializeSerializable(serializable) | |
} | |
} | |
fileprivate func serializeSerializable(_ serializable: Serializable) -> [String: Any] { | |
var result = [String: Any]() | |
var enumeratingMirror: Mirror? = Mirror(reflecting: serializable) | |
while true { | |
guard let mirror = enumeratingMirror else { break } | |
for child in mirror.children { | |
if let label = child.label, let dictionaryValue = getDictionaryValue(child.value) { | |
result[label] = dictionaryValue | |
} | |
} | |
enumeratingMirror = mirror.superclassMirror | |
} | |
return result | |
} | |
fileprivate func getDictionaryValue(_ any: Any) -> Any? { | |
let unwrappedValue: Any | |
if isOptional(any) { | |
switch any { | |
case let optional as Optional<Any>: | |
if case .some(let insideOptional) = optional { | |
unwrappedValue = insideOptional | |
} | |
else { | |
return nil | |
} | |
} | |
} | |
else { | |
unwrappedValue = any | |
} | |
switch unwrappedValue { | |
case let serializable as Serializable: | |
return serializeSerializable(serializable) | |
case let serializableList as [Serializable]: | |
return serializableList.map { serializeSerializable($0) } | |
case let rawRepresentable as RawRepresentable: | |
return rawRepresentable.getValueAsAny() | |
default: | |
return unwrappedValue | |
} | |
} | |
private func isOptional<T>(_ input: T) -> Bool { | |
let mirror = Mirror(reflecting: input) | |
let style = mirror.displayStyle | |
switch style { | |
case .some(.optional): | |
return true | |
default: | |
return false | |
} | |
} | |
extension Collection where Iterator.Element: Serializable { | |
public func serialize() -> [[String: Any]] { | |
return map { $0.serialize() } | |
} | |
} | |
extension RawRepresentable { | |
public func getValueAsAny() -> Any { | |
return rawValue | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment