easy_collections/
map.rs

1use std::collections::hash_map::Entry;
2use std::collections::HashMap;
3use std::hash::Hash;
4use std::iter::FromIterator;
5use std::ops::{Deref, DerefMut, Index, IndexMut};
6
7#[macro_export]
8macro_rules! map {
9    () => {
10        $crate::EasyMap::new()
11    };
12    {$default:expr} => {
13        $crate::EasyMap::new_with_default($default)
14    };
15
16    {$($key:expr => $val:expr$(,)?)*} => {{
17        let mut map = map!{};
18        $(map[$key] = $val;)*
19        map
20    }};
21    {$default:expr; $($key:expr => $val:expr$(,)?)*} => {{
22        let mut map = map!{$default};
23        $(map[$key] = $val;)*
24        map
25    }};
26}
27
28/// A wrapper around `HashMap` that creates default values for empty keys.
29/// It also provides convenience implementations for `Index` and `IndexMut`.
30///
31/// For example:
32/// ```rust
33/// use easy_collections::EasyMap;
34///
35/// let mut map = EasyMap::new();
36/// assert_eq!(map['a'], 0); // default value for `usize` is `0`
37/// // now set insert a value
38/// map['a'] = 42_usize;
39/// assert_eq!(map['a'], 42);
40/// ```
41#[derive(Debug, Clone, Eq, PartialEq)]
42pub struct EasyMap<K: Eq + Hash, V: Clone> {
43    inner: HashMap<K, V>,
44    default: V,
45}
46
47impl<K: Eq + Hash, V: Clone + Default> EasyMap<K, V> {
48    /// Create a new `EasyMap`. The value `V` must implement `Default`.
49    ///
50    /// Note, that there are macros which make this easier:
51    /// ```rust
52    /// use easy_collections::map;
53    ///
54    /// let mut map = map!{};
55    /// map[1] = (10, 4);
56    /// ```
57    ///
58    /// And another to pre-populate a map with values:
59    /// ```rust
60    /// use easy_collections::map;
61    ///
62    /// let map = map!{"foo" => "bar", "hello" => "world"};
63    /// assert_eq!(map["foo"], "bar");
64    /// assert_eq!(map["hello"], "world");
65    /// assert_eq!(map["not here"], "");
66    /// ```
67    pub fn new() -> EasyMap<K, V> {
68        EasyMap::new_with_default(V::default())
69    }
70}
71
72impl<K: Eq + Hash, V: Clone> EasyMap<K, V> {
73    /// Create a new `EasyMap`. The value `V` does not need to implement `Default`, instead you provide it with one here.
74    ///
75    /// Note, that there's a macro which makes this easier:
76    /// ```rust
77    /// use easy_collections::map;
78    ///
79    /// #[derive(Debug, Clone, PartialEq)]
80    /// struct Foo(u32);
81    ///
82    /// let mut map = map!{Foo(1)};
83    /// assert_eq!(map[1], Foo(1));
84    /// assert_eq!(map[2], Foo(1));
85    /// map[1] = Foo(1729);
86    /// assert_eq!(map[1], Foo(1729));
87    /// ```
88    ///
89    /// Or, the same while pre-populating the map with values:
90    /// ```rust
91    /// use easy_collections::map;
92    ///
93    /// let map = map!{42; "foo" => 1, "bar" => 10, "baz" => 100};
94    /// assert_eq!(map["foo"], 1);
95    /// assert_eq!(map["bar"], 10);
96    /// assert_eq!(map["baz"], 100);
97    /// assert_eq!(map["nope"], 42);
98    /// ```
99    pub fn new_with_default(default: V) -> EasyMap<K, V> {
100        EasyMap {
101            inner: HashMap::new(),
102            default,
103        }
104    }
105
106    /// Same as `HashMap::insert`.
107    ///
108    /// NOTE: you probably just want to use the `IndexMut` trait for this:
109    /// ```rust
110    /// use easy_collections::EasyMap;
111    ///
112    /// let mut map = EasyMap::new();
113    /// map[1] = "hello";
114    /// ```
115    pub fn insert(&mut self, k: K, v: V) -> Option<V> {
116        self.inner.insert(k, v)
117    }
118
119    /// Same as `HashMap::remove`.
120    pub fn remove(&mut self, k: K) -> Option<V> {
121        self.inner.remove(&k)
122    }
123
124    /// Same as `HashMap::entry`.
125    pub fn entry(&mut self, k: K) -> Entry<K, V> {
126        self.inner.entry(k)
127    }
128}
129
130impl<K: Eq + Hash, V: Clone + Default> From<Vec<(K, V)>> for EasyMap<K, V> {
131    fn from(v: Vec<(K, V)>) -> Self {
132        v.into_iter().collect()
133    }
134}
135
136impl<K: Eq + Hash + Clone, V: Clone + Default> From<&[(K, V)]> for EasyMap<K, V> {
137    fn from(v: &[(K, V)]) -> Self {
138        v.iter().cloned().collect()
139    }
140}
141
142impl<K: Eq + Hash, V: Clone + Default> FromIterator<(K, V)> for EasyMap<K, V> {
143    fn from_iter<T: IntoIterator<Item = (K, V)>>(iter: T) -> Self {
144        let mut set = map!(V::default());
145        for (k, v) in iter {
146            set.insert(k, v);
147        }
148
149        set
150    }
151}
152
153impl<K: Eq + Hash, V: Clone> IntoIterator for EasyMap<K, V> {
154    type Item = (K, V);
155    type IntoIter = std::collections::hash_map::IntoIter<K, V>;
156
157    fn into_iter(self) -> Self::IntoIter {
158        self.inner.into_iter()
159    }
160}
161
162impl<K: Eq + Hash, V: Clone> Deref for EasyMap<K, V> {
163    type Target = HashMap<K, V>;
164    fn deref(&self) -> &Self::Target {
165        &self.inner
166    }
167}
168
169impl<K: Eq + Hash, V: Clone> DerefMut for EasyMap<K, V> {
170    fn deref_mut(&mut self) -> &mut Self::Target {
171        &mut self.inner
172    }
173}
174
175impl<K: Eq + Hash, V: Clone> Index<K> for EasyMap<K, V> {
176    type Output = V;
177    fn index(&self, key: K) -> &Self::Output {
178        self.inner.get(&key).unwrap_or(&self.default)
179    }
180}
181
182impl<K: Eq + Hash, V: Clone> IndexMut<K> for EasyMap<K, V> {
183    fn index_mut(&mut self, key: K) -> &mut Self::Output {
184        self.inner.entry(key).or_insert(self.default.clone())
185    }
186}
187
188#[cfg(test)]
189mod test {
190    use super::*;
191
192    #[test]
193    fn macros() {
194        // without default
195        let map: EasyMap<char, usize> = map! {};
196        assert_eq!(map['a'], 0);
197        assert_eq!(map['b'], 0);
198        assert_eq!(map['c'], 0);
199
200        // with default
201        let map: EasyMap<char, usize> = map! {1};
202        assert_eq!(map['a'], 1);
203        assert_eq!(map['b'], 1);
204        assert_eq!(map['c'], 1);
205
206        // without default & without trailing comma
207        let map = map! { 'a' => 10, 'b' => 20 };
208        assert_eq!(map['a'], 10);
209        assert_eq!(map['b'], 20);
210        assert_eq!(map['c'], 0);
211
212        // without default & with trailing comma
213        let map = map! { 'a' => 100, 'b' => 200, };
214        assert_eq!(map['a'], 100);
215        assert_eq!(map['b'], 200);
216        assert_eq!(map['c'], 0);
217
218        // with default & without trailing comma
219        let map = map! { 1; 'a' => 10, 'b' => 20 };
220        assert_eq!(map['a'], 10);
221        assert_eq!(map['b'], 20);
222        assert_eq!(map['c'], 1);
223
224        // with default & with trailing comma
225        let map = map! { 1; 'a' => 100, 'b' => 200, };
226        assert_eq!(map['a'], 100);
227        assert_eq!(map['b'], 200);
228        assert_eq!(map['c'], 1);
229    }
230
231    #[test]
232    fn index() {
233        let mut map = EasyMap::new();
234        map['a'] = 1;
235        map['b'] = 2;
236        map['c'] = 3;
237
238        assert_eq!(map['a'], 1);
239        assert_eq!(map['b'], 2);
240        assert_eq!(map['c'], 3);
241    }
242
243    #[test]
244    fn index_mut() {
245        let mut map = map!(1; 'a' => 1729);
246
247        // test existing key
248        let a = &mut map['a'];
249        assert_eq!(*a, 1729);
250        assert_eq!(map['a'], 1729);
251
252        // test non-existent key
253        let b = &mut map['b'];
254        *b = 42;
255        assert_eq!(*b, 42);
256        assert_eq!(map['b'], 42);
257        assert_eq!(map['c'], 1);
258    }
259
260    #[test]
261    fn deref() {
262        let easy: EasyMap<_, _> = map! {"foo" => "bar",};
263        let hash: &HashMap<_, _> = &*easy;
264
265        assert_eq!(&*easy, hash);
266    }
267
268    #[test]
269    fn deref_mut() {
270        let mut easy: EasyMap<_, _> = map! {"foo" => "bar",};
271
272        let hash = &mut *easy;
273        hash.insert("bar", "foo");
274
275        assert_eq!(easy, map! {"foo" => "bar", "bar" => "foo"});
276    }
277
278    #[test]
279    fn iter_via_deref() {
280        let map = map! {'i' => true, 't' => true, 'e' => true, 'r' => true};
281        let mut values = vec![];
282        for (k, v) in &*map {
283            values.push((*k, *v));
284        }
285
286        // the values could be in any order
287        values.sort();
288        assert_eq!(
289            values,
290            &[('e', true), ('i', true), ('r', true), ('t', true)]
291        );
292
293        // ensure we can still use the map here
294        assert_eq!(
295            map,
296            map! {'i' => true, 't' => true, 'e' => true, 'r' => true}
297        );
298    }
299
300    #[test]
301    fn into_iter() {
302        let map = map! {'i' => true, 't' => true, 'e' => true, 'r' => true};
303        let mut values = vec![];
304        for x in map {
305            values.push(x);
306        }
307
308        // the values could be in any order
309        values.sort();
310        assert_eq!(
311            values,
312            &[('e', true), ('i', true), ('r', true), ('t', true)]
313        );
314    }
315
316    #[test]
317    fn from_iter() {
318        let v = vec![('i', true), ('t', true), ('e', true), ('r', true)];
319        let s = v.into_iter().collect::<EasyMap<_, _>>();
320        assert_eq!(s, map! {'i' => true, 't' => true, 'e' => true, 'r' => true});
321    }
322
323    #[test]
324    fn entry() {
325        let mut map = map! {"foo" => 42,};
326        *map.entry("foo").or_insert(1) *= 10;
327        *map.entry("bar").or_insert(1) *= 10;
328
329        assert_eq!(map["foo"], 420);
330        assert_eq!(map["bar"], 10);
331    }
332}