hash_of/
lib.rs

1use std::borrow::Borrow;
2use std::collections::hash_map::DefaultHasher;
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5
6#[derive(Debug)]
7pub struct HashOf<T, H: Hasher = DefaultHasher> {
8    hash: u64,
9    _marker: PhantomData<*const (T, H)>, // Indicate we do not own anything
10}
11
12// Manually implementing some traits because they are not implemented when T or H do not
13// implement them. In particular, DefaultHasher doesn't implement PartialEq
14impl<T, H: Hasher> PartialEq for HashOf<T, H> {
15    #[inline]
16    fn eq(&self, other: &Self) -> bool {
17        self.hash == other.hash
18    }
19}
20
21impl<T, H: Hasher> Eq for HashOf<T, H> {}
22
23impl<T, H: Hasher> Hash for HashOf<T, H> {
24    #[inline]
25    fn hash<H2: Hasher>(&self, state: &mut H2) {
26        state.write_u64(self.hash)
27    }
28}
29
30impl<T> Clone for HashOf<T> {
31    #[inline]
32    fn clone(&self) -> Self {
33        *self
34    }
35}
36
37impl<T> Copy for HashOf<T> {}
38
39impl<T> HashOf<T> {
40    #[inline]
41    pub fn to_inner(self) -> u64 {
42        self.hash
43    }
44}
45
46// Example types to explain the confusing signature...
47// T: str
48// Q: String
49impl<T: Hash + ?Sized, Q: Borrow<T>, H: Hasher + Default> From<&T> for HashOf<Q, H> {
50    fn from(value: &T) -> Self {
51        let mut hasher = H::default();
52        value.hash(&mut hasher);
53        Self {
54            hash: hasher.finish(),
55            _marker: PhantomData,
56        }
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63
64    #[test]
65    fn borrow_hash_eq() {
66        let x = HashOf::<String>::from("test");
67        let s2 = String::new() + "test";
68        let y = HashOf::from(&s2);
69        assert_eq!(x, y);
70    }
71
72    #[test]
73    fn can_hash_non_borrow() {
74        // TODO: Have this work for non-borrow
75        let x = HashOf::<u32>::from(&0);
76        assert_ne!(x.to_inner(), 0);
77    }
78}