1 //! A Rust implementation of the [XXHash] algorithm.
2 //!
3 //! [XXHash]: https://github.com/Cyan4973/xxHash
4 //!
5 //! ### With a fixed seed
6 //!
7 //! ```rust
8 //! use std::hash::BuildHasherDefault;
9 //! use std::collections::HashMap;
10 //! use twox_hash::XxHash64;
11 //!
12 //! let mut hash: HashMap<_, _, BuildHasherDefault<XxHash64>> = Default::default();
13 //! hash.insert(42, "the answer");
14 //! assert_eq!(hash.get(&42), Some(&"the answer"));
15 //! ```
16 //!
17 //! ### With a random seed
18 //!
19 //! ```rust
20 //! use std::collections::HashMap;
21 //! use twox_hash::RandomXxHashBuilder64;
22 //!
23 //! let mut hash: HashMap<_, _, RandomXxHashBuilder64> = Default::default();
24 //! hash.insert(42, "the answer");
25 //! assert_eq!(hash.get(&42), Some(&"the answer"));
26 //! ```
27 
28 #![no_std]
29 
30 extern crate alloc;
31 
32 #[cfg(test)]
33 extern crate std;
34 
35 use core::{marker::PhantomData, mem};
36 
37 mod sixty_four;
38 mod thirty_two;
39 pub mod xxh3;
40 
41 #[cfg(feature = "std")]
42 mod std_support;
43 #[cfg(feature = "std")]
44 pub use std_support::sixty_four::RandomXxHashBuilder64;
45 #[cfg(feature = "std")]
46 pub use std_support::thirty_two::RandomXxHashBuilder32;
47 #[cfg(feature = "std")]
48 pub use std_support::xxh3::{
49     RandomHashBuilder128 as RandomXxh3HashBuilder128,
50     RandomHashBuilder64 as RandomXxh3HashBuilder64,
51 };
52 
53 #[cfg(feature = "digest")]
54 mod digest_support;
55 
56 #[cfg(feature = "digest_0_9")]
57 mod digest_0_9_support;
58 
59 #[cfg(feature = "digest_0_10")]
60 mod digest_0_10_support;
61 
62 pub use crate::sixty_four::XxHash64;
63 pub use crate::thirty_two::XxHash32;
64 pub use crate::xxh3::{Hash128 as Xxh3Hash128, Hash64 as Xxh3Hash64};
65 
66 /// A backwards compatibility type alias. Consider directly using
67 /// `XxHash64` instead.
68 pub type XxHash = XxHash64;
69 
70 #[cfg(feature = "std")]
71 /// A backwards compatibility type alias. Consider directly using
72 /// `RandomXxHashBuilder64` instead.
73 pub type RandomXxHashBuilder = RandomXxHashBuilder64;
74 
75 /// An unaligned buffer with iteration support for `UnalignedItem`.
76 struct UnalignedBuffer<'a, T> {
77     buf: &'a [u8],
78     phantom: PhantomData<T>,
79 }
80 
81 /// Types implementing this trait must be transmutable from a `*const
82 /// u8` to `*const Self` at any possible alignment.
83 ///
84 /// The intent is to use this with only primitive integer types (and
85 /// tightly-packed arrays of those integers).
86 #[allow(clippy::missing_safety_doc)]
87 unsafe trait UnalignedItem {}
88 
89 unsafe impl UnalignedItem for [u64; 4] {}
90 unsafe impl UnalignedItem for [u32; 4] {}
91 unsafe impl UnalignedItem for u64 {}
92 unsafe impl UnalignedItem for u32 {}
93 
94 impl<'a, T: UnalignedItem> UnalignedBuffer<'a, T> {
95     #[inline]
new(buf: &'a [u8]) -> Self96     fn new(buf: &'a [u8]) -> Self {
97         Self {
98             buf,
99             phantom: PhantomData,
100         }
101     }
102 
103     #[inline]
remaining(&self) -> &[u8]104     fn remaining(&self) -> &[u8] {
105         self.buf
106     }
107 }
108 
109 impl<'a, T: UnalignedItem> Iterator for UnalignedBuffer<'a, T> {
110     type Item = T;
111 
next(&mut self) -> Option<Self::Item>112     fn next(&mut self) -> Option<Self::Item> {
113         let size = mem::size_of::<T>();
114         self.buf.get(size..).map(|remaining| {
115             // `self.buf` has at least `size` bytes that can be read as `T`.
116             let result = unsafe { (self.buf.as_ptr() as *const T).read_unaligned() };
117             self.buf = remaining;
118             result
119         })
120     }
121 }
122