Skip to content

Instantly share code, notes, and snippets.

@owenv
Last active June 19, 2019 03:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save owenv/c8c8816d37b089e05e731f5fecb61da1 to your computer and use it in GitHub Desktop.
Save owenv/c8c8816d37b089e05e731f5fecb61da1 to your computer and use it in GitHub Desktop.
protocol Equatable2 {
//@memberwiseDerivable(mapper: equatable2Mapper, reducer: equatable2Reducer, reduceInitialResult: true)
static func == (_: Self, _: Self) -> Bool
}
// lhs and rhs come from the derived requirement, memberKeyPath is added to the argument list
// the return type must match the reducer's argument types
// Self is replaced by generic parameter T, U is the type of the member (which conforms to the given protocol)
func equatable2Mapper<T, U: Equatable2>(_ lhs: T, _ rhs: T, memberKeyPath: KeyPath<T, U>) -> Bool {
return lhs[keyPath: memberKeyPath] == rhs[keyPath: memberKeyPath]
}
// the argument types must match the return type of the mapper
// the return type must match the return type of the derived requirement
func equatable2Reducer(_ first: Bool, _ second: Bool) -> Bool {
return first && second
}
// Dummy manually conforming type
struct A: Equatable2 {
static func == (lhs: A, rhs: A) -> Bool {
return true
}
}
// Dummy manually conforming type
struct B: Equatable2 {
static func == (lhs: B, rhs: B) -> Bool {
return true
}
}
// Example memberwise conforming type
struct Compound: Equatable2 {
let a: A = A()
let a2: A = A()
let b: B = B()
// Compiler Synthesized
static func == (lhs: Compound, rhs: Compound) -> Bool {
return equatable2Reducer(equatable2Reducer(equatable2Reducer(true /* reduceInitialResult expression from attribute */,
equatable2Mapper(lhs, rhs, memberKeyPath: \Compound.a)),
equatable2Mapper(lhs, rhs, memberKeyPath: \Compound.a2)),
equatable2Mapper(lhs, rhs, memberKeyPath: \Compound.b))
}
}
print(Compound() == Compound())
protocol Hashable2 {
//@memberwiseDerivable(mapper: hashable2Mapper, reducer: hashable2Reducer, reduceInitialResult: ()))
func hash(into: inout Hasher)
}
// self parameter is added with generic type T, into: argument is from derived requirement, memberKeyPath is added
func hashable2Mapper<T, U: Hashable2>(`self`: T, into hasher: inout Hasher, memberKeyPath: KeyPath<T, U>) -> Void {
`self`[keyPath: memberKeyPath].hash(into: &hasher)
}
// Reducer doesn't need to do anything in this case, the mapper takes care of everything
func hashable2Reducer(_ first: Void, _ second: Void) -> Void {
return
}
// Dummy manual conformance
extension A: Hashable2 {
func hash(into: inout Hasher) {
return
}
}
// Dummy manual conformance
extension B: Hashable2 {
func hash(into: inout Hasher) {
return
}
}
// Example memberwise conformance
extension Compound: Hashable2 {
// Compiler Synthesized
func hash(into hasher: inout Hasher) {
return hashable2Reducer(hashable2Reducer(hashable2Reducer(() /* reduceInitialResult expression from attribute */ ,
hashable2Mapper(self: self, into: &hasher, memberKeyPath: \Compound.a)),
hashable2Mapper(self: self, into: &hasher, memberKeyPath: \Compound.a2)),
hashable2Mapper(self: self, into: &hasher, memberKeyPath: \Compound.b))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment