Skip to main content

dynomite/util/
dict.rs

1//! Typed hash-map wrappers over [`ahash::AHashMap`].
2//!
3//! The engine needs a small generic hash map plus a specialized
4//! variant keyed on [`MsgId`] for the in-flight message index. Both
5//! are thin wrappers around [`ahash::AHashMap`] that expose only the
6//! operations the rest of the engine actually uses.
7
8use std::collections::hash_map::IntoIter;
9use std::hash::Hash;
10
11use ahash::AHashMap;
12
13use crate::core::types::MsgId;
14
15/// Generic typed map keyed by `K` with an [`ahash`] hasher.
16///
17/// The wrapper exposes the small set of operations used by the rest
18/// of the engine and intentionally hides the underlying hasher and
19/// table layout. Use [`DictMap::iter`] for read-only traversal and
20/// [`DictMap::drain`] when you need to consume the entire map.
21///
22/// # Examples
23///
24/// ```
25/// use dynomite::util::dict::DictMap;
26///
27/// let mut m: DictMap<&'static str, u32> = DictMap::new();
28/// m.insert("k", 7);
29/// assert_eq!(m.get(&"k"), Some(&7));
30/// assert_eq!(m.len(), 1);
31/// assert!(m.remove(&"k").is_some());
32/// assert!(m.is_empty());
33/// ```
34#[derive(Debug, Default, Clone)]
35pub struct DictMap<K: Eq + Hash, V> {
36    inner: AHashMap<K, V>,
37}
38
39impl<K: Eq + Hash, V> DictMap<K, V> {
40    /// Construct an empty map.
41    ///
42    /// # Examples
43    ///
44    /// ```
45    /// use dynomite::util::dict::DictMap;
46    /// let m: DictMap<u32, u32> = DictMap::new();
47    /// assert!(m.is_empty());
48    /// ```
49    pub fn new() -> Self {
50        Self {
51            inner: AHashMap::new(),
52        }
53    }
54
55    /// Construct an empty map with at least `capacity` slots.
56    ///
57    /// # Examples
58    ///
59    /// ```
60    /// use dynomite::util::dict::DictMap;
61    /// let m: DictMap<u32, u32> = DictMap::with_capacity(8);
62    /// assert!(m.is_empty());
63    /// ```
64    pub fn with_capacity(capacity: usize) -> Self {
65        Self {
66            inner: AHashMap::with_capacity(capacity),
67        }
68    }
69
70    /// Insert `value` at `key`, returning the previous value (if any).
71    ///
72    /// # Examples
73    ///
74    /// ```
75    /// use dynomite::util::dict::DictMap;
76    /// let mut m: DictMap<u32, u32> = DictMap::new();
77    /// assert_eq!(m.insert(1, 10), None);
78    /// assert_eq!(m.insert(1, 20), Some(10));
79    /// ```
80    pub fn insert(&mut self, key: K, value: V) -> Option<V> {
81        self.inner.insert(key, value)
82    }
83
84    /// Remove and return the value at `key`.
85    ///
86    /// # Examples
87    ///
88    /// ```
89    /// use dynomite::util::dict::DictMap;
90    /// let mut m: DictMap<u32, u32> = DictMap::new();
91    /// m.insert(1, 10);
92    /// assert_eq!(m.remove(&1), Some(10));
93    /// assert_eq!(m.remove(&1), None);
94    /// ```
95    pub fn remove(&mut self, key: &K) -> Option<V> {
96        self.inner.remove(key)
97    }
98
99    /// Look up an immutable reference to the value at `key`.
100    ///
101    /// # Examples
102    ///
103    /// ```
104    /// use dynomite::util::dict::DictMap;
105    /// let mut m: DictMap<u32, u32> = DictMap::new();
106    /// m.insert(1, 10);
107    /// assert_eq!(m.get(&1), Some(&10));
108    /// ```
109    pub fn get(&self, key: &K) -> Option<&V> {
110        self.inner.get(key)
111    }
112
113    /// Look up a mutable reference to the value at `key`.
114    ///
115    /// # Examples
116    ///
117    /// ```
118    /// use dynomite::util::dict::DictMap;
119    /// let mut m: DictMap<u32, u32> = DictMap::new();
120    /// m.insert(1, 10);
121    /// *m.get_mut(&1).unwrap() = 20;
122    /// assert_eq!(m.get(&1), Some(&20));
123    /// ```
124    pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
125        self.inner.get_mut(key)
126    }
127
128    /// Whether `key` is in the map.
129    ///
130    /// # Examples
131    ///
132    /// ```
133    /// use dynomite::util::dict::DictMap;
134    /// let mut m: DictMap<u32, u32> = DictMap::new();
135    /// m.insert(1, 10);
136    /// assert!(m.contains_key(&1));
137    /// assert!(!m.contains_key(&2));
138    /// ```
139    pub fn contains_key(&self, key: &K) -> bool {
140        self.inner.contains_key(key)
141    }
142
143    /// Number of entries.
144    ///
145    /// # Examples
146    ///
147    /// ```
148    /// use dynomite::util::dict::DictMap;
149    /// let mut m: DictMap<u32, u32> = DictMap::new();
150    /// m.insert(1, 10);
151    /// assert_eq!(m.len(), 1);
152    /// ```
153    pub fn len(&self) -> usize {
154        self.inner.len()
155    }
156
157    /// Whether the map is empty.
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// use dynomite::util::dict::DictMap;
163    /// let m: DictMap<u32, u32> = DictMap::new();
164    /// assert!(m.is_empty());
165    /// ```
166    pub fn is_empty(&self) -> bool {
167        self.inner.is_empty()
168    }
169
170    /// Drop every entry.
171    ///
172    /// # Examples
173    ///
174    /// ```
175    /// use dynomite::util::dict::DictMap;
176    /// let mut m: DictMap<u32, u32> = DictMap::new();
177    /// m.insert(1, 10);
178    /// m.clear();
179    /// assert!(m.is_empty());
180    /// ```
181    pub fn clear(&mut self) {
182        self.inner.clear();
183    }
184
185    /// Borrowed iterator over `(key, value)` pairs.
186    ///
187    /// # Examples
188    ///
189    /// ```
190    /// use dynomite::util::dict::DictMap;
191    /// let mut m: DictMap<u32, u32> = DictMap::new();
192    /// m.insert(1, 10);
193    /// m.insert(2, 20);
194    /// let mut sum = 0u32;
195    /// for (_k, v) in m.iter() { sum += v; }
196    /// assert_eq!(sum, 30);
197    /// ```
198    pub fn iter(&self) -> impl Iterator<Item = (&K, &V)> {
199        self.inner.iter()
200    }
201
202    /// Mutable iterator over `(key, value)` pairs.
203    ///
204    /// # Examples
205    ///
206    /// ```
207    /// use dynomite::util::dict::DictMap;
208    /// let mut m: DictMap<u32, u32> = DictMap::new();
209    /// m.insert(1, 10);
210    /// for (_k, v) in m.iter_mut() { *v += 1; }
211    /// assert_eq!(m.get(&1), Some(&11));
212    /// ```
213    pub fn iter_mut(&mut self) -> impl Iterator<Item = (&K, &mut V)> {
214        self.inner.iter_mut()
215    }
216
217    /// Consume the map and yield `(key, value)` pairs.
218    ///
219    /// # Examples
220    ///
221    /// ```
222    /// use dynomite::util::dict::DictMap;
223    /// let mut m: DictMap<u32, u32> = DictMap::new();
224    /// m.insert(1, 10);
225    /// let drained: Vec<_> = m.drain().collect();
226    /// assert_eq!(drained, vec![(1, 10)]);
227    /// assert!(m.is_empty());
228    /// ```
229    pub fn drain(&mut self) -> impl Iterator<Item = (K, V)> + '_ {
230        self.inner.drain()
231    }
232}
233
234impl<K: Eq + Hash, V> IntoIterator for DictMap<K, V> {
235    type Item = (K, V);
236    type IntoIter = IntoIter<K, V>;
237    fn into_iter(self) -> Self::IntoIter {
238        self.inner.into_iter()
239    }
240}
241
242/// Specialization keyed on [`MsgId`] for the in-flight message index.
243///
244/// # Examples
245///
246/// ```
247/// use dynomite::util::dict::MsgIndex;
248///
249/// let mut idx: MsgIndex<&'static str> = MsgIndex::new();
250/// idx.insert(42, "hello");
251/// assert_eq!(idx.get(&42), Some(&"hello"));
252/// ```
253pub type MsgIndex<V> = DictMap<MsgId, V>;
254
255#[cfg(test)]
256mod tests {
257    use super::*;
258
259    #[test]
260    fn insert_get_remove_round_trip() {
261        let mut m: DictMap<u64, &'static str> = DictMap::new();
262        assert!(m.is_empty());
263        m.insert(1, "one");
264        m.insert(2, "two");
265        assert_eq!(m.len(), 2);
266        assert_eq!(m.get(&1), Some(&"one"));
267        assert!(m.contains_key(&2));
268        assert_eq!(m.remove(&1), Some("one"));
269        assert_eq!(m.remove(&1), None);
270        assert_eq!(m.len(), 1);
271        m.clear();
272        assert!(m.is_empty());
273    }
274
275    #[test]
276    fn msg_index_alias_resolves() {
277        let mut idx: MsgIndex<u32> = MsgIndex::new();
278        idx.insert(7, 700);
279        assert_eq!(idx.get(&7), Some(&700));
280    }
281
282    #[test]
283    fn iter_visits_every_entry() {
284        let mut m: DictMap<u32, u32> = DictMap::with_capacity(4);
285        for i in 0..4 {
286            m.insert(i, i * i);
287        }
288        let mut seen: Vec<(u32, u32)> = m.iter().map(|(k, v)| (*k, *v)).collect();
289        seen.sort_unstable();
290        assert_eq!(seen, vec![(0, 0), (1, 1), (2, 4), (3, 9)]);
291    }
292}