hash32/
lib.rs

1//! 32-bit hashing algorithms
2//!
3//! # Why?
4//!
5//! Because 32-bit architectures are a thing (e.g. ARM Cortex-M) and you don't want your hashing
6//! function to pull in a bunch of slow 64-bit compiler intrinsics (software implementations of
7//! 64-bit operations).
8//!
9//! # Relationship to `core::hash`
10//!
11//! This crate extends [`core::hash::Hasher`] with a 32-bit version, [`hash32::Hasher`].
12//!
13//! The [`hash32::Hasher`] trait requires the hasher to perform only 32-bit operations when
14//! computing the hash.
15//! The trait method [`hash32::Hasher::finish32`] returns the hasher's result as a `u32`.
16//! The [`core::hash::Hasher::finish`] method zero-extends the [`hash32::Hasher::finish32`]
17//! result to a `u64`.
18//!
19//! Since [`hash32::Hasher`] extends [`core::hash::Hasher`], the [`hash32::Hasher`] trait can be
20//! used with any type which implements the [`core::hash::Hash`] trait.
21//!
22//! [`hash32::Hasher`]: crate::Hasher
23//! [`hash32::Hasher::finish32`]: crate::Hasher::finish32
24//! [`core::hash`]: https://doc.rust-lang.org/std/hash/index.html
25//! [`finish32`]: crate::Hasher::finish32
26//!
27//! # Hashers
28//!
29//! This crate provides implementations of the following 32-bit hashing algorithms:
30//!
31//! - [`FnvHasher`] Fowler-Noll-Vo 1a
32//! - [`Murmur3Hasher`] `MurmurHash3`
33//!
34//! ## Picking a hasher
35//!
36//! - [`FnvHasher`] is faster and consumes less code space than [`Murmur3Hasher`].
37//! - [`Murmur3Hasher`] offers better collision resistance than [`FnvHasher`].
38//!
39//! ## Security
40//!
41//! Hashers provided by this crate are not cryptographically secure, and must **not** be used
42//! for security purposes.
43//! Additionally, unlike [`std::hash::DefaultHasher`] the provided hash algorithms lack
44//! denial-of-service protection, and must only be used with trusted data.
45//!
46//! # Generic code
47//!
48//! In generic code, the trait bound `H: core::hash::Hasher` accepts **both** 64-bit hashers such
49//! as [`std::hash::DefaultHasher`]; and 32-bit hashers such as the ones defined in this crate,
50//! [`FnvHasher`], and [`Murmur3Hasher`].
51//!
52//! The trait bound `H: hash32::Hasher` is **more** restrictive as it only accepts 32-bit hashers.
53//!
54//! [`std::hash::DefaultHasher`]: https://doc.rust-lang.org/std/hash/struct.DefaultHasher.html
55//!
56//! # MSRV
57//!
58//! This crate is guaranteed to compile on latest stable Rust. It *might* compile on older
59//! versions but that may change in any new patch release.
60//!
61//! # Examples
62//!
63//! ```
64//! use hash32::{FnvHasher, Hasher as _};
65//!
66//! #[derive(Hash)]
67//! struct Person {
68//!     id: u32,
69//!     name: &'static str,
70//!     phone: u64,
71//! }
72//!
73//! let person1 = Person {
74//!     id: 5,
75//!     name: "Janet",
76//!     phone: 555_666_7777,
77//! };
78//! let person2 = Person {
79//!     id: 5,
80//!     name: "Bob",
81//!     phone: 555_666_7777,
82//! };
83//!
84//! assert!(calculate_hash(&person1) != calculate_hash(&person2));
85//!
86//! fn calculate_hash<T: core::hash::Hash>(t: &T) -> u32 {
87//!     let mut fnv: FnvHasher = Default::default();
88//!     t.hash(&mut fnv);
89//!     fnv.finish32()
90//! }
91//! ```
92
93#![warn(
94    missing_docs,
95    clippy::use_self,
96    clippy::doc_markdown,
97    clippy::ptr_as_ptr,
98    clippy::trivially_copy_pass_by_ref
99)]
100#![no_std]
101
102pub use crate::fnv::FnvHasher;
103pub use crate::murmur3::Murmur3Hasher;
104
105mod fnv;
106mod murmur3;
107
108/// An extension of [`core::hash::Hasher`] for 32-bit hashers.
109///
110/// For hashers that implement this trait, the [`core::hash::Hasher::finish`] method should return a
111/// zero-extended version of the result from [`Hasher::finish32`].
112///
113/// # Contract
114///
115/// Implementers of this trait must **not** perform any 64-bit (or 128-bit) operation while computing
116/// the hash.
117///
118/// # Examples
119///
120/// ```
121/// use core::hash::Hasher as _;
122/// use hash32::{FnvHasher, Hasher as _};
123///
124/// let mut hasher: FnvHasher = Default::default();
125///
126/// hasher.write_u32(1989);
127/// hasher.write_u8(11);
128/// hasher.write_u8(9);
129/// hasher.write(b"Huh?");
130///
131/// println!("Hash is {:x}!", hasher.finish32());
132/// ```
133pub trait Hasher: core::hash::Hasher {
134    /// The equivalent of [`core::hash::Hasher::finish`] for 32-bit hashers.
135    ///
136    /// This returns the hash directly; [`core::hash::Hasher::finish`] zero-extends the `finish32`
137    /// result to 64-bits for compatibility.
138    fn finish32(&self) -> u32;
139}