json_ld_core/utils/hash.rs
1use std::collections::hash_map::DefaultHasher;
2use std::hash::{Hash, Hasher};
3
4/// Hash a set of items.
5///
6/// The standard library does not provide (yet) a `Hash` implementation
7/// for set types. This can be used instead.
8///
9/// Note that this function not particularly strong and does
10/// not protect against DoS attacks.
11pub fn hash_set<S: IntoIterator, H: Hasher>(set: S, hasher: &mut H)
12where
13 S::Item: Hash,
14{
15 // See: https://github.com/rust-lang/rust/pull/48366
16 // Elements must be combined with a associative and commutative operation •.
17 // (u64, •, 0) must form a commutative monoid.
18 // This is satisfied by • = u64::wrapping_add.
19 let mut hash = 0;
20 for item in set {
21 let mut h = DefaultHasher::new();
22 item.hash(&mut h);
23 hash = u64::wrapping_add(hash, h.finish());
24 }
25
26 hasher.write_u64(hash);
27}
28
29/// Hash an optional set of items.
30pub fn hash_set_opt<S: IntoIterator, H: Hasher>(set_opt: Option<S>, hasher: &mut H)
31where
32 S::Item: Hash,
33{
34 if let Some(set) = set_opt {
35 hash_set(set, hasher)
36 }
37}
38
39/// Hash a map.
40///
41/// The standard library does not provide (yet) a `Hash` implementation
42/// for unordered map types. This can be used instead.
43///
44/// Note that this function not particularly strong and does
45/// not protect against DoS attacks.
46pub fn hash_map<'a, K: 'a + Hash, V: 'a + Hash, H: Hasher>(
47 map: impl 'a + IntoIterator<Item = (&'a K, &'a V)>,
48 hasher: &mut H,
49) {
50 // See: https://github.com/rust-lang/rust/pull/48366
51 // Elements must be combined with a associative and commutative operation •.
52 // (u64, •, 0) must form a commutative monoid.
53 // This is satisfied by • = u64::wrapping_add.
54 let mut hash = 0;
55 for entry in map {
56 let mut h = DefaultHasher::new();
57 entry.hash(&mut h);
58 hash = u64::wrapping_add(hash, h.finish());
59 }
60
61 hasher.write_u64(hash);
62}