Last active
May 28, 2018 11:49
-
-
Save shawnthroop/f94a1c083454f6b5fd67817e56f16861 to your computer and use it in GitHub Desktop.
Type-erased Equatable and Encodable values
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
// swift 4.1 | |
/// A type-erased encodable value | |
public struct AnyEncodable { | |
public var base: Any { | |
return value.base | |
} | |
private let value: AnyEquatable | |
private let encodeValue: (Encoder, AnyEquatable) throws -> Void | |
init<E>(_ base: E) where E : Encodable & Equatable { | |
self.value = AnyEquatable(base) | |
self.encodeValue = { try AnyEncodable.encode($1, of: E.self, to: $0) } | |
} | |
} | |
extension AnyEncodable: Encodable { | |
public func encode(to encoder: Encoder) throws { | |
try encodeValue(encoder, value) | |
} | |
} | |
extension AnyEncodable: Equatable { | |
public static func == (lhs: AnyEncodable, rhs: AnyEncodable) -> Bool { | |
return lhs.value == rhs.value | |
} | |
} | |
private extension AnyEncodable { | |
static func encode<T: Encodable>(_ value: AnyEquatable, of type: T.Type, to encoder: Encoder) throws { | |
guard let base = value.base as? T else { | |
fatalError("Value of base should always be \(T.self)") | |
} | |
var container = encoder.singleValueContainer() | |
try container.encode(base) | |
} | |
} |
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
// swift 4.1 | |
/// A type-erased equatable value | |
public struct AnyEquatable { | |
public let base: Any | |
private let valuesAreEqual: (AnyEquatable, AnyEquatable) -> Bool | |
public init<E>(_ base: E) where E : Equatable { | |
self.valuesAreEqual = { AnyEquatable.value($0, ofType: E.self, isEqualTo: $1) } | |
self.base = base | |
} | |
} | |
extension AnyEquatable: Equatable { | |
public static func == (lhs: AnyEquatable, rhs: AnyEquatable) -> Bool { | |
return lhs.baseEqual(to: rhs) | |
} | |
} | |
private extension AnyEquatable { | |
/// Assumes value is actually Equatable or throws a fatal error | |
static func value<T: Equatable>(_ value: AnyEquatable, ofType type: T.Type, isEqualTo other: AnyEquatable) -> Bool { | |
guard let lhv = value.base as? T else { | |
fatalError("Value of base will always be \(T.self)") | |
} | |
guard let rhv = other.base as? T else { | |
return false | |
} | |
return lhv == rhv | |
} | |
func baseEqual(to other: AnyEquatable) -> Bool { | |
return valuesAreEqual(self, other) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment