├── .github └── workflows │ └── rust.yml ├── .gitignore ├── .travis.yml ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: cargo build --verbose 18 | - name: Run tests 19 | run: cargo test --verbose 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | /target/ 4 | 5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 6 | # More information here http://doc.crates.io/guide.html#cargotoml-vs-cargolock 7 | Cargo.lock 8 | 9 | 10 | # vim swap files 11 | .*.swp 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: rust 2 | rust: 3 | - stable 4 | - beta 5 | - nightly 6 | matrix: 7 | allow_failures: 8 | - rust: nightly 9 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "multi-map" 3 | version = "1.3.0" 4 | authors = [ 5 | "theJPster ", 6 | "Daniel Faust", 7 | "Hans Mündelein", 8 | ] 9 | description = "Like a std::collection::HashMap, but allows you to use either of two different keys to retrieve items." 10 | license = "MIT" 11 | repository = "https://github.com/thejpster/multi-map" 12 | documentation = "https://thejpster.github.io/multi-map/doc/multi_map/index.html" 13 | homepage = "https://thejpster.github.io/multi-map" 14 | edition = "2018" 15 | 16 | [dependencies.serde] 17 | version = "1.0" 18 | features = ["derive"] 19 | optional = true 20 | 21 | [dev-dependencies.serde_json] 22 | version = "1.0" 23 | 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Jonathan 'theJPster' Pallant 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-Map 2 | 3 | [![Build Status](https://travis-ci.org/thejpster/multi-map.svg?branch=master)](https://travis-ci.org/thejpster/multi-map) 4 | [![Crate version](https://img.shields.io/crates/v/multi-map.svg)](https://crates.io/crates/multi-map) 5 | [![Documentation](https://img.shields.io/badge/documentation-docs.rs-df3600.svg)](https://docs.rs/multi-map) 6 | 7 | Like a `std::collection::HashMap`, but allows you to use either of two different keys to retrieve items. 8 | 9 | Sometimes, when developing software stacks, a layer will have some context object it needs to store. Assume, for example, we have an HTTP module, which sits below some sort of HTTP-using Application, and above a Socket module. 10 | 11 | When a new connection is created, a message is received from the Socket module with the ID of the new connection. A new HTTP Connection object is created, and stored against the Socket ID, so that it can be easily retrieved when data arrives on the Socket. But to inform the layer above about the new HTTP Connection (as distinct from any other HTTP Connections that may be on going), we need to give the HTTP Connection itself a unique ID, and we need some mechanism of locating the HTTP Connection by this ID as well. 12 | 13 | The trivial solution is to store the HTTP Connections in a list, and then iterate them, looking for a matching Socket ID or a matching HTTP Connection ID. But this is slow. 14 | 15 | A HashMap seems like a good idea, but you can only key on either the HTTP ID or the Socket ID, not on both. 16 | 17 | This module allows you to create a MultiMap - a map which you can look up either by the primary key (HttpID) or an alternative ID (SocketID). Internally, it uses two maps, one on (K1, (K2, V)) and another on (K2, K1). 18 | 19 | Insert, removal and iteration is supported. Gradually, I might implement the rest of the std::collections::HashMap API, but I've found this to be sufficiently useful for now. 20 | -------------------------------------------------------------------------------- /src/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` 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 `` and a second one on ``. 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 | 42 | #[cfg(feature = "serde")] 43 | use serde::{Deserialize, Serialize}; 44 | use std::borrow::Borrow; 45 | use std::collections::hash_map; 46 | use std::collections::HashMap; 47 | use std::fmt::{self, Debug}; 48 | use std::hash::Hash; 49 | 50 | #[cfg_attr( 51 | feature = "serde", 52 | derive(Deserialize, Serialize), 53 | serde(from = "HashMap") 54 | )] 55 | #[derive(Eq)] 56 | pub struct MultiMap 57 | where 58 | K1: Eq + Hash + Clone, 59 | K2: Eq + Hash + Clone, 60 | { 61 | #[cfg_attr(feature = "serde", serde(flatten))] 62 | value_map: HashMap, 63 | #[cfg_attr(feature = "serde", serde(skip))] 64 | key_map: HashMap, 65 | } 66 | 67 | impl From> for MultiMap 68 | where 69 | K1: Eq + Hash + Clone, 70 | K2: Eq + Hash + Clone, 71 | { 72 | fn from(tuple_map: HashMap) -> Self { 73 | let mut m = MultiMap::with_capacity(tuple_map.len()); 74 | for (k1, (k2, v)) in tuple_map { 75 | m.insert(k1, k2, v); 76 | } 77 | m 78 | } 79 | } 80 | 81 | impl MultiMap 82 | where 83 | K1: Eq + Hash + Clone, 84 | K2: Eq + Hash + Clone, 85 | { 86 | /// Creates a new MultiMap. The primary key is of type `K1` and the 87 | /// secondary key is of type `K2`. The value is of type `V`. This is as 88 | /// compared to a `std::collections::HashMap` which is typed on just `K` and 89 | /// `V`. 90 | /// 91 | /// Internally, two HashMaps are created - a main one on `` and a second one on ``. The `(K2, V)` tuple is so 93 | /// that when an item is removed using the `K1` key, the appropriate `K2` 94 | /// value is available so the `K2->K1` map can be removed from the second 95 | /// HashMap, to keep them in sync. 96 | pub fn new() -> MultiMap { 97 | MultiMap { 98 | value_map: HashMap::new(), 99 | key_map: HashMap::new(), 100 | } 101 | } 102 | 103 | /// Creates an empty MultiMap with the specified capacity. 104 | /// 105 | /// The multi map will be able to hold at least `capacity` elements without reallocating. If `capacity` is 0, the multi map will not allocate. 106 | pub fn with_capacity(capacity: usize) -> MultiMap { 107 | MultiMap { 108 | value_map: HashMap::with_capacity(capacity), 109 | key_map: HashMap::with_capacity(capacity), 110 | } 111 | } 112 | 113 | /// Insert an item into the MultiMap. You must supply both keys to insert 114 | /// an item. The keys cannot be modified at a later date, so if you only 115 | /// have one key at this time, use a placeholder value for the second key 116 | /// (perhaps `K2` is `Option<...>`) and remove then re-insert when the 117 | /// second key becomes available. 118 | pub fn insert(&mut self, key_one: K1, key_two: K2, value: V) { 119 | self.key_map.insert(key_two.clone(), key_one.clone()); 120 | self.value_map.insert(key_one, (key_two, value)); 121 | } 122 | 123 | /// Obtain a reference to an item in the MultiMap using the primary key, 124 | /// just like a HashMap. 125 | pub fn get(&self, key: &K1) -> Option<&V> { 126 | let mut result = None; 127 | if let Some(pair) = self.value_map.get(key) { 128 | result = Some(&pair.1) 129 | } 130 | result 131 | } 132 | 133 | /// Obtain a mutable reference to an item in the MultiMap using the 134 | /// primary key, just like a HashMap. 135 | pub fn get_mut(&mut self, key: &K1) -> Option<&mut V> { 136 | let mut result = None; 137 | if let Some(pair) = self.value_map.get_mut(key) { 138 | result = Some(&mut pair.1) 139 | } 140 | result 141 | } 142 | 143 | /// Obtain a reference to an item in the MultiMap using the secondary key. 144 | /// Ordinary HashMaps can't do this. 145 | pub fn get_alt(&self, key: &K2) -> Option<&V> { 146 | let mut result = None; 147 | if let Some(key_a) = self.key_map.get(key) { 148 | if let Some(pair) = self.value_map.get(key_a) { 149 | result = Some(&pair.1) 150 | } 151 | } 152 | result 153 | } 154 | 155 | /// Obtain a mutable reference to an item in the MultiMap using the 156 | /// secondary key. Ordinary HashMaps can't do this. 157 | pub fn get_mut_alt(&mut self, key: &K2) -> Option<&mut V> { 158 | let mut result = None; 159 | if let Some(key_a) = self.key_map.get(key) { 160 | if let Some(pair) = self.value_map.get_mut(key_a) { 161 | result = Some(&mut pair.1) 162 | } 163 | } 164 | result 165 | } 166 | 167 | /// Obtain a tuple of the secondary key and a reference to the value, 168 | /// using the primary key 169 | pub fn get_with_key(&self, key: &K1) -> Option<(&K2, &V)> { 170 | let mut result = None; 171 | if let Some(pair) = self.value_map.get(key) { 172 | result = Some((&pair.0, &pair.1)) 173 | } 174 | result 175 | } 176 | 177 | /// Obtain a tuple of the secondary key and a mutable reference to the value, 178 | /// using the primary key 179 | pub fn get_mut_with_key(&mut self, key: &K1) -> Option<(&K2, &mut V)> { 180 | let mut result = None; 181 | if let Some(pair) = self.value_map.get_mut(key) { 182 | result = Some((&pair.0, &mut pair.1)) 183 | } 184 | result 185 | } 186 | 187 | /// Obtain a tuple of the primary key and a reference to the value, 188 | /// using the secondary key 189 | pub fn get_alt_with_key(&self, key: &K2) -> Option<(&K1, &V)> { 190 | let mut result = None; 191 | if let Some(key_a) = self.key_map.get(key) { 192 | if let Some(pair) = self.value_map.get(key_a) { 193 | result = Some((key_a, &pair.1)) 194 | } 195 | } 196 | result 197 | } 198 | /// Obtain a tuple of the primary key and a mutual reference to the value, 199 | /// using the secondary key 200 | pub fn get_mut_alt_with_key(&mut self, key: &K2) -> Option<(&K1, &mut V)> { 201 | let mut result = None; 202 | if let Some(key_a) = self.key_map.get(key) { 203 | if let Some(pair) = self.value_map.get_mut(key_a) { 204 | result = Some((key_a, &mut pair.1)) 205 | } 206 | } 207 | result 208 | } 209 | 210 | /// Remove an item from the HashMap using the primary key. The value for the 211 | /// given key is returned (if it exists), just like a HashMap. This removes 212 | /// an item from the main HashMap, and the second `` HashMap. 213 | pub fn remove(&mut self, key: &Q) -> Option 214 | where 215 | K1: Borrow, 216 | Q: Hash + Eq, 217 | { 218 | let mut result = None; 219 | if let Some(pair) = self.value_map.remove(key) { 220 | self.key_map.remove(&pair.0); 221 | result = Some(pair.1) 222 | } 223 | result 224 | } 225 | 226 | /// Returns true if the map contains a value for the specified key. The key may be any borrowed 227 | /// form of the map's key type, but Hash and Eq on the borrowed form must match those for the 228 | /// key type 229 | /// 230 | /// ## Example 231 | /// ``` 232 | /// #[macro_use] 233 | /// extern crate multi_map; 234 | /// use multi_map::MultiMap; 235 | /// # fn main() { 236 | /// let map = multimap! { 237 | /// 1, "One" => String::from("Eins"), 238 | /// 2, "Two" => String::from("Zwei"), 239 | /// 3, "Three" => String::from("Drei"), 240 | /// }; 241 | /// assert!(map.contains_key(&1)); 242 | /// assert!(!map.contains_key(&4)); 243 | /// # } 244 | /// ``` 245 | pub fn contains_key(&self, key: &Q) -> bool 246 | where 247 | K1: Borrow, 248 | Q: Hash + Eq, 249 | { 250 | self.value_map.contains_key(key) 251 | } 252 | 253 | /// Returns true if the map contains a value for the specified alternative key. The key may be 254 | /// any borrowed form of the map's key type, but Hash and Eq on the borrowed form must match 255 | /// those for the key type 256 | /// 257 | /// ## Example 258 | /// ``` 259 | /// #[macro_use] 260 | /// extern crate multi_map; 261 | /// use multi_map::MultiMap; 262 | /// # fn main() { 263 | /// let map = multimap! { 264 | /// 1, "One" => String::from("Eins"), 265 | /// 2, "Two" => String::from("Zwei"), 266 | /// 3, "Three" => String::from("Drei"), 267 | /// }; 268 | /// assert!(map.contains_key_alt(&"One")); 269 | /// assert!(!map.contains_key_alt(&"Four")); 270 | /// # } 271 | /// ``` 272 | pub fn contains_key_alt(&self, key: &Q) -> bool 273 | where 274 | K2: Borrow, 275 | Q: Hash + Eq, 276 | { 277 | self.key_map.contains_key(key) 278 | } 279 | 280 | /// Remove an item from the HashMap using the secondary key. The value for 281 | /// the given key is returned (if it exists). Ordinary HashMaps can't do 282 | /// this. This removes an item from both the main HashMap and the second 283 | /// `` HashMap. 284 | pub fn remove_alt(&mut self, key: &Q) -> Option 285 | where 286 | K2: Borrow, 287 | Q: Hash + Eq, 288 | { 289 | let mut result = None; 290 | if let Some(key_a) = self.key_map.remove(key) { 291 | if let Some(pair) = self.value_map.remove(&key_a) { 292 | result = Some(pair.1) 293 | } 294 | } 295 | result 296 | } 297 | 298 | /// Iterate through all the values in the MultiMap in random order. 299 | /// Note that the values 300 | /// are `(K2, V)` tuples, not `V`, as you would get with a HashMap. 301 | pub fn iter(&self) -> Iter<'_, K1, K2, V> { 302 | Iter { 303 | base: self.value_map.iter(), 304 | } 305 | } 306 | 307 | /// Iterate with mutability through all the values in the MultiMap in random order. 308 | /// Note that the values 309 | /// are `(K2, V)` tuples, not `V`, as you would get with a HashMap. 310 | pub fn iter_mut(&mut self) -> IterMut<'_, K1, K2, V> { 311 | IterMut { 312 | base: self.value_map.iter_mut(), 313 | } 314 | } 315 | 316 | /// Returns the number of elements the map can hold without reallocating. 317 | /// 318 | /// This number is a lower bound; the collection might be able to hold 319 | /// more, but is guaranteed to be able to hold at least this many. 320 | /// 321 | /// ``` 322 | /// # use multi_map::MultiMap; 323 | /// let map = MultiMap::::with_capacity(16); 324 | /// 325 | /// assert!(map.capacity() >= 16); 326 | /// ``` 327 | #[inline] 328 | pub fn capacity(&self) -> usize { 329 | std::cmp::min(self.value_map.capacity(), self.key_map.capacity()) 330 | } 331 | 332 | /// Returns the number of elements in the map. 333 | /// 334 | /// ``` 335 | /// # use multi_map::{MultiMap, multimap}; 336 | /// let map = multimap![ 337 | /// 1, "Breakfast" => "Pancakes", 338 | /// 2, "Lunch" => "Sandwich", 339 | /// ]; 340 | /// assert_eq!(map.len(), 2); 341 | /// ``` 342 | #[inline] 343 | pub fn len(&self) -> usize { 344 | std::cmp::max(self.value_map.len(), self.key_map.len()) 345 | } 346 | 347 | /// Clears the map, removing all key-value pairs, just like `HashMap::clear`. 348 | /// 349 | /// Keeps the allocated memory for reuse. 350 | /// 351 | /// ``` 352 | /// # use multi_map::{MultiMap, multimap}; 353 | /// let mut map = multimap![ 354 | /// 1, "Breakfast" => "Pancakes", 355 | /// 2, "Lunch" => "Sandwich", 356 | /// ]; 357 | /// map.clear(); 358 | /// assert_eq!(map.len(), 0); 359 | /// ``` 360 | pub fn clear(&mut self) { 361 | self.value_map.clear(); 362 | self.key_map.clear(); 363 | } 364 | 365 | /// Clears the map, returning an iterator over the primary key and the 366 | /// secondary key + value tuple. Keeps the allocated memory for reuse. 367 | /// 368 | /// There's no `drain_alt` providing an iterator over secondary key and value, 369 | /// but you can map the iterator as follows: 370 | /// ``` 371 | /// use multi_map::MultiMap; 372 | /// 373 | /// let mut a = MultiMap::new(); 374 | /// a.insert("apple", 1, "a"); 375 | /// a.insert("banana", 2, "b"); 376 | /// 377 | /// for (k, v) in a.drain().map(|(k1, (k2, v))| (k2, v)).take(1) { 378 | /// assert!(k == 1 || k == 2); 379 | /// assert!(v == "a" || v == "b"); 380 | /// } 381 | /// 382 | /// assert!(a.is_empty()); 383 | /// ``` 384 | pub fn drain(&mut self) -> hash_map::Drain<'_, K1, (K2, V)> { 385 | self.key_map.clear(); 386 | self.value_map.drain() 387 | } 388 | 389 | /// Returns `true` if the map contains no elements. 390 | /// 391 | /// ``` 392 | /// # use multi_map::MultiMap; 393 | /// let map = MultiMap::::new(); 394 | /// assert!(map.is_empty()); 395 | /// ``` 396 | #[inline] 397 | pub fn is_empty(&self) -> bool { 398 | self.key_map.is_empty() && self.value_map.is_empty() 399 | } 400 | 401 | /// Removes an entry from the map given a primary key, returning the stored 402 | /// keys and value if the key was previously in the map. 403 | /// 404 | /// The key may be any borrowed form of the map's key type, but 405 | /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for 406 | /// the key type. 407 | /// 408 | /// ``` 409 | /// # use multi_map::{MultiMap, multimap}; 410 | /// let mut map = multimap![ 411 | /// 1, "Breakfast" => "Pancakes", 412 | /// 2, "Lunch" => "Sandwich", 413 | /// ]; 414 | /// let item = map.remove_entry(&1); 415 | /// 416 | /// assert_eq!(map.len(), 1); 417 | /// assert_eq!(item, Some((1, "Breakfast", "Pancakes"))); 418 | /// ``` 419 | #[inline] 420 | pub fn remove_entry(&mut self, k: &Q) -> Option<(K1, K2, V)> 421 | where 422 | K1: Borrow, 423 | Q: Hash + Eq, 424 | { 425 | if let Some((k1, (k2, v))) = self.value_map.remove_entry(k) { 426 | self.key_map.remove(&k2).expect("Internally inconsistent key_map"); 427 | Some((k1, k2, v)) 428 | } else { 429 | None 430 | } 431 | } 432 | 433 | /// Removes an entry from the map given a secondary key, returning the stored 434 | /// keys and value if the key was previously in the map. 435 | /// 436 | /// The key may be any borrowed form of the map's key type, but 437 | /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for 438 | /// the key type. 439 | /// 440 | /// ``` 441 | /// # use multi_map::{MultiMap, multimap}; 442 | /// let mut map = multimap![ 443 | /// 1, "Breakfast" => "Pancakes", 444 | /// 2, "Lunch" => "Sandwich", 445 | /// ]; 446 | /// let item = map.remove_entry_alt("Lunch"); 447 | /// 448 | /// assert_eq!(map.len(), 1); 449 | /// assert_eq!(item, Some((2, "Lunch", "Sandwich"))); 450 | /// ``` 451 | #[inline] 452 | pub fn remove_entry_alt(&mut self, k: &Q) -> Option<(K1, K2, V)> 453 | where 454 | K2: Borrow, 455 | Q: Hash + Eq, 456 | { 457 | if let Some(k1) = self.key_map.remove(k) { 458 | self.value_map.remove_entry(&k1).map(|(k1, (k2, v))| (k1, k2, v)) 459 | } else { 460 | None 461 | } 462 | } 463 | 464 | /// Reserves capacity for at least `additional` more elements to be inserted 465 | /// in the `MultiMap`. The collection may reserve more space to avoid 466 | /// frequent reallocations. 467 | /// 468 | /// # Panics 469 | /// 470 | /// Panics if the new allocation size overflows [`usize`]. 471 | /// 472 | /// ``` 473 | /// # use multi_map::MultiMap; 474 | /// let mut map = MultiMap::::new(); 475 | /// map.reserve(16); 476 | /// assert!(map.capacity() >= 16); 477 | /// ``` 478 | #[inline] 479 | pub fn reserve(&mut self, additional: usize) { 480 | self.value_map.reserve(additional); 481 | self.key_map.reserve(additional); 482 | } 483 | 484 | /// Shrinks the capacity of the map as much as possible. It will drop 485 | /// down as much as possible while maintaining the internal rules 486 | /// and possibly leaving some space in accordance with the resize policy. 487 | /// 488 | /// Note that in the general case the capacity is not *guaranteed* to shrink, 489 | /// but a zero-length MultiMap should generally shrink to capacity zero. 490 | /// ``` 491 | /// # use multi_map::MultiMap; 492 | /// let mut map = MultiMap::::with_capacity(16); 493 | /// // This isn't guaranteed to be exactly 16 494 | /// let capacity = map.capacity(); 495 | /// map.shrink_to_fit(); 496 | /// assert!(map.capacity() < capacity); 497 | /// ``` 498 | #[inline] 499 | pub fn shrink_to_fit(&mut self) { 500 | self.value_map.shrink_to_fit(); 501 | self.key_map.shrink_to_fit(); 502 | } 503 | 504 | } 505 | 506 | impl PartialEq for MultiMap 507 | where 508 | K1: Eq + Hash + Clone, 509 | K2: Eq + Hash + Clone, 510 | { 511 | fn eq(&self, other: &MultiMap) -> bool { 512 | self.value_map.eq(&other.value_map) 513 | } 514 | } 515 | 516 | impl fmt::Debug for MultiMap 517 | where 518 | K1: Eq + Hash + Clone + Debug, 519 | K2: Eq + Hash + Clone + Debug, 520 | V: Debug, 521 | { 522 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 523 | f.debug_map() 524 | .entries( 525 | self.value_map 526 | .iter() 527 | .map(|(key_one, &(ref key_two, ref value))| ((key_one, key_two), value)), 528 | ) 529 | .finish() 530 | } 531 | } 532 | 533 | impl Default for MultiMap 534 | where 535 | K1: Eq + Hash + Clone, 536 | K2: Eq + Hash + Clone, 537 | { 538 | /// Creates an empty `MultiMap` 539 | #[inline] 540 | fn default() -> MultiMap { 541 | MultiMap::new() 542 | } 543 | } 544 | 545 | /// An iterator over the entries of a `MultiMap` like in a `HashMap` but with 546 | /// values of the form (K2, V) instead of V. 547 | /// 548 | /// 549 | /// This `struct` is created by the [`iter`](`MultiMap::iter`) method on [`MultiMap`]. See its 550 | /// documentation for more. 551 | /// 552 | #[derive(Clone)] 553 | pub struct Iter<'a, K1: 'a, K2: 'a, V: 'a> { 554 | base: hash_map::Iter<'a, K1, (K2, V)>, 555 | } 556 | 557 | /// An owning iterator over the entries of a `MultiMap`. 558 | /// 559 | /// This `struct` is created by the [`into_iter`](`IntoIterator::into_iter`) method on [`MultiMap`] 560 | /// (provided by the [`IntoIterator`] trait). See its documentation for more. 561 | /// 562 | pub struct IntoIter { 563 | base: hash_map::IntoIter, 564 | } 565 | 566 | /// An mutable iterator over the entries of a `MultiMap`. 567 | /// 568 | /// This `struct` is created by the [`iter_mut`](`IntoIterator::iter_mut`) method on [`MultiMap`] 569 | /// (provided by the [`IterMut`] trait). See its documentation for more. 570 | /// 571 | pub struct IterMut<'a, K1: 'a, K2: 'a, V: 'a> { 572 | base: hash_map::IterMut<'a, K1, (K2, V)>, 573 | } 574 | // TODO: `HashMap` also implements this, do we need this as well? 575 | // impl IntoIter { 576 | // /// Returns a iterator of references over the remaining items. 577 | // #[inline] 578 | // pub(super) fn iter(&self) -> Iter<'_, K, V> { 579 | // Iter { base: self.base.rustc_iter() } 580 | // } 581 | // } 582 | 583 | impl IntoIterator for MultiMap 584 | where 585 | K1: Eq + Hash + Clone, 586 | K2: Eq + Hash + Clone, 587 | { 588 | type Item = (K1, (K2, V)); 589 | type IntoIter = IntoIter; 590 | 591 | /// Creates a consuming iterator, that is, one that moves each key-value 592 | /// pair out of the map in arbitrary order. The map cannot be used after 593 | /// calling this. 594 | /// 595 | fn into_iter(self) -> IntoIter { 596 | IntoIter { 597 | base: self.value_map.into_iter(), 598 | } 599 | } 600 | } 601 | 602 | impl<'a, K1, K2, V> IntoIterator for &'a MultiMap 603 | where 604 | K1: Eq + Hash + Clone, 605 | K2: Eq + Hash + Clone, 606 | { 607 | type Item = (&'a K1, &'a (K2, V)); 608 | type IntoIter = Iter<'a, K1, K2, V>; 609 | 610 | fn into_iter(self) -> Iter<'a, K1, K2, V> { 611 | self.iter() 612 | } 613 | } 614 | 615 | impl<'a, K1, K2, V> IntoIterator for &'a mut MultiMap 616 | where 617 | K1: Eq + Hash + Clone, 618 | K2: Eq + Hash + Clone, 619 | { 620 | type Item = (&'a K1, (&'a K2, &'a mut V)); 621 | type IntoIter = IterMut<'a, K1, K2, V>; 622 | 623 | // Creates a mutable iterator on MultiMap's values. 624 | fn into_iter(self) -> IterMut<'a, K1, K2, V> { 625 | self.iter_mut() 626 | } 627 | } 628 | 629 | impl<'a, K1, K2, V> Iterator for Iter<'a, K1, K2, V> { 630 | type Item = (&'a K1, &'a (K2, V)); 631 | 632 | fn next(&mut self) -> Option<(&'a K1, &'a (K2, V))> { 633 | self.base.next() 634 | } 635 | #[inline] 636 | fn size_hint(&self) -> (usize, Option) { 637 | self.base.size_hint() 638 | } 639 | } 640 | 641 | impl Iterator for IntoIter { 642 | type Item = (K1, (K2, V)); 643 | 644 | #[inline] 645 | fn next(&mut self) -> Option<(K1, (K2, V))> { 646 | self.base.next() 647 | } 648 | #[inline] 649 | fn size_hint(&self) -> (usize, Option) { 650 | self.base.size_hint() 651 | } 652 | } 653 | 654 | impl<'a, K1, K2, V> Iterator for IterMut<'a, K1, K2, V> { 655 | type Item = (&'a K1, (&'a K2, &'a mut V)); 656 | 657 | #[inline] 658 | fn next(&mut self) -> Option<(&'a K1, (&'a K2, &'a mut V))> { 659 | self.base.next().map(|v| (v.0, (&v.1.0, &mut v.1.1))) 660 | } 661 | #[inline] 662 | fn size_hint(&self) -> (usize, Option) { 663 | self.base.size_hint() 664 | } 665 | } 666 | 667 | #[macro_export] 668 | /// Create a `MultiMap` from a list of key-value tuples 669 | /// 670 | /// ## Example 671 | /// 672 | /// ``` 673 | /// #[macro_use] 674 | /// extern crate multi_map; 675 | /// use multi_map::MultiMap; 676 | /// 677 | /// # fn main() { 678 | /// #[derive(Hash,Clone,PartialEq,Eq)] 679 | /// enum ThingIndex { 680 | /// IndexOne, 681 | /// IndexTwo, 682 | /// IndexThree, 683 | /// }; 684 | /// 685 | /// let map = multimap!{ 686 | /// 1, ThingIndex::IndexOne => "Chicken Fried Steak", 687 | /// 2, ThingIndex::IndexTwo => "Blueberry Pancakes", 688 | /// }; 689 | /// 690 | /// assert!(*map.get_alt(&ThingIndex::IndexOne).unwrap() == "Chicken Fried Steak"); 691 | /// assert!(*map.get(&2).unwrap() == "Blueberry Pancakes"); 692 | /// # } 693 | /// ``` 694 | macro_rules! multimap { 695 | (@single $($x:tt)*) => (()); 696 | (@count $($rest:expr),*) => (<[()]>::len(&[$(multimap!(@single $rest)),*])); 697 | 698 | ($($key1:expr, $key2:expr => $value:expr,)+) => { multimap!($($key1, $key2 => $value),+) }; 699 | ($($key1:expr, $key2:expr => $value:expr),*) => { 700 | { 701 | let _cap = multimap!(@count $($key1),*); 702 | let mut _map = MultiMap::with_capacity(_cap); 703 | $( 704 | _map.insert($key1, $key2, $value); 705 | )* 706 | _map 707 | } 708 | }; 709 | } 710 | 711 | mod test { 712 | 713 | #[test] 714 | fn big_test() { 715 | use super::MultiMap; 716 | 717 | let mut map = MultiMap::new(); 718 | 719 | map.insert(1, "One", String::from("Ein")); 720 | map.insert(2, "Two", String::from("Zwei")); 721 | map.insert(3, "Three", String::from("Drei")); 722 | 723 | assert!(*map.get(&1).unwrap() == "Ein"); 724 | assert!(*map.get(&2).unwrap() == "Zwei"); 725 | assert!(*map.get(&3).unwrap() == "Drei"); 726 | assert!(map.contains_key(&1)); 727 | assert!(!map.contains_key(&4)); 728 | assert!(map.contains_key_alt(&"One")); 729 | assert!(!map.contains_key_alt(&"Four")); 730 | 731 | map.get_mut_alt(&"One").unwrap().push('s'); 732 | 733 | assert!(*map.get_alt(&"One").unwrap() == "Eins"); 734 | assert!(*map.get_alt(&"Two").unwrap() == "Zwei"); 735 | assert!(*map.get_alt(&"Three").unwrap() == "Drei"); 736 | 737 | map.remove(&3); 738 | 739 | assert!(*map.get_alt(&"One").unwrap() == "Eins"); 740 | assert!(*map.get_alt(&"Two").unwrap() == "Zwei"); 741 | assert!(map.get_alt(&"Three") == None); 742 | assert!(map.get(&3) == None); 743 | 744 | assert!(map.remove_alt(&"Three") == None); 745 | assert!(map.remove_alt(&"One").unwrap() == "Eins"); 746 | 747 | map.get_mut(&2).unwrap().push('!'); 748 | 749 | assert!(map.get(&1) == None); 750 | assert!(*map.get(&2).unwrap() == "Zwei!"); 751 | assert!(map.get_alt(&"Three") == None); 752 | assert!(map.get(&3) == None); 753 | } 754 | #[test] 755 | fn test_get_with_key() { 756 | use super::MultiMap; 757 | let mut map = MultiMap::new(); 758 | map.insert(1, "One", String::from("Ein")); 759 | map.insert(2, "Two", String::from("Zwei")); 760 | map.insert(3, "Three", String::from("Drei")); 761 | assert!(*map.get_with_key(&1).unwrap().0 == "One"); 762 | assert!(*map.get_with_key(&1).unwrap().1 == String::from("Ein")); 763 | assert!(*map.get_with_key(&2).unwrap().0 == "Two"); 764 | assert!(*map.get_with_key(&2).unwrap().1 == String::from("Zwei")); 765 | assert!(*map.get_with_key(&3).unwrap().0 == "Three"); 766 | assert!(*map.get_with_key(&3).unwrap().1 == String::from("Drei")); 767 | let pair = map.get_mut_with_key(&1).unwrap(); 768 | assert!(pair.0 == &"One"); 769 | pair.1.push_str("s"); 770 | assert!(*map.get_alt_with_key(&"One").unwrap().0 == 1); 771 | assert!(*map.get_alt_with_key(&"One").unwrap().1 == String::from("Eins")); 772 | assert!(*map.get_alt_with_key(&"Two").unwrap().0 == 2); 773 | assert!(*map.get_alt_with_key(&"Two").unwrap().1 == String::from("Zwei")); 774 | assert!(*map.get_alt_with_key(&"Three").unwrap().0 == 3); 775 | assert!(*map.get_alt_with_key(&"Three").unwrap().1 == String::from("Drei")); 776 | let pair = map.get_mut_alt_with_key(&"One").unwrap(); 777 | assert!(pair.0 == &1); 778 | pair.1.push_str("s"); 779 | assert!(*map.get_with_key(&1).unwrap().1 == String::from("Einss")); 780 | } 781 | #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] 782 | struct MultiCount<'a>(i32, &'a str, &'a str); 783 | #[derive(Debug, Eq, Ord, PartialEq, PartialOrd)] 784 | struct MultiCountOwned(i32, String, String); 785 | 786 | #[test] 787 | fn into_iter_test() { 788 | use super::MultiMap; 789 | let mut map = MultiMap::new(); 790 | 791 | map.insert(1, "One", String::from("Eins")); 792 | map.insert(2, "Two", String::from("Zwei")); 793 | map.insert(3, "Three", String::from("Drei")); 794 | 795 | let mut vec_borrow = Vec::new(); 796 | for (k1, (k2, v)) in &map { 797 | vec_borrow.push(MultiCount(*k1, *k2, v)); 798 | } 799 | vec_borrow.sort(); 800 | assert_eq!( 801 | vec_borrow, 802 | vec!( 803 | MultiCount(1, "One", "Eins"), 804 | MultiCount(2, "Two", "Zwei"), 805 | MultiCount(3, "Three", "Drei") 806 | ) 807 | ); 808 | 809 | let mut vec_owned = Vec::new(); 810 | for (k1, (k2, v)) in map { 811 | vec_owned.push(MultiCountOwned(k1, String::from(k2), v)); 812 | } 813 | vec_owned.sort(); 814 | assert_eq!( 815 | vec_owned, 816 | vec!( 817 | MultiCountOwned(1, String::from("One"), String::from("Eins")), 818 | MultiCountOwned(2, String::from("Two"), String::from("Zwei")), 819 | MultiCountOwned(3, String::from("Three"), String::from("Drei")) 820 | ) 821 | ) 822 | } 823 | 824 | #[cfg(feature = "serde")] 825 | #[test] 826 | fn serde_test() { 827 | use super::MultiMap; 828 | let mut map = MultiMap::new(); 829 | 830 | map.insert(1, "One", String::from("Eins")); 831 | map.insert(2, "Two", String::from("Zwei")); 832 | map.insert(3, "Three", String::from("Drei")); 833 | let serialized = serde_json::to_string(&map).unwrap(); 834 | 835 | let deserialized: MultiMap = serde_json::from_str(&serialized).unwrap(); 836 | 837 | assert_eq!(*deserialized.get(&1).unwrap(), String::from("Eins")); 838 | assert_eq!(*deserialized.get_alt(&"One").unwrap(), String::from("Eins")); 839 | 840 | assert_eq!(*deserialized.get(&2).unwrap(), String::from("Zwei")); 841 | assert_eq!(*deserialized.get_alt(&"Two").unwrap(), String::from("Zwei")); 842 | 843 | assert_eq!(*deserialized.get(&3).unwrap(), String::from("Drei")); 844 | assert_eq!( 845 | *deserialized.get_alt(&"Three").unwrap(), 846 | String::from("Drei") 847 | ); 848 | 849 | assert_eq!(deserialized.get(&4), None); 850 | assert_eq!(deserialized.get_alt(&"Four"), None); 851 | } 852 | 853 | #[test] 854 | fn macro_test() { 855 | use super::MultiMap; 856 | 857 | let map: MultiMap = MultiMap::new(); 858 | 859 | assert_eq!(map, multimap! {}); 860 | 861 | let mut map = MultiMap::new(); 862 | map.insert(1, "One", String::from("Eins")); 863 | 864 | assert_eq!( 865 | map, 866 | multimap! { 867 | 1, "One" => String::from("Eins"), 868 | } 869 | ); 870 | 871 | assert_eq!( 872 | map, 873 | multimap! { 874 | 1, "One" => String::from("Eins") 875 | } 876 | ); 877 | 878 | let mut map = MultiMap::new(); 879 | map.insert(1, "One", String::from("Eins")); 880 | map.insert(2, "Two", String::from("Zwei")); 881 | map.insert(3, "Three", String::from("Drei")); 882 | 883 | assert_eq!( 884 | map, 885 | multimap! { 886 | 1, "One" => String::from("Eins"), 887 | 2, "Two" => String::from("Zwei"), 888 | 3, "Three" => String::from("Drei"), 889 | } 890 | ); 891 | 892 | assert_eq!( 893 | map, 894 | multimap! { 895 | 1, "One" => String::from("Eins"), 896 | 2, "Two" => String::from("Zwei"), 897 | 3, "Three" => String::from("Drei") 898 | } 899 | ); 900 | } 901 | } 902 | --------------------------------------------------------------------------------