/rust/registry/src/index.crates.io-6f17d22bba15001f/twox-hash-2.1.1/src/xxhash32.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! The implementation of XXH32. |
2 | | |
3 | | use core::{ |
4 | | fmt, |
5 | | hash::{self, BuildHasher}, |
6 | | mem, |
7 | | }; |
8 | | |
9 | | use crate::{IntoU32, IntoU64}; |
10 | | |
11 | | // Keeping these constants in this form to match the C code. |
12 | | const PRIME32_1: u32 = 0x9E3779B1; |
13 | | const PRIME32_2: u32 = 0x85EBCA77; |
14 | | const PRIME32_3: u32 = 0xC2B2AE3D; |
15 | | const PRIME32_4: u32 = 0x27D4EB2F; |
16 | | const PRIME32_5: u32 = 0x165667B1; |
17 | | |
18 | | type Lane = u32; |
19 | | type Lanes = [Lane; 4]; |
20 | | type Bytes = [u8; 16]; |
21 | | |
22 | | const BYTES_IN_LANE: usize = mem::size_of::<Bytes>(); |
23 | | |
24 | | #[derive(Clone, PartialEq)] |
25 | | struct BufferData(Lanes); |
26 | | |
27 | | impl BufferData { |
28 | 150M | const fn new() -> Self { |
29 | 150M | Self([0; 4]) |
30 | 150M | } |
31 | | |
32 | 150M | const fn bytes(&self) -> &Bytes { |
33 | | const _: () = assert!(mem::align_of::<u8>() <= mem::align_of::<Lane>()); |
34 | | // SAFETY[bytes]: The alignment of `u32` is at least that of |
35 | | // `u8` and all the values are initialized. |
36 | 150M | unsafe { &*self.0.as_ptr().cast() } |
37 | 150M | } |
38 | | |
39 | 511M | fn bytes_mut(&mut self) -> &mut Bytes { |
40 | 511M | // SAFETY: See SAFETY[bytes] |
41 | 511M | unsafe { &mut *self.0.as_mut_ptr().cast() } |
42 | 511M | } |
43 | | } |
44 | | |
45 | | impl fmt::Debug for BufferData { |
46 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
47 | 0 | f.debug_list().entries(self.0.iter()).finish() |
48 | 0 | } |
49 | | } |
50 | | |
51 | | #[derive(Debug, Clone, PartialEq)] |
52 | | struct Buffer { |
53 | | offset: usize, |
54 | | data: BufferData, |
55 | | } |
56 | | |
57 | | impl Buffer { |
58 | 150M | const fn new() -> Self { |
59 | 150M | Self { |
60 | 150M | offset: 0, |
61 | 150M | data: BufferData::new(), |
62 | 150M | } |
63 | 150M | } |
64 | | |
65 | | // RATIONALE: See RATIONALE[inline] |
66 | | #[inline] |
67 | 452M | fn extend<'d>(&mut self, data: &'d [u8]) -> (Option<&Lanes>, &'d [u8]) { |
68 | 452M | // Most of the slice methods we use here have `_unchecked` variants, but |
69 | 452M | // |
70 | 452M | // 1. this method is called one time per `Hasher::write` call |
71 | 452M | // 2. this method early exits if we don't have anything in the buffer |
72 | 452M | // |
73 | 452M | // Because of this, removing the panics via `unsafe` doesn't |
74 | 452M | // have much benefit other than reducing code size by a tiny |
75 | 452M | // bit. |
76 | 452M | |
77 | 452M | if self.offset == 0 { |
78 | 210M | return (None, data); |
79 | 242M | }; |
80 | 242M | |
81 | 242M | let bytes = self.data.bytes_mut(); |
82 | 242M | debug_assert!(self.offset <= bytes.len()); |
83 | | |
84 | 242M | let empty = &mut bytes[self.offset..]; |
85 | 242M | let n_to_copy = usize::min(empty.len(), data.len()); |
86 | 242M | |
87 | 242M | let dst = &mut empty[..n_to_copy]; |
88 | 242M | |
89 | 242M | let (src, rest) = data.split_at(n_to_copy); |
90 | 242M | |
91 | 242M | dst.copy_from_slice(src); |
92 | 242M | self.offset += n_to_copy; |
93 | 242M | |
94 | 242M | debug_assert!(self.offset <= bytes.len()); |
95 | | |
96 | 242M | if self.offset == bytes.len() { |
97 | 121M | self.offset = 0; |
98 | 121M | (Some(&self.data.0), rest) |
99 | | } else { |
100 | 120M | (None, rest) |
101 | | } |
102 | 452M | } Unexecuted instantiation: <twox_hash::xxhash32::Buffer>::extend <twox_hash::xxhash32::Buffer>::extend Line | Count | Source | 67 | 452M | fn extend<'d>(&mut self, data: &'d [u8]) -> (Option<&Lanes>, &'d [u8]) { | 68 | 452M | // Most of the slice methods we use here have `_unchecked` variants, but | 69 | 452M | // | 70 | 452M | // 1. this method is called one time per `Hasher::write` call | 71 | 452M | // 2. this method early exits if we don't have anything in the buffer | 72 | 452M | // | 73 | 452M | // Because of this, removing the panics via `unsafe` doesn't | 74 | 452M | // have much benefit other than reducing code size by a tiny | 75 | 452M | // bit. | 76 | 452M | | 77 | 452M | if self.offset == 0 { | 78 | 210M | return (None, data); | 79 | 242M | }; | 80 | 242M | | 81 | 242M | let bytes = self.data.bytes_mut(); | 82 | 242M | debug_assert!(self.offset <= bytes.len()); | 83 | | | 84 | 242M | let empty = &mut bytes[self.offset..]; | 85 | 242M | let n_to_copy = usize::min(empty.len(), data.len()); | 86 | 242M | | 87 | 242M | let dst = &mut empty[..n_to_copy]; | 88 | 242M | | 89 | 242M | let (src, rest) = data.split_at(n_to_copy); | 90 | 242M | | 91 | 242M | dst.copy_from_slice(src); | 92 | 242M | self.offset += n_to_copy; | 93 | 242M | | 94 | 242M | debug_assert!(self.offset <= bytes.len()); | 95 | | | 96 | 242M | if self.offset == bytes.len() { | 97 | 121M | self.offset = 0; | 98 | 121M | (Some(&self.data.0), rest) | 99 | | } else { | 100 | 120M | (None, rest) | 101 | | } | 102 | 452M | } |
<twox_hash::xxhash32::Buffer>::extend Line | Count | Source | 67 | 60.5k | fn extend<'d>(&mut self, data: &'d [u8]) -> (Option<&Lanes>, &'d [u8]) { | 68 | 60.5k | // Most of the slice methods we use here have `_unchecked` variants, but | 69 | 60.5k | // | 70 | 60.5k | // 1. this method is called one time per `Hasher::write` call | 71 | 60.5k | // 2. this method early exits if we don't have anything in the buffer | 72 | 60.5k | // | 73 | 60.5k | // Because of this, removing the panics via `unsafe` doesn't | 74 | 60.5k | // have much benefit other than reducing code size by a tiny | 75 | 60.5k | // bit. | 76 | 60.5k | | 77 | 60.5k | if self.offset == 0 { | 78 | 60.5k | return (None, data); | 79 | 0 | }; | 80 | 0 |
| 81 | 0 | let bytes = self.data.bytes_mut(); | 82 | 0 | debug_assert!(self.offset <= bytes.len()); | 83 | | | 84 | 0 | let empty = &mut bytes[self.offset..]; | 85 | 0 | let n_to_copy = usize::min(empty.len(), data.len()); | 86 | 0 |
| 87 | 0 | let dst = &mut empty[..n_to_copy]; | 88 | 0 |
| 89 | 0 | let (src, rest) = data.split_at(n_to_copy); | 90 | 0 |
| 91 | 0 | dst.copy_from_slice(src); | 92 | 0 | self.offset += n_to_copy; | 93 | 0 |
| 94 | 0 | debug_assert!(self.offset <= bytes.len()); | 95 | | | 96 | 0 | if self.offset == bytes.len() { | 97 | 0 | self.offset = 0; | 98 | 0 | (Some(&self.data.0), rest) | 99 | | } else { | 100 | 0 | (None, rest) | 101 | | } | 102 | 60.5k | } |
<twox_hash::xxhash32::Buffer>::extend Line | Count | Source | 67 | 27.3k | fn extend<'d>(&mut self, data: &'d [u8]) -> (Option<&Lanes>, &'d [u8]) { | 68 | 27.3k | // Most of the slice methods we use here have `_unchecked` variants, but | 69 | 27.3k | // | 70 | 27.3k | // 1. this method is called one time per `Hasher::write` call | 71 | 27.3k | // 2. this method early exits if we don't have anything in the buffer | 72 | 27.3k | // | 73 | 27.3k | // Because of this, removing the panics via `unsafe` doesn't | 74 | 27.3k | // have much benefit other than reducing code size by a tiny | 75 | 27.3k | // bit. | 76 | 27.3k | | 77 | 27.3k | if self.offset == 0 { | 78 | 4.21k | return (None, data); | 79 | 23.1k | }; | 80 | 23.1k | | 81 | 23.1k | let bytes = self.data.bytes_mut(); | 82 | 23.1k | debug_assert!(self.offset <= bytes.len()); | 83 | | | 84 | 23.1k | let empty = &mut bytes[self.offset..]; | 85 | 23.1k | let n_to_copy = usize::min(empty.len(), data.len()); | 86 | 23.1k | | 87 | 23.1k | let dst = &mut empty[..n_to_copy]; | 88 | 23.1k | | 89 | 23.1k | let (src, rest) = data.split_at(n_to_copy); | 90 | 23.1k | | 91 | 23.1k | dst.copy_from_slice(src); | 92 | 23.1k | self.offset += n_to_copy; | 93 | 23.1k | | 94 | 23.1k | debug_assert!(self.offset <= bytes.len()); | 95 | | | 96 | 23.1k | if self.offset == bytes.len() { | 97 | 5.33k | self.offset = 0; | 98 | 5.33k | (Some(&self.data.0), rest) | 99 | | } else { | 100 | 17.7k | (None, rest) | 101 | | } | 102 | 27.3k | } |
|
103 | | |
104 | | // RATIONALE: See RATIONALE[inline] |
105 | | #[inline] |
106 | 452M | fn set(&mut self, data: &[u8]) { |
107 | 452M | if data.is_empty() { |
108 | 183M | return; |
109 | 269M | } |
110 | 269M | |
111 | 269M | debug_assert_eq!(self.offset, 0); |
112 | | |
113 | 269M | let n_to_copy = data.len(); |
114 | 269M | |
115 | 269M | let bytes = self.data.bytes_mut(); |
116 | 269M | debug_assert!(n_to_copy < bytes.len()); |
117 | | |
118 | 269M | bytes[..n_to_copy].copy_from_slice(data); |
119 | 269M | self.offset = data.len(); |
120 | 452M | } Unexecuted instantiation: <twox_hash::xxhash32::Buffer>::set <twox_hash::xxhash32::Buffer>::set Line | Count | Source | 106 | 452M | fn set(&mut self, data: &[u8]) { | 107 | 452M | if data.is_empty() { | 108 | 183M | return; | 109 | 269M | } | 110 | 269M | | 111 | 269M | debug_assert_eq!(self.offset, 0); | 112 | | | 113 | 269M | let n_to_copy = data.len(); | 114 | 269M | | 115 | 269M | let bytes = self.data.bytes_mut(); | 116 | 269M | debug_assert!(n_to_copy < bytes.len()); | 117 | | | 118 | 269M | bytes[..n_to_copy].copy_from_slice(data); | 119 | 269M | self.offset = data.len(); | 120 | 452M | } |
<twox_hash::xxhash32::Buffer>::set Line | Count | Source | 106 | 60.5k | fn set(&mut self, data: &[u8]) { | 107 | 60.5k | if data.is_empty() { | 108 | 0 | return; | 109 | 60.5k | } | 110 | 60.5k | | 111 | 60.5k | debug_assert_eq!(self.offset, 0); | 112 | | | 113 | 60.5k | let n_to_copy = data.len(); | 114 | 60.5k | | 115 | 60.5k | let bytes = self.data.bytes_mut(); | 116 | 60.5k | debug_assert!(n_to_copy < bytes.len()); | 117 | | | 118 | 60.5k | bytes[..n_to_copy].copy_from_slice(data); | 119 | 60.5k | self.offset = data.len(); | 120 | 60.5k | } |
<twox_hash::xxhash32::Buffer>::set Line | Count | Source | 106 | 27.3k | fn set(&mut self, data: &[u8]) { | 107 | 27.3k | if data.is_empty() { | 108 | 19.6k | return; | 109 | 7.67k | } | 110 | 7.67k | | 111 | 7.67k | debug_assert_eq!(self.offset, 0); | 112 | | | 113 | 7.67k | let n_to_copy = data.len(); | 114 | 7.67k | | 115 | 7.67k | let bytes = self.data.bytes_mut(); | 116 | 7.67k | debug_assert!(n_to_copy < bytes.len()); | 117 | | | 118 | 7.67k | bytes[..n_to_copy].copy_from_slice(data); | 119 | 7.67k | self.offset = data.len(); | 120 | 27.3k | } |
|
121 | | |
122 | | // RATIONALE: See RATIONALE[inline] |
123 | | #[inline] |
124 | 150M | fn remaining(&self) -> &[u8] { |
125 | 150M | &self.data.bytes()[..self.offset] |
126 | 150M | } Unexecuted instantiation: <twox_hash::xxhash32::Buffer>::remaining <twox_hash::xxhash32::Buffer>::remaining Line | Count | Source | 124 | 150M | fn remaining(&self) -> &[u8] { | 125 | 150M | &self.data.bytes()[..self.offset] | 126 | 150M | } |
<twox_hash::xxhash32::Buffer>::remaining Line | Count | Source | 124 | 60.5k | fn remaining(&self) -> &[u8] { | 125 | 60.5k | &self.data.bytes()[..self.offset] | 126 | 60.5k | } |
<twox_hash::xxhash32::Buffer>::remaining Line | Count | Source | 124 | 2.21k | fn remaining(&self) -> &[u8] { | 125 | 2.21k | &self.data.bytes()[..self.offset] | 126 | 2.21k | } |
|
127 | | } |
128 | | |
129 | | #[derive(Clone, PartialEq)] |
130 | | struct Accumulators(Lanes); |
131 | | |
132 | | impl Accumulators { |
133 | 301M | const fn new(seed: u32) -> Self { |
134 | 301M | Self([ |
135 | 301M | seed.wrapping_add(PRIME32_1).wrapping_add(PRIME32_2), |
136 | 301M | seed.wrapping_add(PRIME32_2), |
137 | 301M | seed, |
138 | 301M | seed.wrapping_sub(PRIME32_1), |
139 | 301M | ]) |
140 | 301M | } |
141 | | |
142 | | // RATIONALE: See RATIONALE[inline] |
143 | | #[inline] |
144 | 1.09G | fn write(&mut self, lanes: Lanes) { |
145 | 1.09G | let [acc1, acc2, acc3, acc4] = &mut self.0; |
146 | 1.09G | let [lane1, lane2, lane3, lane4] = lanes; |
147 | 1.09G | |
148 | 1.09G | *acc1 = round(*acc1, lane1.to_le()); |
149 | 1.09G | *acc2 = round(*acc2, lane2.to_le()); |
150 | 1.09G | *acc3 = round(*acc3, lane3.to_le()); |
151 | 1.09G | *acc4 = round(*acc4, lane4.to_le()); |
152 | 1.09G | } Unexecuted instantiation: <twox_hash::xxhash32::Accumulators>::write <twox_hash::xxhash32::Accumulators>::write Line | Count | Source | 144 | 1.09G | fn write(&mut self, lanes: Lanes) { | 145 | 1.09G | let [acc1, acc2, acc3, acc4] = &mut self.0; | 146 | 1.09G | let [lane1, lane2, lane3, lane4] = lanes; | 147 | 1.09G | | 148 | 1.09G | *acc1 = round(*acc1, lane1.to_le()); | 149 | 1.09G | *acc2 = round(*acc2, lane2.to_le()); | 150 | 1.09G | *acc3 = round(*acc3, lane3.to_le()); | 151 | 1.09G | *acc4 = round(*acc4, lane4.to_le()); | 152 | 1.09G | } |
Unexecuted instantiation: <twox_hash::xxhash32::Accumulators>::write <twox_hash::xxhash32::Accumulators>::write Line | Count | Source | 144 | 4.63M | fn write(&mut self, lanes: Lanes) { | 145 | 4.63M | let [acc1, acc2, acc3, acc4] = &mut self.0; | 146 | 4.63M | let [lane1, lane2, lane3, lane4] = lanes; | 147 | 4.63M | | 148 | 4.63M | *acc1 = round(*acc1, lane1.to_le()); | 149 | 4.63M | *acc2 = round(*acc2, lane2.to_le()); | 150 | 4.63M | *acc3 = round(*acc3, lane3.to_le()); | 151 | 4.63M | *acc4 = round(*acc4, lane4.to_le()); | 152 | 4.63M | } |
|
153 | | |
154 | | // RATIONALE: See RATIONALE[inline] |
155 | | #[inline] |
156 | 603M | fn write_many<'d>(&mut self, mut data: &'d [u8]) -> &'d [u8] { |
157 | 1.57G | while let Some((chunk, rest)) = data.split_first_chunk::<BYTES_IN_LANE>() { |
158 | 975M | // SAFETY: We have the right number of bytes and are |
159 | 975M | // handling the unaligned case. |
160 | 975M | let lanes = unsafe { chunk.as_ptr().cast::<Lanes>().read_unaligned() }; |
161 | 975M | self.write(lanes); |
162 | 975M | data = rest; |
163 | 975M | } |
164 | 603M | data |
165 | 603M | } Unexecuted instantiation: <twox_hash::xxhash32::Accumulators>::write_many <twox_hash::xxhash32::Accumulators>::write_many Line | Count | Source | 156 | 603M | fn write_many<'d>(&mut self, mut data: &'d [u8]) -> &'d [u8] { | 157 | 1.57G | while let Some((chunk, rest)) = data.split_first_chunk::<BYTES_IN_LANE>() { | 158 | 970M | // SAFETY: We have the right number of bytes and are | 159 | 970M | // handling the unaligned case. | 160 | 970M | let lanes = unsafe { chunk.as_ptr().cast::<Lanes>().read_unaligned() }; | 161 | 970M | self.write(lanes); | 162 | 970M | data = rest; | 163 | 970M | } | 164 | 603M | data | 165 | 603M | } |
<twox_hash::xxhash32::Accumulators>::write_many Line | Count | Source | 156 | 60.5k | fn write_many<'d>(&mut self, mut data: &'d [u8]) -> &'d [u8] { | 157 | 60.5k | while let Some((chunk, rest)) = data.split_first_chunk::<BYTES_IN_LANE>() { | 158 | 0 | // SAFETY: We have the right number of bytes and are | 159 | 0 | // handling the unaligned case. | 160 | 0 | let lanes = unsafe { chunk.as_ptr().cast::<Lanes>().read_unaligned() }; | 161 | 0 | self.write(lanes); | 162 | 0 | data = rest; | 163 | 0 | } | 164 | 60.5k | data | 165 | 60.5k | } |
<twox_hash::xxhash32::Accumulators>::write_many Line | Count | Source | 156 | 27.3k | fn write_many<'d>(&mut self, mut data: &'d [u8]) -> &'d [u8] { | 157 | 4.65M | while let Some((chunk, rest)) = data.split_first_chunk::<BYTES_IN_LANE>() { | 158 | 4.62M | // SAFETY: We have the right number of bytes and are | 159 | 4.62M | // handling the unaligned case. | 160 | 4.62M | let lanes = unsafe { chunk.as_ptr().cast::<Lanes>().read_unaligned() }; | 161 | 4.62M | self.write(lanes); | 162 | 4.62M | data = rest; | 163 | 4.62M | } | 164 | 27.3k | data | 165 | 27.3k | } |
|
166 | | |
167 | | // RATIONALE: See RATIONALE[inline] |
168 | | #[inline] |
169 | 26.2M | const fn finish(&self) -> u32 { |
170 | 26.2M | let [acc1, acc2, acc3, acc4] = self.0; |
171 | 26.2M | |
172 | 26.2M | let acc1 = acc1.rotate_left(1); |
173 | 26.2M | let acc2 = acc2.rotate_left(7); |
174 | 26.2M | let acc3 = acc3.rotate_left(12); |
175 | 26.2M | let acc4 = acc4.rotate_left(18); |
176 | 26.2M | |
177 | 26.2M | acc1.wrapping_add(acc2) |
178 | 26.2M | .wrapping_add(acc3) |
179 | 26.2M | .wrapping_add(acc4) |
180 | 26.2M | } Unexecuted instantiation: <twox_hash::xxhash32::Accumulators>::finish <twox_hash::xxhash32::Accumulators>::finish Line | Count | Source | 169 | 26.2M | const fn finish(&self) -> u32 { | 170 | 26.2M | let [acc1, acc2, acc3, acc4] = self.0; | 171 | 26.2M | | 172 | 26.2M | let acc1 = acc1.rotate_left(1); | 173 | 26.2M | let acc2 = acc2.rotate_left(7); | 174 | 26.2M | let acc3 = acc3.rotate_left(12); | 175 | 26.2M | let acc4 = acc4.rotate_left(18); | 176 | 26.2M | | 177 | 26.2M | acc1.wrapping_add(acc2) | 178 | 26.2M | .wrapping_add(acc3) | 179 | 26.2M | .wrapping_add(acc4) | 180 | 26.2M | } |
Unexecuted instantiation: <twox_hash::xxhash32::Accumulators>::finish <twox_hash::xxhash32::Accumulators>::finish Line | Count | Source | 169 | 787 | const fn finish(&self) -> u32 { | 170 | 787 | let [acc1, acc2, acc3, acc4] = self.0; | 171 | 787 | | 172 | 787 | let acc1 = acc1.rotate_left(1); | 173 | 787 | let acc2 = acc2.rotate_left(7); | 174 | 787 | let acc3 = acc3.rotate_left(12); | 175 | 787 | let acc4 = acc4.rotate_left(18); | 176 | 787 | | 177 | 787 | acc1.wrapping_add(acc2) | 178 | 787 | .wrapping_add(acc3) | 179 | 787 | .wrapping_add(acc4) | 180 | 787 | } |
|
181 | | } |
182 | | |
183 | | impl fmt::Debug for Accumulators { |
184 | 0 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
185 | 0 | let [acc1, acc2, acc3, acc4] = self.0; |
186 | 0 | f.debug_struct("Accumulators") |
187 | 0 | .field("acc1", &acc1) |
188 | 0 | .field("acc2", &acc2) |
189 | 0 | .field("acc3", &acc3) |
190 | 0 | .field("acc4", &acc4) |
191 | 0 | .finish() |
192 | 0 | } |
193 | | } |
194 | | |
195 | | /// Calculates the 32-bit hash. |
196 | | /// |
197 | | /// ### Caution |
198 | | /// |
199 | | /// Although this struct implements [`hash::Hasher`][], it only calculates a |
200 | | /// 32-bit number, leaving the upper bits as 0. This means it is |
201 | | /// unlikely to be correct to use this in places like a [`HashMap`][std::collections::HashMap]. |
202 | | #[derive(Debug, Clone, PartialEq)] |
203 | | pub struct Hasher { |
204 | | seed: u32, |
205 | | accumulators: Accumulators, |
206 | | buffer: Buffer, |
207 | | length: u64, |
208 | | } |
209 | | |
210 | | impl Default for Hasher { |
211 | 0 | fn default() -> Self { |
212 | 0 | Self::with_seed(0) |
213 | 0 | } |
214 | | } |
215 | | |
216 | | impl Hasher { |
217 | | /// Hash all data at once. If you can use this function, you may |
218 | | /// see noticable speed gains for certain types of input. |
219 | | #[must_use] |
220 | | // RATIONALE[inline]: Keeping parallel to the 64-bit |
221 | | // implementation, even though the performance gains for the |
222 | | // 32-bit version haven't been tested. |
223 | | #[inline] |
224 | 150M | pub fn oneshot(seed: u32, data: &[u8]) -> u32 { |
225 | 150M | let len = data.len(); |
226 | 150M | |
227 | 150M | // Since we know that there's no more data coming, we don't |
228 | 150M | // need to construct the intermediate buffers or copy data to |
229 | 150M | // or from the buffers. |
230 | 150M | |
231 | 150M | let mut accumulators = Accumulators::new(seed); |
232 | 150M | |
233 | 150M | let data = accumulators.write_many(data); |
234 | 150M | |
235 | 150M | Self::finish_with(seed, len.into_u64(), &accumulators, data) |
236 | 150M | } Unexecuted instantiation: <twox_hash::xxhash32::Hasher>::oneshot <twox_hash::xxhash32::Hasher>::oneshot Line | Count | Source | 224 | 150M | pub fn oneshot(seed: u32, data: &[u8]) -> u32 { | 225 | 150M | let len = data.len(); | 226 | 150M | | 227 | 150M | // Since we know that there's no more data coming, we don't | 228 | 150M | // need to construct the intermediate buffers or copy data to | 229 | 150M | // or from the buffers. | 230 | 150M | | 231 | 150M | let mut accumulators = Accumulators::new(seed); | 232 | 150M | | 233 | 150M | let data = accumulators.write_many(data); | 234 | 150M | | 235 | 150M | Self::finish_with(seed, len.into_u64(), &accumulators, data) | 236 | 150M | } |
|
237 | | |
238 | | /// Constructs the hasher with an initial seed. |
239 | | #[must_use] |
240 | 150M | pub const fn with_seed(seed: u32) -> Self { |
241 | 150M | // Step 1. Initialize internal accumulators |
242 | 150M | Self { |
243 | 150M | seed, |
244 | 150M | accumulators: Accumulators::new(seed), |
245 | 150M | buffer: Buffer::new(), |
246 | 150M | length: 0, |
247 | 150M | } |
248 | 150M | } |
249 | | |
250 | | /// The seed this hasher was created with. |
251 | 0 | pub const fn seed(&self) -> u32 { |
252 | 0 | self.seed |
253 | 0 | } |
254 | | |
255 | | /// The total number of bytes hashed. |
256 | 0 | pub const fn total_len(&self) -> u64 { |
257 | 0 | self.length |
258 | 0 | } |
259 | | |
260 | | /// The total number of bytes hashed, truncated to 32 bits. |
261 | | /// |
262 | | /// For the full 64-bit byte count, use [`total_len`](Self::total_len). |
263 | 0 | pub const fn total_len_32(&self) -> u32 { |
264 | 0 | self.length as u32 |
265 | 0 | } |
266 | | |
267 | | /// Returns the hash value for the values written so far. Unlike |
268 | | /// [`hash::Hasher::finish`][], this method returns the actual 32-bit |
269 | | /// value calculated, not a 64-bit value. |
270 | | #[must_use] |
271 | | // RATIONALE: See RATIONALE[inline] |
272 | | #[inline] |
273 | 150M | pub fn finish_32(&self) -> u32 { |
274 | 150M | Self::finish_with( |
275 | 150M | self.seed, |
276 | 150M | self.length, |
277 | 150M | &self.accumulators, |
278 | 150M | self.buffer.remaining(), |
279 | 150M | ) |
280 | 150M | } Unexecuted instantiation: <twox_hash::xxhash32::Hasher>::finish_32 <twox_hash::xxhash32::Hasher>::finish_32 Line | Count | Source | 273 | 150M | pub fn finish_32(&self) -> u32 { | 274 | 150M | Self::finish_with( | 275 | 150M | self.seed, | 276 | 150M | self.length, | 277 | 150M | &self.accumulators, | 278 | 150M | self.buffer.remaining(), | 279 | 150M | ) | 280 | 150M | } |
<twox_hash::xxhash32::Hasher>::finish_32 Line | Count | Source | 273 | 60.5k | pub fn finish_32(&self) -> u32 { | 274 | 60.5k | Self::finish_with( | 275 | 60.5k | self.seed, | 276 | 60.5k | self.length, | 277 | 60.5k | &self.accumulators, | 278 | 60.5k | self.buffer.remaining(), | 279 | 60.5k | ) | 280 | 60.5k | } |
<twox_hash::xxhash32::Hasher>::finish_32 Line | Count | Source | 273 | 2.21k | pub fn finish_32(&self) -> u32 { | 274 | 2.21k | Self::finish_with( | 275 | 2.21k | self.seed, | 276 | 2.21k | self.length, | 277 | 2.21k | &self.accumulators, | 278 | 2.21k | self.buffer.remaining(), | 279 | 2.21k | ) | 280 | 2.21k | } |
|
281 | | |
282 | | #[must_use] |
283 | | // RATIONALE: See RATIONALE[inline] |
284 | | #[inline] |
285 | 301M | fn finish_with(seed: u32, len: u64, accumulators: &Accumulators, mut remaining: &[u8]) -> u32 { |
286 | | // Step 3. Accumulator convergence |
287 | 301M | let mut acc = if len < BYTES_IN_LANE.into_u64() { |
288 | 275M | seed.wrapping_add(PRIME32_5) |
289 | | } else { |
290 | 26.2M | accumulators.finish() |
291 | | }; |
292 | | |
293 | | // Step 4. Add input length |
294 | | // |
295 | | // "Note that, if input length is so large that it requires |
296 | | // more than 32-bits, only the lower 32-bits are added to the |
297 | | // accumulator." |
298 | 301M | acc += len as u32; |
299 | | |
300 | | // Step 5. Consume remaining input |
301 | 645M | while let Some((chunk, rest)) = remaining.split_first_chunk() { |
302 | 343M | let lane = u32::from_ne_bytes(*chunk).to_le(); |
303 | 343M | |
304 | 343M | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_3)); |
305 | 343M | acc = acc.rotate_left(17).wrapping_mul(PRIME32_4); |
306 | 343M | |
307 | 343M | remaining = rest; |
308 | 343M | } |
309 | | |
310 | 752M | for &byte in remaining { |
311 | 450M | let lane = byte.into_u32(); |
312 | 450M | |
313 | 450M | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_5)); |
314 | 450M | acc = acc.rotate_left(11).wrapping_mul(PRIME32_1); |
315 | 450M | } |
316 | | |
317 | | // Step 6. Final mix (avalanche) |
318 | 301M | acc ^= acc >> 15; |
319 | 301M | acc = acc.wrapping_mul(PRIME32_2); |
320 | 301M | acc ^= acc >> 13; |
321 | 301M | acc = acc.wrapping_mul(PRIME32_3); |
322 | 301M | acc ^= acc >> 16; |
323 | 301M | |
324 | 301M | acc |
325 | 301M | } Unexecuted instantiation: <twox_hash::xxhash32::Hasher>::finish_with <twox_hash::xxhash32::Hasher>::finish_with Line | Count | Source | 285 | 301M | fn finish_with(seed: u32, len: u64, accumulators: &Accumulators, mut remaining: &[u8]) -> u32 { | 286 | | // Step 3. Accumulator convergence | 287 | 301M | let mut acc = if len < BYTES_IN_LANE.into_u64() { | 288 | 275M | seed.wrapping_add(PRIME32_5) | 289 | | } else { | 290 | 26.2M | accumulators.finish() | 291 | | }; | 292 | | | 293 | | // Step 4. Add input length | 294 | | // | 295 | | // "Note that, if input length is so large that it requires | 296 | | // more than 32-bits, only the lower 32-bits are added to the | 297 | | // accumulator." | 298 | 301M | acc += len as u32; | 299 | | | 300 | | // Step 5. Consume remaining input | 301 | 644M | while let Some((chunk, rest)) = remaining.split_first_chunk() { | 302 | 343M | let lane = u32::from_ne_bytes(*chunk).to_le(); | 303 | 343M | | 304 | 343M | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_3)); | 305 | 343M | acc = acc.rotate_left(17).wrapping_mul(PRIME32_4); | 306 | 343M | | 307 | 343M | remaining = rest; | 308 | 343M | } | 309 | | | 310 | 752M | for &byte in remaining { | 311 | 450M | let lane = byte.into_u32(); | 312 | 450M | | 313 | 450M | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_5)); | 314 | 450M | acc = acc.rotate_left(11).wrapping_mul(PRIME32_1); | 315 | 450M | } | 316 | | | 317 | | // Step 6. Final mix (avalanche) | 318 | 301M | acc ^= acc >> 15; | 319 | 301M | acc = acc.wrapping_mul(PRIME32_2); | 320 | 301M | acc ^= acc >> 13; | 321 | 301M | acc = acc.wrapping_mul(PRIME32_3); | 322 | 301M | acc ^= acc >> 16; | 323 | 301M | | 324 | 301M | acc | 325 | 301M | } |
<twox_hash::xxhash32::Hasher>::finish_with Line | Count | Source | 285 | 60.5k | fn finish_with(seed: u32, len: u64, accumulators: &Accumulators, mut remaining: &[u8]) -> u32 { | 286 | | // Step 3. Accumulator convergence | 287 | 60.5k | let mut acc = if len < BYTES_IN_LANE.into_u64() { | 288 | 60.5k | seed.wrapping_add(PRIME32_5) | 289 | | } else { | 290 | 0 | accumulators.finish() | 291 | | }; | 292 | | | 293 | | // Step 4. Add input length | 294 | | // | 295 | | // "Note that, if input length is so large that it requires | 296 | | // more than 32-bits, only the lower 32-bits are added to the | 297 | | // accumulator." | 298 | 60.5k | acc += len as u32; | 299 | | | 300 | | // Step 5. Consume remaining input | 301 | 61.2k | while let Some((chunk, rest)) = remaining.split_first_chunk() { | 302 | 754 | let lane = u32::from_ne_bytes(*chunk).to_le(); | 303 | 754 | | 304 | 754 | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_3)); | 305 | 754 | acc = acc.rotate_left(17).wrapping_mul(PRIME32_4); | 306 | 754 | | 307 | 754 | remaining = rest; | 308 | 754 | } | 309 | | | 310 | 181k | for &byte in remaining { | 311 | 121k | let lane = byte.into_u32(); | 312 | 121k | | 313 | 121k | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_5)); | 314 | 121k | acc = acc.rotate_left(11).wrapping_mul(PRIME32_1); | 315 | 121k | } | 316 | | | 317 | | // Step 6. Final mix (avalanche) | 318 | 60.5k | acc ^= acc >> 15; | 319 | 60.5k | acc = acc.wrapping_mul(PRIME32_2); | 320 | 60.5k | acc ^= acc >> 13; | 321 | 60.5k | acc = acc.wrapping_mul(PRIME32_3); | 322 | 60.5k | acc ^= acc >> 16; | 323 | 60.5k | | 324 | 60.5k | acc | 325 | 60.5k | } |
<twox_hash::xxhash32::Hasher>::finish_with Line | Count | Source | 285 | 2.21k | fn finish_with(seed: u32, len: u64, accumulators: &Accumulators, mut remaining: &[u8]) -> u32 { | 286 | | // Step 3. Accumulator convergence | 287 | 2.21k | let mut acc = if len < BYTES_IN_LANE.into_u64() { | 288 | 1.42k | seed.wrapping_add(PRIME32_5) | 289 | | } else { | 290 | 787 | accumulators.finish() | 291 | | }; | 292 | | | 293 | | // Step 4. Add input length | 294 | | // | 295 | | // "Note that, if input length is so large that it requires | 296 | | // more than 32-bits, only the lower 32-bits are added to the | 297 | | // accumulator." | 298 | 2.21k | acc += len as u32; | 299 | | | 300 | | // Step 5. Consume remaining input | 301 | 2.83k | while let Some((chunk, rest)) = remaining.split_first_chunk() { | 302 | 624 | let lane = u32::from_ne_bytes(*chunk).to_le(); | 303 | 624 | | 304 | 624 | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_3)); | 305 | 624 | acc = acc.rotate_left(17).wrapping_mul(PRIME32_4); | 306 | 624 | | 307 | 624 | remaining = rest; | 308 | 624 | } | 309 | | | 310 | 5.57k | for &byte in remaining { | 311 | 3.36k | let lane = byte.into_u32(); | 312 | 3.36k | | 313 | 3.36k | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_5)); | 314 | 3.36k | acc = acc.rotate_left(11).wrapping_mul(PRIME32_1); | 315 | 3.36k | } | 316 | | | 317 | | // Step 6. Final mix (avalanche) | 318 | 2.21k | acc ^= acc >> 15; | 319 | 2.21k | acc = acc.wrapping_mul(PRIME32_2); | 320 | 2.21k | acc ^= acc >> 13; | 321 | 2.21k | acc = acc.wrapping_mul(PRIME32_3); | 322 | 2.21k | acc ^= acc >> 16; | 323 | 2.21k | | 324 | 2.21k | acc | 325 | 2.21k | } |
|
326 | | } |
327 | | |
328 | | impl hash::Hasher for Hasher { |
329 | | // RATIONALE: See RATIONALE[inline] |
330 | | #[inline] |
331 | 452M | fn write(&mut self, data: &[u8]) { |
332 | 452M | let len = data.len(); |
333 | 452M | |
334 | 452M | // Step 2. Process stripes |
335 | 452M | let (buffered_lanes, data) = self.buffer.extend(data); |
336 | | |
337 | 452M | if let Some(&lanes) = buffered_lanes { |
338 | 121M | self.accumulators.write(lanes); |
339 | 330M | } |
340 | | |
341 | 452M | let data = self.accumulators.write_many(data); |
342 | 452M | |
343 | 452M | self.buffer.set(data); |
344 | 452M | |
345 | 452M | self.length += len.into_u64(); |
346 | 452M | } Unexecuted instantiation: <twox_hash::xxhash32::Hasher as core::hash::Hasher>::write <twox_hash::xxhash32::Hasher as core::hash::Hasher>::write Line | Count | Source | 331 | 452M | fn write(&mut self, data: &[u8]) { | 332 | 452M | let len = data.len(); | 333 | 452M | | 334 | 452M | // Step 2. Process stripes | 335 | 452M | let (buffered_lanes, data) = self.buffer.extend(data); | 336 | | | 337 | 452M | if let Some(&lanes) = buffered_lanes { | 338 | 121M | self.accumulators.write(lanes); | 339 | 330M | } | 340 | | | 341 | 452M | let data = self.accumulators.write_many(data); | 342 | 452M | | 343 | 452M | self.buffer.set(data); | 344 | 452M | | 345 | 452M | self.length += len.into_u64(); | 346 | 452M | } |
<twox_hash::xxhash32::Hasher as core::hash::Hasher>::write Line | Count | Source | 331 | 60.5k | fn write(&mut self, data: &[u8]) { | 332 | 60.5k | let len = data.len(); | 333 | 60.5k | | 334 | 60.5k | // Step 2. Process stripes | 335 | 60.5k | let (buffered_lanes, data) = self.buffer.extend(data); | 336 | | | 337 | 60.5k | if let Some(&lanes) = buffered_lanes { | 338 | 0 | self.accumulators.write(lanes); | 339 | 60.5k | } | 340 | | | 341 | 60.5k | let data = self.accumulators.write_many(data); | 342 | 60.5k | | 343 | 60.5k | self.buffer.set(data); | 344 | 60.5k | | 345 | 60.5k | self.length += len.into_u64(); | 346 | 60.5k | } |
<twox_hash::xxhash32::Hasher as core::hash::Hasher>::write Line | Count | Source | 331 | 27.3k | fn write(&mut self, data: &[u8]) { | 332 | 27.3k | let len = data.len(); | 333 | 27.3k | | 334 | 27.3k | // Step 2. Process stripes | 335 | 27.3k | let (buffered_lanes, data) = self.buffer.extend(data); | 336 | | | 337 | 27.3k | if let Some(&lanes) = buffered_lanes { | 338 | 5.33k | self.accumulators.write(lanes); | 339 | 22.0k | } | 340 | | | 341 | 27.3k | let data = self.accumulators.write_many(data); | 342 | 27.3k | | 343 | 27.3k | self.buffer.set(data); | 344 | 27.3k | | 345 | 27.3k | self.length += len.into_u64(); | 346 | 27.3k | } |
|
347 | | |
348 | | // RATIONALE: See RATIONALE[inline] |
349 | | #[inline] |
350 | 150M | fn finish(&self) -> u64 { |
351 | 150M | Hasher::finish_32(self).into() |
352 | 150M | } Unexecuted instantiation: <twox_hash::xxhash32::Hasher as core::hash::Hasher>::finish <twox_hash::xxhash32::Hasher as core::hash::Hasher>::finish Line | Count | Source | 350 | 150M | fn finish(&self) -> u64 { | 351 | 150M | Hasher::finish_32(self).into() | 352 | 150M | } |
<twox_hash::xxhash32::Hasher as core::hash::Hasher>::finish Line | Count | Source | 350 | 60.5k | fn finish(&self) -> u64 { | 351 | 60.5k | Hasher::finish_32(self).into() | 352 | 60.5k | } |
<twox_hash::xxhash32::Hasher as core::hash::Hasher>::finish Line | Count | Source | 350 | 2.21k | fn finish(&self) -> u64 { | 351 | 2.21k | Hasher::finish_32(self).into() | 352 | 2.21k | } |
|
353 | | } |
354 | | |
355 | | // RATIONALE: See RATIONALE[inline] |
356 | | #[inline] |
357 | 4.38G | const fn round(mut acc: u32, lane: u32) -> u32 { |
358 | 4.38G | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_2)); |
359 | 4.38G | acc = acc.rotate_left(13); |
360 | 4.38G | acc.wrapping_mul(PRIME32_1) |
361 | 4.38G | } Unexecuted instantiation: twox_hash::xxhash32::round twox_hash::xxhash32::round Line | Count | Source | 357 | 4.36G | const fn round(mut acc: u32, lane: u32) -> u32 { | 358 | 4.36G | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_2)); | 359 | 4.36G | acc = acc.rotate_left(13); | 360 | 4.36G | acc.wrapping_mul(PRIME32_1) | 361 | 4.36G | } |
Unexecuted instantiation: twox_hash::xxhash32::round twox_hash::xxhash32::round Line | Count | Source | 357 | 18.5M | const fn round(mut acc: u32, lane: u32) -> u32 { | 358 | 18.5M | acc = acc.wrapping_add(lane.wrapping_mul(PRIME32_2)); | 359 | 18.5M | acc = acc.rotate_left(13); | 360 | 18.5M | acc.wrapping_mul(PRIME32_1) | 361 | 18.5M | } |
|
362 | | |
363 | | /// Constructs [`Hasher`][] for multiple hasher instances. See |
364 | | /// the [usage warning][Hasher#caution]. |
365 | | #[derive(Clone)] |
366 | | pub struct State(u32); |
367 | | |
368 | | impl State { |
369 | | /// Constructs the hasher with an initial seed. |
370 | 0 | pub fn with_seed(seed: u32) -> Self { |
371 | 0 | Self(seed) |
372 | 0 | } |
373 | | } |
374 | | |
375 | | impl BuildHasher for State { |
376 | | type Hasher = Hasher; |
377 | | |
378 | 0 | fn build_hasher(&self) -> Self::Hasher { |
379 | 0 | Hasher::with_seed(self.0) |
380 | 0 | } |
381 | | } |
382 | | |
383 | | #[cfg(test)] |
384 | | mod test { |
385 | | use core::{ |
386 | | array, |
387 | | hash::{BuildHasherDefault, Hasher as _}, |
388 | | }; |
389 | | use std::collections::HashMap; |
390 | | |
391 | | use super::*; |
392 | | |
393 | | const _TRAITS: () = { |
394 | | const fn is_clone<T: Clone>() {} |
395 | | is_clone::<Hasher>(); |
396 | | is_clone::<State>(); |
397 | | }; |
398 | | |
399 | | const EMPTY_BYTES: [u8; 0] = []; |
400 | | |
401 | | #[test] |
402 | | fn ingesting_byte_by_byte_is_equivalent_to_large_chunks() { |
403 | | let bytes = [0; 32]; |
404 | | |
405 | | let mut byte_by_byte = Hasher::with_seed(0); |
406 | | for byte in bytes.chunks(1) { |
407 | | byte_by_byte.write(byte); |
408 | | } |
409 | | let byte_by_byte = byte_by_byte.finish(); |
410 | | |
411 | | let mut one_chunk = Hasher::with_seed(0); |
412 | | one_chunk.write(&bytes); |
413 | | let one_chunk = one_chunk.finish(); |
414 | | |
415 | | assert_eq!(byte_by_byte, one_chunk); |
416 | | } |
417 | | |
418 | | #[test] |
419 | | fn hash_of_nothing_matches_c_implementation() { |
420 | | let mut hasher = Hasher::with_seed(0); |
421 | | hasher.write(&EMPTY_BYTES); |
422 | | assert_eq!(hasher.finish(), 0x02cc_5d05); |
423 | | } |
424 | | |
425 | | #[test] |
426 | | fn hash_of_single_byte_matches_c_implementation() { |
427 | | let mut hasher = Hasher::with_seed(0); |
428 | | hasher.write(&[42]); |
429 | | assert_eq!(hasher.finish(), 0xe0fe_705f); |
430 | | } |
431 | | |
432 | | #[test] |
433 | | fn hash_of_multiple_bytes_matches_c_implementation() { |
434 | | let mut hasher = Hasher::with_seed(0); |
435 | | hasher.write(b"Hello, world!\0"); |
436 | | assert_eq!(hasher.finish(), 0x9e5e_7e93); |
437 | | } |
438 | | |
439 | | #[test] |
440 | | fn hash_of_multiple_chunks_matches_c_implementation() { |
441 | | let bytes: [u8; 100] = array::from_fn(|i| i as u8); |
442 | | let mut hasher = Hasher::with_seed(0); |
443 | | hasher.write(&bytes); |
444 | | assert_eq!(hasher.finish(), 0x7f89_ba44); |
445 | | } |
446 | | |
447 | | #[test] |
448 | | fn hash_with_different_seed_matches_c_implementation() { |
449 | | let mut hasher = Hasher::with_seed(0x42c9_1977); |
450 | | hasher.write(&EMPTY_BYTES); |
451 | | assert_eq!(hasher.finish(), 0xd6bf_8459); |
452 | | } |
453 | | |
454 | | #[test] |
455 | | fn hash_with_different_seed_and_multiple_chunks_matches_c_implementation() { |
456 | | let bytes: [u8; 100] = array::from_fn(|i| i as u8); |
457 | | let mut hasher = Hasher::with_seed(0x42c9_1977); |
458 | | hasher.write(&bytes); |
459 | | assert_eq!(hasher.finish(), 0x6d2f_6c17); |
460 | | } |
461 | | |
462 | | #[test] |
463 | | fn hashes_with_different_offsets_are_the_same() { |
464 | | let bytes = [0x7c; 4096]; |
465 | | let expected = Hasher::oneshot(0, &[0x7c; 64]); |
466 | | |
467 | | let the_same = bytes |
468 | | .windows(64) |
469 | | .map(|w| { |
470 | | let mut hasher = Hasher::with_seed(0); |
471 | | hasher.write(w); |
472 | | hasher.finish_32() |
473 | | }) |
474 | | .all(|h| h == expected); |
475 | | assert!(the_same); |
476 | | } |
477 | | |
478 | | // This test validates wraparound/truncation behavior for very |
479 | | // large inputs of a 32-bit hash, but runs very slowly in the |
480 | | // normal "cargo test" build config since it hashes 4.3GB of |
481 | | // data. It runs reasonably quick under "cargo test --release". |
482 | | #[ignore] |
483 | | #[test] |
484 | | fn length_overflows_32bit() { |
485 | | // Hash 4.3 billion (4_300_000_000) bytes, which overflows a u32. |
486 | | let bytes200: [u8; 200] = array::from_fn(|i| i as _); |
487 | | |
488 | | let mut hasher = Hasher::with_seed(0); |
489 | | for _ in 0..(4_300_000_000 / bytes200.len()) { |
490 | | hasher.write(&bytes200); |
491 | | } |
492 | | |
493 | | assert_eq!(hasher.total_len(), 0x0000_0001_004c_cb00); |
494 | | assert_eq!(hasher.total_len_32(), 0x004c_cb00); |
495 | | |
496 | | // compared against the C implementation |
497 | | assert_eq!(hasher.finish(), 0x1522_4ca7); |
498 | | } |
499 | | |
500 | | #[test] |
501 | | fn can_be_used_in_a_hashmap_with_a_default_seed() { |
502 | | let mut hash: HashMap<_, _, BuildHasherDefault<Hasher>> = Default::default(); |
503 | | hash.insert(42, "the answer"); |
504 | | assert_eq!(hash.get(&42), Some(&"the answer")); |
505 | | } |
506 | | } |
507 | | |
508 | | #[cfg(feature = "random")] |
509 | | #[cfg_attr(docsrs, doc(cfg(feature = "random")))] |
510 | | mod random_impl { |
511 | | use super::*; |
512 | | |
513 | | /// Constructs a randomized seed and reuses it for multiple hasher |
514 | | /// instances. See the [usage warning][Hasher#caution]. |
515 | | #[derive(Clone)] |
516 | | pub struct RandomState(State); |
517 | | |
518 | | impl Default for RandomState { |
519 | | fn default() -> Self { |
520 | | Self::new() |
521 | | } |
522 | | } |
523 | | |
524 | | impl RandomState { |
525 | | fn new() -> Self { |
526 | | Self(State::with_seed(rand::random())) |
527 | | } |
528 | | } |
529 | | |
530 | | impl BuildHasher for RandomState { |
531 | | type Hasher = Hasher; |
532 | | |
533 | | fn build_hasher(&self) -> Self::Hasher { |
534 | | self.0.build_hasher() |
535 | | } |
536 | | } |
537 | | |
538 | | #[cfg(test)] |
539 | | mod test { |
540 | | use std::collections::HashMap; |
541 | | |
542 | | use super::*; |
543 | | |
544 | | const _: () = { |
545 | | const fn is_clone<T: Clone>() {} |
546 | | is_clone::<Hasher>(); |
547 | | is_clone::<RandomState>(); |
548 | | }; |
549 | | |
550 | | #[test] |
551 | | fn can_be_used_in_a_hashmap_with_a_random_seed() { |
552 | | let mut hash: HashMap<_, _, RandomState> = Default::default(); |
553 | | hash.insert(42, "the answer"); |
554 | | assert_eq!(hash.get(&42), Some(&"the answer")); |
555 | | } |
556 | | } |
557 | | } |
558 | | |
559 | | #[cfg(feature = "random")] |
560 | | #[cfg_attr(docsrs, doc(cfg(feature = "random")))] |
561 | | pub use random_impl::*; |
562 | | |
563 | | #[cfg(feature = "serialize")] |
564 | | #[cfg_attr(docsrs, doc(cfg(feature = "serialize")))] |
565 | | mod serialize_impl { |
566 | | use serde::{Deserialize, Serialize}; |
567 | | |
568 | | use super::*; |
569 | | |
570 | | impl<'de> Deserialize<'de> for Hasher { |
571 | | fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> |
572 | | where |
573 | | D: serde::Deserializer<'de>, |
574 | | { |
575 | | let shim = Deserialize::deserialize(deserializer)?; |
576 | | |
577 | | let Shim { |
578 | | total_len, |
579 | | seed, |
580 | | core, |
581 | | buffer, |
582 | | buffer_usage, |
583 | | } = shim; |
584 | | let Core { v1, v2, v3, v4 } = core; |
585 | | |
586 | | let mut buffer_data = BufferData::new(); |
587 | | buffer_data.bytes_mut().copy_from_slice(&buffer); |
588 | | |
589 | | Ok(Hasher { |
590 | | seed, |
591 | | accumulators: Accumulators([v1, v2, v3, v4]), |
592 | | buffer: Buffer { |
593 | | offset: buffer_usage, |
594 | | data: buffer_data, |
595 | | }, |
596 | | length: total_len, |
597 | | }) |
598 | | } |
599 | | } |
600 | | |
601 | | impl Serialize for Hasher { |
602 | | fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> |
603 | | where |
604 | | S: serde::Serializer, |
605 | | { |
606 | | let Hasher { |
607 | | seed, |
608 | | ref accumulators, |
609 | | ref buffer, |
610 | | length, |
611 | | } = *self; |
612 | | let [v1, v2, v3, v4] = accumulators.0; |
613 | | let Buffer { offset, ref data } = *buffer; |
614 | | let buffer = *data.bytes(); |
615 | | |
616 | | let shim = Shim { |
617 | | total_len: length, |
618 | | seed, |
619 | | core: Core { v1, v2, v3, v4 }, |
620 | | buffer, |
621 | | buffer_usage: offset, |
622 | | }; |
623 | | |
624 | | shim.serialize(serializer) |
625 | | } |
626 | | } |
627 | | |
628 | | #[derive(Serialize, Deserialize)] |
629 | | struct Shim { |
630 | | total_len: u64, |
631 | | seed: u32, |
632 | | core: Core, |
633 | | buffer: [u8; 16], |
634 | | buffer_usage: usize, |
635 | | } |
636 | | |
637 | | #[derive(Serialize, Deserialize)] |
638 | | struct Core { |
639 | | v1: u32, |
640 | | v2: u32, |
641 | | v3: u32, |
642 | | v4: u32, |
643 | | } |
644 | | |
645 | | #[cfg(test)] |
646 | | mod test { |
647 | | use std::hash::Hasher as _; |
648 | | |
649 | | use super::*; |
650 | | |
651 | | type Result<T = (), E = serde_json::Error> = core::result::Result<T, E>; |
652 | | |
653 | | #[test] |
654 | | fn test_serialization_cycle() -> Result { |
655 | | let mut hasher = Hasher::with_seed(0); |
656 | | hasher.write(b"Hello, world!\0"); |
657 | | let _ = hasher.finish(); |
658 | | |
659 | | let serialized = serde_json::to_string(&hasher)?; |
660 | | let unserialized: Hasher = serde_json::from_str(&serialized)?; |
661 | | assert_eq!(hasher, unserialized); |
662 | | Ok(()) |
663 | | } |
664 | | |
665 | | #[test] |
666 | | fn test_serialization_stability() -> Result { |
667 | | let mut hasher = Hasher::with_seed(0); |
668 | | hasher.write(b"Hello, world!\0"); |
669 | | let _ = hasher.finish(); |
670 | | |
671 | | let expected_serialized = r#"{ |
672 | | "total_len": 14, |
673 | | "seed": 0, |
674 | | "core": { |
675 | | "v1": 606290984, |
676 | | "v2": 2246822519, |
677 | | "v3": 0, |
678 | | "v4": 1640531535 |
679 | | }, |
680 | | "buffer": [ |
681 | | 72, 101, 108, 108, 111, 44, 32, 119, |
682 | | 111, 114, 108, 100, 33, 0, 0, 0 |
683 | | ], |
684 | | "buffer_usage": 14 |
685 | | }"#; |
686 | | |
687 | | let unserialized: Hasher = serde_json::from_str(expected_serialized)?; |
688 | | assert_eq!(hasher, unserialized); |
689 | | |
690 | | let expected_value: serde_json::Value = serde_json::from_str(expected_serialized)?; |
691 | | let actual_value = serde_json::to_value(&hasher)?; |
692 | | assert_eq!(expected_value, actual_value); |
693 | | |
694 | | Ok(()) |
695 | | } |
696 | | } |
697 | | } |