Skip to content

Instantly share code, notes, and snippets.

@jayrhynas
Last active April 27, 2018 17:18
Show Gist options
  • Save jayrhynas/6b80a52bfe153f44b3d7781239a0fd4d to your computer and use it in GitHub Desktop.
Save jayrhynas/6b80a52bfe153f44b3d7781239a0fd4d to your computer and use it in GitHub Desktop.
protocol StaticDecodable {
static func decode(from decoder: Decoder) throws -> Self
}
// MARK: - Container Extensions
extension KeyedDecodingContainer {
func decode<T>(_ type: T.Type, forKey key: K) throws -> T where T: StaticDecodable {
return try T.decode(from: try self.superDecoder(forKey: key))
}
func decodeIfPresent<T>(_ type: T.Type, forKey key: K) throws -> T? where T : StaticDecodable {
let decoder: Decoder
do {
decoder = try self.superDecoder(forKey: key)
} catch let error as DecodingError {
switch error {
case .keyNotFound(_, _), .valueNotFound(_, _):
return nil
default:
throw error
}
}
return try T.decode(from: decoder)
}
}
extension UnkeyedDecodingContainer {
mutating func decode<T>(_ type: T.Type) throws -> T where T: StaticDecodable {
return try T.decode(from: try self.superDecoder())
}
mutating func decodeIfPresent<T>(_ type: T.Type) throws -> T? where T : StaticDecodable {
let decoder: Decoder
do {
decoder = try self.superDecoder()
} catch DecodingError.valueNotFound(_, _) {
return nil
}
return try T.decode(from: decoder)
}
}
extension SingleValueDecodingContainer {
func decode<T>(_ type: T.Type) throws -> T where T: StaticDecodable {
// relies on implementation detail that container is just the Decoder
guard let decoder = self as? Decoder else {
throw DecodingError.dataCorruptedError(
in: self,
debugDescription: "SingleValueDecodingContainer is not a Decoder"
)
}
return try T.decode(from: decoder)
}
}
// MARK: - Specific Decoder Extensions
#if canImport(Foundation)
import Foundation
fileprivate struct StaticDecodableWrapper<T>: Decodable where T: StaticDecodable {
var value: T
init(from decoder: Decoder) throws {
value = try T.decode(from: decoder)
}
}
extension JSONDecoder {
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: StaticDecodable {
let wrapper = try self.decode(StaticDecodableWrapper<T>.self, from: data)
return wrapper.value
}
}
extension PropertyListDecoder {
func decode<T>(_ type: T.Type, from data: Data) throws -> T where T: StaticDecodable {
let wrapper = try self.decode(StaticDecodableWrapper<T>.self, from: data)
return wrapper.value
}
func decode<T>(_ type: T.Type, from data: Data, format: inout PropertyListSerialization.PropertyListFormat) throws -> T where T: StaticDecodable {
let wrapper = try self.decode(StaticDecodableWrapper<T>.self, from: data, format: &format)
return wrapper.value
}
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment