projected_hash_map/
lib.rs

1use std::borrow::Borrow;
2use std::collections::HashSet;
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5
6///
7#[derive(std::cmp::Eq)]
8pub struct HashMapHelper<T, V>
9    where
10        V: Borrow<T>,
11        T: Hash + PartialEq + Eq,
12{
13    inner: V,
14    pd: PhantomData<T>,
15}
16
17impl<T, V> Borrow<T> for HashMapHelper<T, V>
18    where
19        V: Borrow<T>,
20        T: Hash + PartialEq + Eq,
21{
22    fn borrow(&self) -> &T {
23        self.inner.borrow()
24    }
25}
26
27impl<T, V> PartialEq for HashMapHelper<T, V>
28    where
29        V: Borrow<T>,
30        T: Hash + PartialEq + Eq,
31{
32    fn eq(&self, other: &Self) -> bool {
33        self.inner.borrow() == other.inner.borrow()
34    }
35}
36
37impl<T, V> Hash for HashMapHelper<T, V>
38    where
39        V: Borrow<T>,
40        T: Hash + PartialEq + Eq,
41{
42    fn hash<H: Hasher>(&self, state: &mut H) {
43        self.inner.borrow().hash(state);
44    }
45}
46
47pub struct ProjectedHashMap<T, V>
48    where
49        V: Borrow<T>,
50        T: Hash + PartialEq + Eq,
51{
52    pd: PhantomData<T>,
53    repr: HashSet<HashMapHelper<T, V>>,
54}
55
56impl<T, V> Default for ProjectedHashMap<T, V>
57    where
58        V: Borrow<T>,
59        T: Hash + PartialEq + Eq,
60{
61    fn default() -> Self {
62        Self { repr: HashSet::new(), pd: PhantomData }
63    }
64}
65
66impl<T, V> ProjectedHashMap<T, V>
67    where
68        V: Borrow<T>,
69        T: Hash + PartialEq + Eq,
70        HashMapHelper<T, V>: Eq,
71{
72    /// Gets element
73    pub fn get(&self, key: &T) -> Option<&V> {
74        self.repr.get(key).map(|v| &v.inner)
75    }
76
77    /// The insert inside `HashSet`, will not remove existing element if it has the same key.
78    pub fn insert(&mut self, edge: V) {
79        self.repr.replace(HashMapHelper { inner: edge, pd: PhantomData });
80    }
81
82    /// Checks if empty.
83    #[must_use]
84    pub fn is_empty(&self) -> bool {
85        self.repr.is_empty()
86    }
87
88    /// Gets iterator
89    pub fn iter(&self) -> impl Iterator<Item = &V> + '_ {
90        self.repr.iter().map(|it| &it.inner)
91    }
92
93    /// Gets length
94    #[must_use]
95    pub fn len(&self) -> usize {
96        self.repr.len()
97    }
98
99    /// Removes element
100    pub fn remove(&mut self, key: &T) -> bool {
101        self.repr.remove(key)
102    }
103}
104
105#[cfg(test)]
106mod tests {
107    use super::*;
108
109    #[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
110    struct User {
111        height: usize,
112        name: String,
113        weight: usize,
114    }
115
116    impl User {
117        fn new(name: String) -> Self {
118            Self {
119                name,
120                height: 12,
121                weight: 12,
122            }
123        }
124    }
125
126    impl Borrow<String> for User {
127        fn borrow(&self) -> &String {
128            &self.name
129        }
130    }
131
132    #[test]
133    fn test_hashset() {
134        let p1 = "p1".to_string();
135        let p2 = "p2".to_string();
136        let p3 = "p3".to_string();
137        let e0 = User::new(p1.clone());
138        let e1 = User::new(p2);
139        let e2 = User::new(p3);
140        let e3 = User::new(p1);
141
142        let mut se = ProjectedHashMap::default();
143        se.insert(e0.clone());
144        se.insert(e1);
145        se.insert(e2);
146        se.insert(e3.clone());
147
148        let key3 = e3.name.clone();
149        let key0 = e0.name.clone();
150
151        assert_eq!(se.get(&key3).unwrap(), &e3);
152        assert_eq!(se.get(&key0).unwrap(), &e0);
153    }
154
155    #[test]
156    fn test_remove_key() {
157        let p1 = "p1".to_string();
158        let p2 = "p2".to_string();
159        let e1 = User::new(p1);
160        let e2 = User::new(p2);
161        let mut se = ProjectedHashMap::default();
162        se.insert(e2.clone());
163
164        let key = e1.name.clone();
165        se.insert(e1.clone());
166        assert_eq!(se.get(&key).unwrap(), &e1);
167        se.remove(&e1.name);
168        assert_eq!(se.get(&key), None);
169
170        let key2 = e2.name.clone();
171        assert_eq!(se.get(&key2).unwrap(), &e2);
172    }
173}
174