Expand description
§HashWith
HashWith
is a procedural macro for deriving Hash
on structs that contain
fields which do not implement Hash
by default (like f64
).
It supports custom hash functions per field.
§Inline Example
The #[hash_with(expr)]
notation takes in some expression and so long as the result is a type that
implements Hash
. For example if you wanted to serialize a f64
in your struct you can use
the following snippet.
use hash_with::HashWith;
/// Some struct which needs to implement [`Hash`]
#[derive(HashWith)]
struct Brightness {
/// The inner value with a hash function override.
/// The `f64::to_bits()` method returns a `u64` which is why it can be used here.
#[hash_with(self.inner.to_bits())]
inner: f64,
}
// Sets values
let b1 = Brightness { inner: 1.1 };
let b2 = Brightness { inner: 2.2 };
// Not equal in terms of their hash
assert_ne!(b1.get_hash(), b2.get_hash());
§Function Call Example
With HashWith
you can also call functions by name for the Hash
implementation. This can
be useful for repeatedly creating a Hash
implementation for multiple of the same datatype
in a struct.
The function must however have the signature Fn<T, H: std::hash::Hasher>(T, &mut H) -> ()
.
Basically what this means is the function must look something like the following example.
/// A custom hash function for f64
fn hash_f64_bits<H: std::hash::Hasher>(val: &f64, state: &mut H) {
val.to_bits().hash(state);
}
/// An example struct.
#[derive(HashWith)]
struct Config {
name: String,
/// A brightness value which is hashed with [`hash_f64_bits`].
#[hash_with = "hash_f64_bits"]
brightness: f64,
}
§Ignoring Fields in Hash Calculation Example
The #[hash_without]
attribute can be applied to struct fields to exclude them
from the generated hash. This is useful for fields that should not affect equality
in hashed collections or when you want to ignore volatile or irrelevant data.
#[derive(HashWith)]
struct User {
id: u32,
/// This field will be ignored in the hash calculation.
#[hash_without]
session_token: String,
}
let user_1 = User { id: 1, session_token: "abc".into() };
let user_2 = User { id: 1, session_token: "xyz".into() };
// The hash ignores `session_token`, so these are equal in terms of hash.
assert_eq!(user_1.get_hash(), user_2.get_hash());