Let's say we have a type Foo
that can be created locally or delivered from cloud.
struct Foo: Hashable, Sendable {
public enum ID: Hashable, Sendable {
case local(String)
case cloud(String)
case whole(local: String, cloud: String)
}
let id: ID
}
It holds an id
property that has 3 cases, which represent 2 workflows.
- If it gets created locally first, and synchronized with cloud later, then it will be like:
/// created locally first var fooLocal = Foo(id: .local("aaaa")) /// synchronized with cloud fooLocal = Foo(id: .whole(local: "aaaa", cloud: "bbbb"))
- If it gets created on cloud first, and delivered to device later, then it will be like:
/// parse the payload from the cloud var fooCloud = Foo(id: .cloud("bbbb")) /// finalized on local device fooCloud = Foo(id: .whole(local: "aaaa", cloud: "bbbb"))
In summary, all Foo
s will come with partial ID
and become whole at a later time. So what I want to achieve is, to treat the them equal if they share the same partial ID or the whole ID.
It is easy to implement that logic for the Equtable
protocol of ID
:
public static func == (lhs: Self, rhs: Self) -> Bool {
switch (lhs, rhs) {
case (.cloud, .local):
return false
case (.local, .cloud):
return false
case let (.whole(local: l1, cloud: l2), .whole(local: r1, cloud: r2)):
return l1 == r1 && l2 == r2
case let (.whole(local: l, cloud: _), .local(r)):
return l == r
case let (.whole(local: _, cloud: l), .cloud(r)):
return l == r
case let (.local(l), .local(r)):
return l == r
case let (.local(l), .whole(local: r, cloud: _)):
return l == r
case let (.cloud(l), .cloud(r)):
return l == r
case let (.cloud(l), .whole(local: _, cloud: r)):
return l == r
}
}
But I am not entirely sure how to implement the Hashable
of ID
, so that the hashValue
could be the same if the Foo
instances share the same id
partially or wholly.
Basically, I want this to happen:
var fooIDSet: Set<Foo.ID> = []
let fooIDLocal = Foo.ID.local("aaaa")
let fooIDCloud = Foo.ID.cloud("bbbb")
let fooIDWhole = Foo.ID.whole(local: "aaaa", cloud: "bbbb")
print(fooIDSet.insert(fooIDWhole).inserted) /// <= This prints `true`
print(fooIDSet.insert(fooIDLocal).inserted) /// <= This prints `false`
print(fooIDSet.insert(fooIDCloud).inserted) /// <= This prints `false`
All helps are appreciated!