I can go one step further and generalize this into a Union
enum. Right now I would have as much boilerplate as this:
enum Union<A> {
case _0(A)
struct Payload {
let _0: A?
}
var payload: Payload {
switch self {
case ._0(let payload):
return Payload(_0: payload)
}
}
}
extension Union: Equatable where A: Equatable {}
extension Union: Hashable where A: Hashable {}
enum Union2<A, B> {
case _0(A)
case _1(B)
struct Payload {
let _0: A?
let _1: B?
}
var payload: Payload {
switch self {
case ._0(let payload):
return Payload(_0: payload, _1: .none)
case ._1(let payload):
return Payload(_0: .none, _1: payload)
}
}
}
extension Union2: Equatable where A: Equatable, B: Equatable {}
extension Union2: Hashable where A: Hashable, B: Hashable {}
enum Union3<A, B, C> {
case _0(A)
case _1(B)
case _2(C)
struct Payload {
let _0: A?
let _1: B?
let _2: C?
}
var payload: Payload {
switch self {
case ._0(let payload):
return Payload(_0: payload, _1: .none, _2: .none)
case ._1(let payload):
return Payload(_0: .none, _1: payload, _2: .none)
case ._2(let payload):
return Payload(_0: .none, _1: .none, _2: payload)
}
}
}
extension Union3: Equatable where A: Equatable, B: Equatable, C: Equatable {}
extension Union3: Hashable where A: Hashable, B: Hashable, C: Hashable {}
enum Union4<A, B, C, D> {
case _0(A)
case _1(B)
case _2(C)
case _3(D)
struct Payload {
let _0: A?
let _1: B?
let _2: C?
let _3: D?
}
var payload: Payload {
switch self {
case ._0(let payload):
return Payload(_0: payload, _1: .none, _2: .none, _3: .none)
case ._1(let payload):
return Payload(_0: .none, _1: payload, _2: .none, _3: .none)
case ._2(let payload):
return Payload(_0: .none, _1: .none, _2: payload, _3: .none)
case ._3(let payload):
return Payload(_0: .none, _1: .none, _2: .none, _3: payload)
}
}
}
extension Union4: Equatable
where A: Equatable, B: Equatable, C: Equatable, D: Equatable {}
extension Union4: Hashable
where A: Hashable, B: Hashable, C: Hashable, D: Hashable {}
// Types for my use-case
typealias PartialDriverKeyPathSetUnion<A> = Union<
PartialKeyPathSet<A.Driver>
> where A: Drivable
typealias PartialDriverKeyPathSetUnion2<A, B> = Union2<
PartialKeyPathSet<A.Driver>,
PartialKeyPathSet<B.Driver>
> where A: Drivable, B: Drivable
typealias PartialDriverKeyPathSetUnion3<A, B, C> = Union3<
PartialKeyPathSet<A.Driver>,
PartialKeyPathSet<B.Driver>,
PartialKeyPathSet<C.Driver>
> where A: Drivable, B: Drivable, C: Drivable
typealias PartialDriverKeyPathSetUnion4<A, B, C, D> = Union4<
PartialKeyPathSet<A.Driver>,
PartialKeyPathSet<B.Driver>,
PartialKeyPathSet<C.Driver>,
PartialKeyPathSet<D.Driver>
> where A: Drivable, B: Drivable, C: Drivable, D: Drivable
As you can see we would also need variadic generic typealiases to wrap custom constraints around a variadic type such as Union
.
enum Union<T...> {
case $T...(T)
var payload: (T?...) {
...
}
}
extension Union: Equatable where T...: Equatable {}
extension Union: Hashable where T...: Hashable {}
typealias PartialDriverKeyPathSetUnion<T...> = Union<
PartialKeyPathSet<T.Driver>...
> where T...: Drivable