1use std::collections::{BTreeMap, BTreeSet, BinaryHeap, LinkedList, VecDeque};
36
37use futures::future::{FutureExt, TryFutureExt};
38use futures::stream::{Stream, StreamExt, TryStream, TryStreamExt};
39
40pub use sha2::digest::generic_array;
41pub use sha2::digest::{Digest, Output};
42pub use sha2::Sha256;
43
44#[cfg(test)]
45mod tests {
46 use super::*;
47
48 #[test]
49 fn hash_equivalence_string_and_bytes() {
50 let s = "hello";
51 let from_str = Hash::<Sha256>::hash(s);
52 let from_string = Hash::<Sha256>::hash(s.to_string());
53
54 assert_eq!(from_str, from_string);
55 }
56
57 #[test]
58 fn hash_empty_matches_default() {
59 let empty_vec: Vec<u8> = Vec::new();
60 let empty_str = "";
61 let empty_opt: Option<u8> = None;
62
63 assert_eq!(Hash::<Sha256>::hash(empty_vec), default_hash::<Sha256>());
64 assert_ne!(Hash::<Sha256>::hash(empty_str), default_hash::<Sha256>());
65 assert_eq!(Hash::<Sha256>::hash(empty_opt), default_hash::<Sha256>());
66 }
67
68 #[test]
69 fn hash_sequence_is_order_sensitive() {
70 let a = vec![1u8, 2, 3];
71 let b = vec![3u8, 2, 1];
72
73 let hash_a = Hash::<Sha256>::hash(a);
74 let hash_b = Hash::<Sha256>::hash(b);
75
76 assert_ne!(hash_a, hash_b);
77 }
78}
79
80pub trait Hash<D: Digest>: Sized {
82 fn hash(self) -> Output<D>;
84}
85
86impl<D: Digest> Hash<D> for () {
87 fn hash(self) -> Output<D> {
88 default_hash::<D>()
89 }
90}
91
92impl<D: Digest> Hash<D> for bool {
93 fn hash(self) -> Output<D> {
94 D::digest([self as u8])
95 }
96}
97
98macro_rules! hash_number {
99 ($n:literal, $ty:ty) => {
100 impl<D: Digest> Hash<D> for $ty {
101 fn hash(self) -> Output<D> {
102 D::digest(self.to_be_bytes())
103 }
104 }
105 };
106}
107
108hash_number!(4, f32);
109hash_number!(8, f64);
110hash_number!(1, i8);
111hash_number!(2, i16);
112hash_number!(4, i32);
113hash_number!(8, i64);
114hash_number!(16, i128);
115hash_number!(1, u8);
116hash_number!(2, u16);
117hash_number!(4, u32);
118hash_number!(8, u64);
119hash_number!(16, u128);
120
121impl<D: Digest> Hash<D> for isize {
122 fn hash(self) -> Output<D> {
123 Hash::<D>::hash(self as i64)
124 }
125}
126
127impl<D: Digest> Hash<D> for usize {
128 fn hash(self) -> Output<D> {
129 Hash::<D>::hash(self as u64)
130 }
131}
132
133impl<D: Digest> Hash<D> for &str {
134 fn hash(self) -> Output<D> {
135 D::digest(self.as_bytes())
136 }
137}
138
139impl<D: Digest> Hash<D> for String {
140 fn hash(self) -> Output<D> {
141 Hash::<D>::hash(self.as_str())
142 }
143}
144
145impl<D: Digest> Hash<D> for &String {
146 fn hash(self) -> Output<D> {
147 Hash::<D>::hash(self.as_str())
148 }
149}
150
151impl<D: Digest, T: Hash<D>> Hash<D> for Option<T> {
152 fn hash(self) -> Output<D> {
153 if let Some(value) = self {
154 value.hash()
155 } else {
156 default_hash::<D>()
157 }
158 }
159}
160
161macro_rules! hash_tuple {
162 ($($len:expr => ($($n:tt $name:ident)+))+) => {
163 $(
164 impl<D: Digest, $($name),+> Hash<D> for ($($name,)+)
165 where
166 $($name: Hash<D>,)+
167 {
168 fn hash(self) -> Output<D> {
169 let mut hasher = D::new();
170 $(
171 let hash = self.$n.hash();
172 hasher.update(hash);
173 )+
174 hasher.finalize()
175 }
176 }
177
178 impl<'a, D: Digest, $($name),+> Hash<D> for &'a ($($name,)+)
179 where
180 $(&'a $name: Hash<D>,)+
181 {
182 fn hash(self) -> Output<D> {
183 let mut hasher = D::new();
184 $(
185 let hash = self.$n.hash();
186 hasher.update(hash);
187 )+
188 hasher.finalize()
189 }
190 }
191 )+
192 }
193}
194
195hash_tuple! {
196 1 => (0 T0)
197 2 => (0 T0 1 T1)
198 3 => (0 T0 1 T1 2 T2)
199 4 => (0 T0 1 T1 2 T2 3 T3)
200 5 => (0 T0 1 T1 2 T2 3 T3 4 T4)
201 6 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5)
202 7 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6)
203 8 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7)
204 9 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8)
205 10 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9)
206 11 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10)
207 12 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11)
208 13 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12)
209 14 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13)
210 15 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14)
211 16 => (0 T0 1 T1 2 T2 3 T3 4 T4 5 T5 6 T6 7 T7 8 T8 9 T9 10 T10 11 T11 12 T12 13 T13 14 T14 15 T15)
212}
213
214impl<D: Digest, T: Hash<D>> Hash<D> for [T; 0] {
215 fn hash(self) -> Output<D> {
216 default_hash::<D>()
217 }
218}
219
220macro_rules! hash_array {
221 ($($len:tt)+) => {
222 $(
223 impl<D: Digest, T: Hash<D>> Hash<D> for [T; $len] {
224 fn hash(self) -> Output<D> {
225 if self.is_empty() {
226 return default_hash::<D>();
227 }
228
229 let mut hasher = D::new();
230
231 for item in self {
232 hasher.update(item.hash());
233 }
234
235 hasher.finalize()
236 }
237 }
238 )+
239 }
240}
241
242hash_array! {
243 1 2 3 4 5 6 7 8 9 10
244 11 12 13 14 15 16 17 18 19 20
245 21 22 23 24 25 26 27 28 29 30
246 31 32
247}
248
249macro_rules! hash_seq {
250 ($ty:ty) => {
251 impl<D: Digest, T: Hash<D>> Hash<D> for $ty {
252 fn hash(self) -> Output<D> {
253 if self.is_empty() {
254 return default_hash::<D>();
255 }
256
257 let mut hasher = D::new();
258
259 for item in self.into_iter() {
260 hasher.update(item.hash());
261 }
262
263 hasher.finalize()
264 }
265 }
266
267 impl<'a, D, T> Hash<D> for &'a $ty
268 where
269 D: Digest,
270 &'a T: Hash<D>,
271 {
272 fn hash(self) -> Output<D> {
273 if self.is_empty() {
274 return default_hash::<D>();
275 }
276
277 let mut hasher = D::new();
278 for item in self.into_iter() {
279 hasher.update(item.hash());
280 }
281 hasher.finalize()
282 }
283 }
284 };
285}
286
287hash_seq!(BTreeSet<T>);
288hash_seq!(BinaryHeap<T>);
289hash_seq!(LinkedList<T>);
290hash_seq!(Vec<T>);
291hash_seq!(VecDeque<T>);
292
293#[cfg(feature = "smallvec")]
294impl<const N: usize, D: Digest, T> Hash<D> for smallvec::SmallVec<[T; N]>
295where
296 [T; N]: smallvec::Array,
297 <smallvec::SmallVec<[T; N]> as IntoIterator>::Item: Hash<D>,
298{
299 fn hash(self) -> Output<D> {
300 if self.is_empty() {
301 return default_hash::<D>();
302 }
303
304 let mut hasher = D::new();
305
306 for item in self.into_iter() {
307 hasher.update(item.hash());
308 }
309
310 hasher.finalize()
311 }
312}
313
314#[cfg(feature = "smallvec")]
315impl<'a, const N: usize, D: Digest, T> Hash<D> for &'a smallvec::SmallVec<[T; N]>
316where
317 [T; N]: smallvec::Array,
318 <&'a smallvec::SmallVec<[T; N]> as IntoIterator>::Item: Hash<D>,
319{
320 fn hash(self) -> Output<D> {
321 if self.is_empty() {
322 return default_hash::<D>();
323 }
324
325 let mut hasher = D::new();
326
327 for item in self.into_iter() {
328 hasher.update(item.hash());
329 }
330
331 hasher.finalize()
332 }
333}
334
335impl<D: Digest, K: Hash<D>, V: Hash<D>> Hash<D> for BTreeMap<K, V> {
336 fn hash(self) -> Output<D> {
337 if self.is_empty() {
338 return default_hash::<D>();
339 }
340
341 let mut hasher = D::new();
342
343 for item in self {
344 hasher.update(item.hash());
345 }
346
347 hasher.finalize()
348 }
349}
350
351impl<'a, D, K, V> Hash<D> for &'a BTreeMap<K, V>
352where
353 D: Digest,
354 &'a K: Hash<D>,
355 &'a V: Hash<D>,
356{
357 fn hash(self) -> Output<D> {
358 if self.is_empty() {
359 return default_hash::<D>();
360 }
361
362 let mut hasher = D::new();
363
364 for item in self {
365 hasher.update(item.hash());
366 }
367
368 hasher.finalize()
369 }
370}
371
372pub async fn hash_stream<D, T, S>(stream: S) -> Output<D>
374where
375 D: Digest,
376 T: Hash<D>,
377 S: Stream<Item = T>,
378{
379 stream
380 .map(|item| Hash::<D>::hash(item))
381 .fold(D::new(), |mut hasher, hash| {
382 hasher.update(hash);
383 futures::future::ready(hasher)
384 })
385 .map(|hasher| hasher.finalize())
386 .await
387}
388
389pub async fn hash_try_stream<D, T, E, S>(stream: S) -> Result<Output<D>, E>
391where
392 D: Digest,
393 T: Hash<D>,
394 E: std::error::Error,
395 S: TryStream<Ok = T, Error = E>,
396{
397 stream
398 .map_ok(|item| Hash::<D>::hash(item))
399 .try_fold(D::new(), |mut hasher, hash| {
400 hasher.update(hash);
401 futures::future::ready(Ok(hasher))
402 })
403 .map_ok(|hasher| hasher.finalize())
404 .await
405}
406
407pub fn default_hash<D: Digest>() -> Output<D> {
409 generic_array::GenericArray::default()
410}