pub type NoHash = BuildHasherDefault<NoHasher>;Expand description
§No-Hash (Passthrough) Hash State.
Hashing can be expensive, and is totally unnecessary for most numeric or
pre-hashed types. (You don’t need a hash to tell you that 1_u8 is
different than 2_u8!)
NoHash is a drop in replacement for the standard library’s hasher used in
HashMap and HashSet that lets
the values speak for themselves (e.g. hash(13_u16) == 13_u64), bringing a
free performance boost.
This idea isn’t new, but unlike the hashers offered by nohash or prehash,
NoHash does not limit itself to primitives or require any custom trait
implementations.
It “just works” for any type whose std::hash::Hash implementation writes
a single <= 64-bit integer via one of the following:
write_i8write_i16write_i32write_i64write_isize(if the target pointer width is <= 64)write_u8write_u16write_u32write_u64write_usize(if the target pointer width is <= 64)
In other words, NoHash can always be used for i8, i16, i32, i64,
u8, u16, u32, u64, all their NonZero and Wrapping counterparts,
and any custom types that derive their hashes from one of these types.
(isize and usize will work on most platforms too, just not those with
monstrous 128-bit pointer widths.)
§Examples
use dactyl::NoHash;
use std::collections::{HashMap, HashSet};
let mut set: HashSet<u32, NoHash> = HashSet::default();
assert!(set.insert(0_u32));
assert!(set.insert(1_u32));
assert!(set.insert(2_u32));
assert!(! set.insert(2_u32)); // Not unique!
let mut set: HashMap<i8, &str, NoHash> = HashMap::default();
assert_eq!(set.insert(-2_i8, "Hello"), None);
assert_eq!(set.insert(-1_i8, "World"), None);
assert_eq!(set.insert(0_i8, "How"), None);
assert_eq!(set.insert(1_i8, "Are"), None);
assert_eq!(set.insert(1_i8, "You?"), Some("Are")); // Not unique!This can also be used with custom types that implement Hash in such a
way that only a single specialized write_* call occurs.
use dactyl::NoHash;
use std::{
collections::HashSet,
hash::{Hash, Hasher},
};
struct Person {
name: String,
id: u64,
}
impl Eq for Person {}
impl Hash for Person {
fn hash<H: Hasher>(&self, state: &mut H) {
state.write_u64(self.id);
// Note: `self.id.hash(state)` would also work because it just
// calls `write_u64` under-the-hood.
}
}
impl PartialEq for Person {
fn eq(&self, b: &Self) -> bool { self.id == b.id }
}
let mut set: HashSet<Person, NoHash> = HashSet::default();
assert!(set.insert(Person { name: "Jane".to_owned(), id: 5 }));
assert!(set.insert(Person { name: "Joan".to_owned(), id: 6 }));
assert!(! set.insert(Person { name: "Jack".to_owned(), id: 6 })); // Duplicate ID.§Panics
NoHash does not support slices, i128, or u128 as they cannot be
losslessly converted to u64. If a Hash implementation tries to make use
of those write methods, it will panic. On 128-bit platforms, attempts to hash
isize or usize will likewise result in a panic.
NoHash will also panic if a Hash implementation writes two or more
values to the hasher — as a tuple would, for example — but only for debug
builds. When building in release mode, NoHash will simply pass-through
the last integer written to it, ignoring everything else.
Aliased Type§
struct NoHash(/* private fields */);