Last active
April 27, 2018 17:18
-
-
Save jayrhynas/6b80a52bfe153f44b3d7781239a0fd4d to your computer and use it in GitHub Desktop.
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 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