multi_map/
lib.rs

1//! # multi-map
2//!
3//! `MultiMap` is like a `std::collection::HashMap`, but allows you to use either of
4//! two different keys to retrieve items.
5//!
6//! The keys have two distinct types - `K1` and `K2` - which may be the same.
7//! Accessing on the primary `K1` key is via the usual `get`, `get_mut` and
8//! `remove_alt` methods, while accessing via the secondary `K2` key is via new
9//! `get_alt`, `get_mut_alt` and `remove_alt` methods. The value is of type `V`.
10//!
11//! Internally, two `HashMap`s are created - a main one on `<K1, (K2,
12//! V)>` and a second one on `<K2, K1>`. The `(K2, V)` tuple is so
13//! that when an item is removed using the `K1` key, the appropriate `K2`
14//! value is available so the `K2->K1` map can be removed from the second
15//! `MultiMap`, to keep them in sync.
16//!
17//! Using two `HashMap`s instead of one naturally brings a slight performance
18//! and memory penalty. Notably, indexing by `K2` requires two `HashMap` lookups.
19//!
20//! ```
21//! extern crate multi_map;
22//! use multi_map::MultiMap;
23//!
24//! # fn main() {
25//! #[derive(Hash,Clone,PartialEq,Eq)]
26//! enum ThingIndex {
27//!     IndexOne,
28//!     IndexTwo,
29//!     IndexThree,
30//! };
31//!
32//! let mut map = MultiMap::new();
33//! map.insert(1, ThingIndex::IndexOne, "Chicken Fried Steak");
34//! map.insert(2, ThingIndex::IndexTwo, "Blueberry Pancakes");
35//!
36//! assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == "Chicken Fried Steak");
37//! assert!(*map.get(&2).unwrap() == "Blueberry Pancakes");
38//! assert!(map.remove_alt(&ThingIndex::IndexTwo).unwrap() == "Blueberry Pancakes");
39//! # }
40//! ```
41
42use std::borrow::Borrow;
43use std::collections::hash_map;
44use std::collections::HashMap;
45use std::fmt::{self, Debug};
46use std::hash::Hash;
47
48#[derive(Eq)]
49pub struct MultiMap<K1: Eq + Hash, K2: Eq + Hash, V> {
50    value_map: HashMap<K1, (K2, V)>,
51    key_map: HashMap<K2, K1>,
52}
53
54impl<K1: Eq + Hash + Clone, K2: Eq + Hash + Clone, V> MultiMap<K1, K2, V> {
55    /// Creates a new MultiMap. The primary key is of type `K1` and the
56    /// secondary key is of type `K2`. The value is of type `V`. This is as
57    /// compared to a `std::collections::HashMap` which is typed on just `K` and
58    /// `V`.
59    ///
60    /// Internally, two HashMaps are created - a main one on `<K1, (K2,
61    /// V)>` and a second one on `<K2, K1>`. The `(K2, V)` tuple is so
62    /// that when an item is removed using the `K1` key, the appropriate `K2`
63    /// value is available so the `K2->K1` map can be removed from the second
64    /// HashMap, to keep them in sync.
65    pub fn new() -> MultiMap<K1, K2, V> {
66        MultiMap {
67            value_map: HashMap::new(),
68            key_map: HashMap::new(),
69        }
70    }
71
72    /// Creates an empty MultiMap with the specified capacity.
73    ///
74    /// The multi map will be able to hold at least `capacity` elements without reallocating. If `capacity` is 0, the multi map will not allocate.
75    pub fn with_capacity(capacity: usize) -> MultiMap<K1, K2, V> {
76        MultiMap {
77            value_map: HashMap::with_capacity(capacity),
78            key_map: HashMap::with_capacity(capacity),
79        }
80    }
81
82    /// Insert an item into the MultiMap. You must supply both keys to insert
83    /// an item. The keys cannot be modified at a later date, so if you only
84    /// have one key at this time, use a placeholder value for the second key
85    /// (perhaps `K2` is `Option<...>`) and remove then re-insert when the
86    /// second key becomes available.
87    pub fn insert(&mut self, key_one: K1, key_two: K2, value: V) {
88        self.key_map.insert(key_two.clone(), key_one.clone());
89        self.value_map.insert(key_one, (key_two, value));
90    }
91
92    /// Obtain a reference to an item in the MultiMap using the primary key,
93    /// just like a HashMap.
94    pub fn get(&self, key: &K1) -> Option<&V> {
95        let mut result = None;
96        if let Some(pair) = self.value_map.get(key) {
97            result = Some(&pair.1)
98        }
99        result
100    }
101
102    /// Obtain a mutable reference to an item in the MultiMap using the
103    /// primary key, just like a HashMap.
104    pub fn get_mut(&mut self, key: &K1) -> Option<&mut V> {
105        let mut result = None;
106        if let Some(pair) = self.value_map.get_mut(key) {
107            result = Some(&mut pair.1)
108        }
109        result
110    }
111
112    /// Obtain a reference to an item in the MultiMap using the secondary key.
113    /// Ordinary HashMaps can't do this.
114    pub fn get_alt(&self, key: &K2) -> Option<&V> {
115        let mut result = None;
116        if let Some(key_a) = self.key_map.get(key) {
117            if let Some(pair) = self.value_map.get(key_a) {
118                result = Some(&pair.1)
119            }
120        }
121        result
122    }
123
124    /// Obtain a mutable reference to an item in the MultiMap using the
125    /// secondary key. Ordinary HashMaps can't do this.
126    pub fn get_mut_alt(&mut self, key: &K2) -> Option<&mut V> {
127        let mut result = None;
128        if let Some(key_a) = self.key_map.get(key) {
129            if let Some(pair) = self.value_map.get_mut(key_a) {
130                result = Some(&mut pair.1)
131            }
132        }
133        result
134    }
135
136    /// Remove an item from the HashMap using the primary key. The value for the
137    /// given key is returned (if it exists), just like a HashMap. This removes
138    /// an item from the main HashMap, and the second `<K2, K1>` HashMap.
139    pub fn remove<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
140    where
141        K1: Borrow<Q>,
142        Q: Hash + Eq,
143    {
144        let mut result = None;
145        if let Some(pair) = self.value_map.remove(key) {
146            self.key_map.remove(&pair.0);
147            result = Some(pair.1)
148        }
149        result
150    }
151
152    /// Returns true if the map contains a value for the specified key. The key may be any borrowed
153    /// form of the map's key type, but Hash and Eq on the borrowed form must match those for the
154    /// key type
155    ///
156    /// ## Example
157    /// ```
158    /// #[macro_use]
159    /// extern crate multi_map;
160    /// use multi_map::MultiMap;
161    /// # fn main() {
162    /// let map = multimap! {
163    ///     1, "One" => String::from("Eins"),
164    ///     2, "Two" => String::from("Zwei"),
165    ///     3, "Three" => String::from("Drei"),
166    /// };
167    /// assert!(map.contains_key(&1));
168    /// assert!(!map.contains_key(&4));
169    /// # }
170    /// ```
171    pub fn contains_key<Q: ?Sized>(&self, key: &Q) -> bool
172    where
173        K1: Borrow<Q>,
174        Q: Hash + Eq,
175    {
176        self.value_map.contains_key(key)
177    }
178
179    /// Returns true if the map contains a value for the specified alternative key. The key may be
180    /// any borrowed form of the map's key type, but Hash and Eq on the borrowed form must match
181    /// those for the key type
182    ///
183    /// ## Example
184    /// ```
185    /// #[macro_use]
186    /// extern crate multi_map;
187    /// use multi_map::MultiMap;
188    /// # fn main() {
189    /// let map = multimap! {
190    ///     1, "One" => String::from("Eins"),
191    ///     2, "Two" => String::from("Zwei"),
192    ///     3, "Three" => String::from("Drei"),
193    /// };
194    /// assert!(map.contains_key_alt(&"One"));
195    /// assert!(!map.contains_key_alt(&"Four"));
196    /// # }
197    /// ```
198    pub fn contains_key_alt<Q: ?Sized>(&self, key: &Q) -> bool
199    where
200        K2: Borrow<Q>,
201        Q: Hash + Eq,
202    {
203        self.key_map.contains_key(key)
204    }
205
206    /// Remove an item from the HashMap using the secondary key. The value for
207    /// the given key is returned (if it exists). Ordinary HashMaps can't do
208    /// this. This removes an item from both the main HashMap and the second
209    /// `<K2, K1>` HashMap.
210    pub fn remove_alt<Q: ?Sized>(&mut self, key: &Q) -> Option<V>
211    where
212        K2: Borrow<Q>,
213        Q: Hash + Eq,
214    {
215        let mut result = None;
216        if let Some(key_a) = self.key_map.remove(key) {
217            if let Some(pair) = self.value_map.remove(&key_a) {
218                result = Some(pair.1)
219            }
220        }
221        result
222    }
223
224    /// Iterate through all the values in the MultiMap in random order.
225    /// Note that the values
226    /// are `(K2, V)` tuples, not `V`, as you would get with a HashMap.
227    pub fn iter(&self) -> Iter<'_, K1, K2, V> {
228        Iter {
229            base: self.value_map.iter(),
230        }
231    }
232}
233
234impl<K1: Eq + Hash, K2: Eq + Hash, V: Eq> PartialEq for MultiMap<K1, K2, V> {
235    fn eq(&self, other: &MultiMap<K1, K2, V>) -> bool {
236        self.value_map.eq(&other.value_map)
237    }
238}
239
240impl<K1: Eq + Hash + Debug, K2: Eq + Hash + Debug, V: Debug> fmt::Debug for MultiMap<K1, K2, V> {
241    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
242        f.debug_map()
243            .entries(
244                self.value_map
245                    .iter()
246                    .map(|(key_one, &(ref key_two, ref value))| ((key_one, key_two), value)),
247            )
248            .finish()
249    }
250}
251
252impl<K1, K2, V> Default for MultiMap<K1, K2, V>
253where
254    K1: Eq + Hash + Clone,
255    K2: Eq + Hash + Clone,
256{
257    /// Creates an empty `MultiMap<K1, K2, V>`
258    #[inline]
259    fn default() -> MultiMap<K1, K2, V> {
260        MultiMap::new()
261    }
262}
263
264/// An iterator over the entries of a `MultiMap` like in a `HashMap` but with
265/// values of the form (K2, V) instead of V.
266///
267///
268/// This `struct` is created by the [`iter`] method on [`MultiMap`]. See its
269/// documentation for more.
270///
271#[derive(Clone, Debug)]
272pub struct Iter<'a, K1: 'a, K2: 'a, V: 'a> {
273    base: hash_map::Iter<'a, K1, (K2, V)>,
274}
275
276/// An owning iterator over the entries of a `MultiMap`.
277///
278/// This `struct` is created by the [`into_iter`] method on [`MultiMap`]
279/// (provided by the `IntoIterator` trait). See its documentation for more.
280///
281pub struct IntoIter<K1, K2, V> {
282    base: hash_map::IntoIter<K1, (K2, V)>,
283}
284// TODO: `HashMap` also implements this, do we need this as well?
285// impl<K, V> IntoIter<K, V> {
286//     /// Returns a iterator of references over the remaining items.
287//     #[inline]
288//     pub(super) fn iter(&self) -> Iter<'_, K, V> {
289//         Iter { base: self.base.rustc_iter() }
290//     }
291// }
292
293impl<K1, K2, V> IntoIterator for MultiMap<K1, K2, V>
294where
295    K1: Eq + Hash + Debug,
296    K2: Eq + Hash + Debug,
297    V: Debug,
298{
299    type Item = (K1, (K2, V));
300    type IntoIter = IntoIter<K1, K2, V>;
301
302    /// Creates a consuming iterator, that is, one that moves each key-value
303    /// pair out of the map in arbitrary order. The map cannot be used after
304    /// calling this.
305    ///
306    fn into_iter(self) -> IntoIter<K1, K2, V> {
307        IntoIter {
308            base: self.value_map.into_iter(),
309        }
310    }
311}
312
313impl<'a, K1, K2, V> IntoIterator for &'a MultiMap<K1, K2, V>
314where
315    K1: Eq + Hash + Debug + Clone,
316    K2: Eq + Hash + Debug + Clone,
317    V: Debug,
318{
319    type Item = (&'a K1, &'a (K2, V));
320    type IntoIter = Iter<'a, K1, K2, V>;
321
322    fn into_iter(self) -> Iter<'a, K1, K2, V> {
323        self.iter()
324    }
325}
326
327impl<'a, K1, K2, V> Iterator for Iter<'a, K1, K2, V> {
328    type Item = (&'a K1, &'a (K2, V));
329
330    fn next(&mut self) -> Option<(&'a K1, &'a (K2, V))> {
331        self.base.next()
332    }
333    #[inline]
334    fn size_hint(&self) -> (usize, Option<usize>) {
335        self.base.size_hint()
336    }
337}
338
339impl<K1, K2, V> Iterator for IntoIter<K1, K2, V> {
340    type Item = (K1, (K2, V));
341
342    #[inline]
343    fn next(&mut self) -> Option<(K1, (K2, V))> {
344        self.base.next()
345    }
346    #[inline]
347    fn size_hint(&self) -> (usize, Option<usize>) {
348        self.base.size_hint()
349    }
350}
351
352#[macro_export]
353/// Create a `MultiMap` from a list of key-value tuples
354///
355/// ## Example
356///
357/// ```
358/// #[macro_use]
359/// extern crate multi_map;
360/// use multi_map::MultiMap;
361///
362/// # fn main() {
363/// #[derive(Hash,Clone,PartialEq,Eq)]
364/// enum ThingIndex {
365///     IndexOne,
366///     IndexTwo,
367///     IndexThree,
368/// };
369///
370/// let map = multimap!{
371///     1, ThingIndex::IndexOne => "Chicken Fried Steak",
372///     2, ThingIndex::IndexTwo => "Blueberry Pancakes",
373/// };
374///
375/// assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == "Chicken Fried Steak");
376/// assert!(*map.get(&2).unwrap() == "Blueberry Pancakes");
377/// # }
378/// ```
379macro_rules! multimap {
380    (@single $($x:tt)*) => (());
381    (@count $($rest:expr),*) => (<[()]>::len(&[$(multimap!(@single $rest)),*]));
382
383    ($($key1:expr, $key2:expr => $value:expr,)+) => { multimap!($($key1, $key2 => $value),+) };
384    ($($key1:expr, $key2:expr => $value:expr),*) => {
385        {
386            let _cap = multimap!(@count $($key1),*);
387            let mut _map = MultiMap::with_capacity(_cap);
388            $(
389                _map.insert($key1, $key2, $value);
390            )*
391            _map
392        }
393    };
394}
395
396mod test {
397
398    #[test]
399    fn big_test() {
400        use MultiMap;
401
402        let mut map = MultiMap::new();
403
404        map.insert(1, "One", String::from("Ein"));
405        map.insert(2, "Two", String::from("Zwei"));
406        map.insert(3, "Three", String::from("Drei"));
407
408        assert!(*map.get(&1).unwrap() == String::from("Ein"));
409        assert!(*map.get(&2).unwrap() == String::from("Zwei"));
410        assert!(*map.get(&3).unwrap() == String::from("Drei"));
411        assert!(map.contains_key(&1));
412        assert!(!map.contains_key(&4));
413        assert!(map.contains_key_alt(&"One"));
414        assert!(!map.contains_key_alt(&"Four"));
415
416        map.get_mut_alt(&"One").unwrap().push_str("s");
417
418        assert!(*map.get_alt(&"One").unwrap() == String::from("Eins"));
419        assert!(*map.get_alt(&"Two").unwrap() == String::from("Zwei"));
420        assert!(*map.get_alt(&"Three").unwrap() == String::from("Drei"));
421
422        map.remove(&3);
423
424        assert!(*map.get_alt(&"One").unwrap() == String::from("Eins"));
425        assert!(*map.get_alt(&"Two").unwrap() == String::from("Zwei"));
426        assert!(map.get_alt(&"Three") == None);
427        assert!(map.get(&3) == None);
428
429        assert!(map.remove_alt(&"Three") == None);
430        assert!(*map.remove_alt(&"One").unwrap() == String::from("Eins"));
431
432        map.get_mut(&2).unwrap().push_str("!");
433
434        assert!(map.get(&1) == None);
435        assert!(*map.get(&2).unwrap() == String::from("Zwei!"));
436        assert!(map.get_alt(&"Three") == None);
437        assert!(map.get(&3) == None);
438    }
439    #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
440    struct MultiCount<'a>(i32, &'a str, &'a str);
441    #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)]
442    struct MultiCountOwned(i32, String, String);
443
444    #[test]
445    fn into_iter_test() {
446        use MultiMap;
447        let mut map = MultiMap::new();
448
449        map.insert(1, "One", String::from("Eins"));
450        map.insert(2, "Two", String::from("Zwei"));
451        map.insert(3, "Three", String::from("Drei"));
452
453        let mut vec_borrow = Vec::new();
454        for (k1, (k2, v)) in &map {
455            vec_borrow.push(MultiCount(*k1, *k2, v));
456        }
457        vec_borrow.sort();
458        assert_eq!(
459            vec_borrow,
460            vec!(
461                MultiCount(1, "One", "Eins"),
462                MultiCount(2, "Two", "Zwei"),
463                MultiCount(3, "Three", "Drei")
464            )
465        );
466
467        let mut vec_owned = Vec::new();
468        for (k1, (k2, v)) in map {
469            vec_owned.push(MultiCountOwned(k1, String::from(k2), v));
470        }
471        vec_owned.sort();
472        assert_eq!(
473            vec_owned,
474            vec!(
475                MultiCountOwned(1, String::from("One"), String::from("Eins")),
476                MultiCountOwned(2, String::from("Two"), String::from("Zwei")),
477                MultiCountOwned(3, String::from("Three"), String::from("Drei"))
478            )
479        )
480    }
481
482    #[test]
483    fn macro_test() {
484        use MultiMap;
485
486        let map: MultiMap<i32, &str, String> = MultiMap::new();
487
488        assert_eq!(map, multimap! {});
489
490        let mut map = MultiMap::new();
491        map.insert(1, "One", String::from("Eins"));
492
493        assert_eq!(
494            map,
495            multimap! {
496                1, "One" => String::from("Eins"),
497            }
498        );
499
500        assert_eq!(
501            map,
502            multimap! {
503                1, "One" => String::from("Eins")
504            }
505        );
506
507        let mut map = MultiMap::new();
508        map.insert(1, "One", String::from("Eins"));
509        map.insert(2, "Two", String::from("Zwei"));
510        map.insert(3, "Three", String::from("Drei"));
511
512        assert_eq!(
513            map,
514            multimap! {
515                1, "One" => String::from("Eins"),
516                2, "Two" => String::from("Zwei"),
517                3, "Three" => String::from("Drei"),
518            }
519        );
520
521        assert_eq!(
522            map,
523            multimap! {
524                1, "One" => String::from("Eins"),
525                2, "Two" => String::from("Zwei"),
526                3, "Three" => String::from("Drei")
527            }
528        );
529    }
530}