nohash-hasher
A Rust Hasher that skips hashing entirely, turning HashMap and HashSet lookups on integer keys into a direct pass-through.
Repository Health
Technical Analysis
nohash-hasher is a tiny Rust crate providing NoHashHasher<T>, an implementation of std::hash::Hasher that does not hash at all. For types whose Hash impl writes exactly one integer value (u8 through i64/isize, plus any type implementing the IsEnabled marker trait), it simply stores that value and returns it unchanged from finish(). This eliminates the CPU overhead of a general-purpose hashing algorithm for workloads where keys are already well-distributed integers, such as IDs, indices, or interned handles.
The crate exposes IntMap<K, V> and IntSet<T> type aliases that wire HashMap/HashSet up to BuildNoHashHasher<T> out of the box, so adopting it is usually a one-line type swap. In debug builds it also asserts that a hasher instance is never written to more than once, catching accidental misuse (multi-field hashes) that would silently corrupt hash quality in a release build. It supports no_std via a std feature flag, and has no external dependencies.
What You Get
NoHashHasher<T>— astd::hash::Hasherimplementation that stores a single integer write and returns it as-is fromfinish()IntMap<K, V>andIntSet<T>type aliases — drop-inHashMap/HashSetreplacements pre-wired withBuildNoHashHasherBuildNoHashHasher<T>— aBuildHasherDefaultalias for constructing the hasher with standard collection APIs- The
IsEnabledmarker trait to opt custom integer-backed types into the no-hash fast path - Debug-mode safety assertions that panic on a double-write to the same hasher instance, catching misuse before it silently degrades hash quality in release
Common Use Cases
- Using dense numeric IDs, arena indices, or interned symbol handles as
HashMap/HashSetkeys without paying for a general hash function - Building high-throughput graph, arena, or slotmap-style data structures where keys are already unique integers
- Replacing SipHash-based default hashing in hot loops where profiling shows hashing overhead is significant
- Implementing custom newtypes over integers (e.g. wrapped entity IDs) that opt in via
IsEnabledfor no-hash lookups
Under The Hood
Architecture
The entire crate lives in a single src/lib.rs file of under 200 lines of logic. It defines the NoHashHasher<T> struct (a PhantomData-tagged wrapper around a u64, plus an extra bool write-guard field in debug builds), the IsEnabled marker trait blanket-implemented for the ten built-in integer primitive types, and two convenience type aliases (IntMap, IntSet) built on BuildHasherDefault<NoHashHasher<T>>. There are no submodules, no internal abstractions to trace, and no runtime dispatch — the design is intentionally as flat as a single-purpose utility crate can be, trading architectural depth for auditability.
Tech Stack
The crate has zero external dependencies and targets no_std by default, only pulling in std::collections::HashMap/HashSet behind an opt-in std Cargo feature (enabled by default via [features] default = ["std"]). It relies solely on core::hash::{Hasher, BuildHasherDefault} and core::marker::PhantomData from the Rust standard library, with edition 2018 and no build scripts, macros, or codegen involved.
Code Quality
Tests live inline in src/lib.rs under #[cfg(test)] mod tests and cover all ten supported integer types with both a correctness check (write_* then finish() roundtrips the value) and, in debug builds, a #[should_panic] test per type verifying the double-write guard fires. There is no separate integration test suite, no CI config visible in the shallow clone, and no linter configuration beyond a repo-root .editorconfig; the crate’s small surface area limits the practical blast radius of any latent issues. Error handling is deliberately assertion-based (panic!) rather than Result-based, appropriate for a hard misuse-invariant rather than a recoverable runtime condition.
What Makes It Unique
The crate’s core idea — a Hasher that performs no hashing and simply forwards the single integer write — is a well-known micro-optimization pattern in the Rust ecosystem, but nohash-hasher packages it with a genuinely useful safety net: debug-only instrumentation that panics if a type’s Hash impl ever writes more than once, which would otherwise silently collapse hash quality (and correctness) for composite keys in a release build without that check. Combined with no_std support and zero dependencies, it’s a low-risk, easy-to-audit building block rather than a novel algorithmic contribution.