projected_hash_map/
lib.rs1use std::borrow::Borrow;
2use std::collections::HashSet;
3use std::hash::{Hash, Hasher};
4use std::marker::PhantomData;
5
6#[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 pub fn get(&self, key: &T) -> Option<&V> {
74 self.repr.get(key).map(|v| &v.inner)
75 }
76
77 pub fn insert(&mut self, edge: V) {
79 self.repr.replace(HashMapHelper { inner: edge, pd: PhantomData });
80 }
81
82 #[must_use]
84 pub fn is_empty(&self) -> bool {
85 self.repr.is_empty()
86 }
87
88 pub fn iter(&self) -> impl Iterator<Item = &V> + '_ {
90 self.repr.iter().map(|it| &it.inner)
91 }
92
93 #[must_use]
95 pub fn len(&self) -> usize {
96 self.repr.len()
97 }
98
99 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