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}