blob: 700f5d1efb39d5797c591146897775d451d24101 [file] [log] [blame]
//! 32-bit hashing machinery
//!
//! # Why?
//!
//! Because 32-bit architectures are a thing (e.g. ARM Cortex-M) and you don't want your hashing
//! function to pull in a bunch of slow 64-bit compiler intrinsics (software implementations of
//! 64-bit operations).
//!
//! # Relationship to `core::hash`
//!
//! This crate exposes the same interfaces you'll find in [`core::hash`]: `Hash`, `Hasher`,
//! `BuildHasher` and `BuildHasherDefault`. The main difference is that `hash32::Hasher::finish`
//! returns a `u32` instead of `u64`, and the contract of `hash32::Hasher` forbids the implementer
//! from performing 64-bit (or 128-bit) operations while computing the hash.
//!
//! [`core::hash`]: https://doc.rust-lang.org/std/hash/index.html
//!
//! # `#[derive(Hash32)]`
//!
//! The easiest way to implement `hash32::Hash` for a `struct` is to use the `#[derive(Hash32)]`.
//!
//! Note that you need to *explicitly* depend on both `hash32` *and* `hash32_derive`; both crates
//! must appear in your `Cargo.toml`.
//!
//! ``` ignore
//! use hash32_derive::Hash32;
//!
//! #[derive(Hash32)]
//! struct Ipv4Addr([u8; 4]);
//!
//! # fn main() {}
//!
//! ```
//! # Hashers
//!
//! This crate provides implementations of the following 32-bit hashing algorithms:
//!
//! - [Fowler-Noll-Vo](struct.FnvHasher.html)
//! - [MurmurHash3](struct.Murmur3Hasher.html)
//!
//! # MSRV
//!
//! This crate is guaranteed to compile on latest stable Rust. It *might* compile on older
//! versions but that may change in any new patch release.
//!
//! # Future
//!
//! In the future we'd like to deprecate this crate in favor of making `core::hash::Hasher` generic
//! over the size of the computed hash. Below is shown the planned change (but it doesn't work due
//! to limitations in the `associated_type_defaults` feature):
//!
//! ``` ignore
//! #![feature(associated_type_defaults)]
//!
//! trait Hasher {
//! type Hash = u64; // default type for backwards compatibility
//!
//! fn finish(&self) -> Self::Hash; // changed
//! fn write(&mut self, bytes: &[u8]);
//! }
//! ```
//!
//! With this change a single `#[derive(Hash)]` would enough to make a type hashable with 32-bit and
//! 64-bit hashers.
#![deny(missing_docs)]
#![deny(warnings)]
#![no_std]
extern crate byteorder;
use core::marker::PhantomData;
use core::{mem, slice, fmt};
pub use fnv::Hasher as FnvHasher;
pub use murmur3::Hasher as Murmur3Hasher;
mod fnv;
mod murmur3;
/// See [`core::hash::BuildHasherDefault`][0] for details
///
/// [0]: https://doc.rust-lang.org/core/hash/struct.BuildHasherDefault.html
pub struct BuildHasherDefault<H>
{
_marker: PhantomData<H>,
}
impl<H> Default for BuildHasherDefault<H>
where
H: Default + Hasher,
{
fn default() -> Self {
BuildHasherDefault {
_marker: PhantomData,
}
}
}
impl<H> Clone for BuildHasherDefault<H>
where
H: Default + Hasher,
{
fn clone(&self) -> Self {
BuildHasherDefault::default()
}
}
impl<H> PartialEq for BuildHasherDefault<H>
where
H: Default + Hasher,
{
fn eq(&self, _other: &BuildHasherDefault<H>) -> bool {
true
}
}
impl<H: Default + Hasher> Eq for BuildHasherDefault<H> {}
impl<H: Default + Hasher> fmt::Debug for BuildHasherDefault<H> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.pad("BuildHasherDefault")
}
}
impl<H> BuildHasherDefault<H>
{
/// `const` constructor
pub const fn new() -> Self {
BuildHasherDefault {
_marker: PhantomData,
}
}
}
impl<H> BuildHasher for BuildHasherDefault<H>
where
H: Default + Hasher,
{
type Hasher = H;
fn build_hasher(&self) -> Self::Hasher {
H::default()
}
}
/// See [`core::hash::BuildHasher`][0] for details
///
/// [0]: https://doc.rust-lang.org/core/hash/trait.BuildHasher.html
pub trait BuildHasher {
/// See [`core::hash::BuildHasher::Hasher`][0]
///
/// [0]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#associatedtype.Hasher
type Hasher: Hasher;
/// See [`core::hash::BuildHasher.build_hasher`][0]
///
/// [0]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#tymethod.build_hasher
fn build_hasher(&self) -> Self::Hasher;
}
/// See [`core::hash::Hasher`][0] for details
///
/// [0]: https://doc.rust-lang.org/core/hash/trait.Hasher.html
///
/// # Contract
///
/// Implementers of this trait must *not* perform any 64-bit (or 128-bit) operation while computing
/// the hash.
pub trait Hasher {
/// See [`core::hash::Hasher.finish`][0]
///
/// [0]: https://doc.rust-lang.org/std/hash/trait.Hasher.html#tymethod.finish
fn finish(&self) -> u32;
/// See [`core::hash::Hasher.write`][0]
///
/// [0]: https://doc.rust-lang.org/std/hash/trait.Hasher.html#tymethod.write
fn write(&mut self, bytes: &[u8]);
}
/// See [`core::hash::Hash`][0] for details
///
/// [0]: https://doc.rust-lang.org/core/hash/trait.Hash.html
pub trait Hash {
/// Feeds this value into the given `Hasher`.
fn hash<H>(&self, state: &mut H)
where
H: Hasher;
/// Feeds a slice of this type into the given `Hasher`.
fn hash_slice<H>(data: &[Self], state: &mut H)
where
H: Hasher,
Self: Sized,
{
for piece in data {
piece.hash(state);
}
}
}
macro_rules! int {
($ty:ident) => {
impl Hash for $ty {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
unsafe { state.write(&mem::transmute::<$ty, [u8; mem::size_of::<$ty>()]>(*self)) }
}
fn hash_slice<H>(data: &[Self], state: &mut H)
where
H: Hasher,
{
let newlen = data.len() * mem::size_of::<$ty>();
let ptr = data.as_ptr() as *const u8;
unsafe { state.write(slice::from_raw_parts(ptr, newlen)) }
}
}
};
}
int!(i16);
int!(i32);
int!(i64);
int!(i8);
int!(isize);
int!(u16);
int!(u32);
int!(u64);
int!(u8);
int!(usize);
impl Hash for bool {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(*self as u8).hash(state)
}
}
impl Hash for char {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
(*self as u32).hash(state)
}
}
impl Hash for str {
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
state.write(self.as_bytes());
state.write(&[0xff]);
}
}
impl<T> Hash for [T]
where
T: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
self.len().hash(state);
T::hash_slice(self, state);
}
}
macro_rules! array {
($($n:expr),+) => {
$(
impl<T> Hash for [T; $n]
where
T: Hash,
{
fn hash<H>(&self, state: &mut H)
where
H: Hasher,
{
Hash::hash(&self[..], state)
}
}
)+
};
}
array!(
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 32
);
impl<'a, T: ?Sized + Hash> Hash for &'a T {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl<'a, T: ?Sized + Hash> Hash for &'a mut T {
fn hash<H: Hasher>(&self, state: &mut H) {
(**self).hash(state);
}
}
impl Hash for () {
fn hash<H: Hasher>(&self, _state: &mut H) {}
}
macro_rules! tuple {
( $($name:ident)+) => (
impl<$($name: Hash),*> Hash for ($($name,)*)
where
last_type!($($name,)+): ?Sized
{
#[allow(non_snake_case)]
fn hash<S: Hasher>(&self, state: &mut S) {
let ($(ref $name,)*) = *self;
$($name.hash(state);)*
}
}
);
}
macro_rules! last_type {
($a:ident,) => { $a };
($a:ident, $($rest_a:ident,)+) => { last_type!($($rest_a,)+) };
}
tuple! { A }
tuple! { A B }
tuple! { A B C }
tuple! { A B C D }
tuple! { A B C D E }
tuple! { A B C D E F }
tuple! { A B C D E F G }
tuple! { A B C D E F G H }
tuple! { A B C D E F G H I }
tuple! { A B C D E F G H I J }
tuple! { A B C D E F G H I J K }
tuple! { A B C D E F G H I J K L }
#[cfg(test)]
mod test {
use super::{FnvHasher, Hash, Hasher};
#[test]
fn hashes_tuples() {
let mut h = FnvHasher::default();
().hash(&mut h);
(1_usize,).hash(&mut h);
(1_u8, 2_i8).hash(&mut h);
(1_u16, 2_i16, 3_u32).hash(&mut h);
(1_i32, 2_u64, 3_i64, true).hash(&mut h);
(1_isize, 'a', "abc", [1u32, 2, 3, 4], false).hash(&mut h);
h.finish();
}
}