HashableByKeyPath


HashableByKeyPath
helps avoid common mistakes when implementing Hashable
and Equatable
conformance:
struct Foo: HashableKeyPathProvider {
@HashableKeyPathCollectionBuilder<TestObject>
static var hashableKeyPaths: HashableKeyPathCollection<Foo> {
\Foo.bar1
\Foo.bar2
\Foo.bar3
}
var bar1: String
var bar2: String
var bar3: Int
}
let foo1 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo2 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo3 = Foo(bar: "value2", bar2: "value2", bar3: "value3")
let foos: Set = [foo1, foo2]
foo1 == foo1 // true
foo1 == foo2 // true
foo1 == foo3 // false
foo2 == foo3 // false
foos.count // 1
foos.contains(foo2) // true
foos.contains(foo3) // false
If the type only needs to conform to Equatable
the type can conform to EquatableByKeyPath
:
struct Foo: EquatableKeyPathProvider {
@EquatableKeyPathCollectionBuilder<TestObject>
static var equatableKeyPaths: EquatableKeyPathCollection<Foo> {
\Foo.bar1
\Foo.bar2
\Foo.bar3
}
var bar1: String
var bar2: String
var bar3: Int
}
let foo1 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo2 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo3 = Foo(bar: "value2", bar2: "value2", bar3: "value3")
foo1 == foo1 // true
foo1 == foo2 // true
foo1 == foo3 // false
foo2 == foo3 // false
When using a non-final class the HashableKeyPathProvider
and EquatableKeyPathProvider
protocols cannot be used. In this case the HashableByKeyPath
and EquatableByKeyPath
protocols should be used:
struct Foo: HashableByKeyPath {
static func addHashableKeyPaths<Consumer: HashableKeyPathConsumer>(to consumer: inout Consumer) where Consumer.Root == Self {
consumer.addHashableKeyPath(\.bar1)
consumer.addHashableKeyPath(\.bar2)
consumer.addHashableKeyPath(\.bar3)
}
var bar1: String
var bar2: String
var bar3: Int
}
let foo1 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo2 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo3 = Foo(bar: "value2", bar2: "value2", bar3: "value3")
let foos: Set = [foo1, foo2]
foo1 == foo1 // true
foo1 == foo2 // true
foo1 == foo3 // false
foo2 == foo3 // false
foos.count // 1
foos.contains(foo2) // true
foos.contains(foo3) // false
If the type only needs to conform to Equatable
the type can conform to EquatableByKeyPath
:
struct Foo: EquatableByKeyPath {
static func addHashableKeyPaths<Consumer: HashableKeyPathConsumer>(to consumer: inout Consumer) where Consumer.Root == Self {
consumer.addEquatableKeyPath(\.bar1)
consumer.addEquatableKeyPath(\.bar2)
consumer.addEquatableKeyPath(\.bar3)
}
var bar1: String
var bar2: String
var bar3: Int
}
let foo1 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo2 = Foo(bar: "value", bar2: "value2", bar3: "value3")
let foo3 = Foo(bar: "value2", bar2: "value2", bar3: "value3")
foo1 == foo1 // true
foo1 == foo2 // true
foo1 == foo3 // false
foo2 == foo3 // false
Installation
HashableByKeyPath
supports installation via SwiftPM. This can be done by adding the package to the dependencies section and as the dependency of a target:
let package = Package(
...
dependencies: [
.package(url: "https://github.com/JosephDuffy/HashableByKeyPath.git", from: "1.0.0"),
],
targets: [
.target(name: "MyApp", dependencies: ["HashableByKeyPath"]),
],
...
)
Documentation
HashableByKeyPath
is fully documented, with code-level documentation available online. The online documentation is generated from the source code with every release, so it is up-to-date with the latest release, but may be different to the code in master
.
Tests and CI
HashableByKeyPath
has a full test suite, which is run on GitHub actions as part of pull requests. All tests must pass for a pull request to be merged.
Code coverage is collected and reported to to Codecov.
License
The project is released under the MIT license. View the LICENSE file for the full license.
HashableByKeyPath
HashableByKeyPath
helps avoid common mistakes when implementingHashable
andEquatable
conformance:lhs.foo == lhs.foo
lhs.foo1 == rhs.foo2
==
andhash(into:)
functions; “Two instances that are equal must feed the same values toHasher
inhash(into:)
, in the same order“If the type only needs to conform to
Equatable
the type can conform toEquatableByKeyPath
:When using a non-final class the
HashableKeyPathProvider
andEquatableKeyPathProvider
protocols cannot be used. In this case theHashableByKeyPath
andEquatableByKeyPath
protocols should be used:If the type only needs to conform to
Equatable
the type can conform toEquatableByKeyPath
:Installation
HashableByKeyPath
supports installation via SwiftPM. This can be done by adding the package to the dependencies section and as the dependency of a target:Documentation
HashableByKeyPath
is fully documented, with code-level documentation available online. The online documentation is generated from the source code with every release, so it is up-to-date with the latest release, but may be different to the code inmaster
.Tests and CI
HashableByKeyPath
has a full test suite, which is run on GitHub actions as part of pull requests. All tests must pass for a pull request to be merged.Code coverage is collected and reported to to Codecov.
License
The project is released under the MIT license. View the LICENSE file for the full license.