├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | /target/ 2 | **/*.rs.bk 3 | Cargo.lock 4 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | license = "MIT" 3 | name = "bisetmap" 4 | version = "0.1.6" 5 | readme = "README.md" 6 | description = "BisetMap is a fast and thread-safe two-way hash map of sets. It is best suited where you need to associate two collumns uniquely. Each key is associated to one or more other unique values. The structure is interior mutable and all operations are thread safe. Each clone provides access to the same underlying data. Serialize and Deserialize from serde are also implemented." 7 | authors = ["Arash Shakery (arash16.com)"] 8 | keywords = ["bidirectional", "two-way", "map", "hashmap", "multimap"] 9 | categories = ["data-structures", "algorithms"] 10 | documentation = "https://docs.rs/bisetmap/" 11 | homepage = "https://github.com/arash16/bisetmap/" 12 | repository = "https://github.com/arash16/bisetmap/" 13 | 14 | [dependencies] 15 | serde = "1.0" 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Arash Shakery 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 | [![crates.io](https://img.shields.io/crates/v/bisetmap.svg)](https://crates.io/crates/bisetmap) 2 | [![Documentation](https://docs.rs/bisetmap/badge.svg)](https://docs.rs/bisetmap/) 3 | 4 | # BisetMap 5 | BisetMap is a fast and thread-safe two-way hash map of sets for Rust. It is best suited where you need to associate 6 | two collumns uniquely. Each key is associated to one or more other unique values. 7 | 8 | The structure is interior mutable and all operations are thread safe. Each clone provides access to the same 9 | underlying data. Serialize and Deserialize from serde are also implemented. 10 | 11 | ## Usage 12 | To use BisetMap in your Rust project, add `bisetmap = 0.1` to the dependencies section of your `Cargo.toml`. 13 | See [the docs](https://docs.rs/bisetmap/) for more details and example code. 14 | 15 | ## Examples 16 | 17 | ```rust 18 | use bisetmap::BisetMap; 19 | 20 | let subscriptions = BisetMap::new(); 21 | 22 | // insert client-ids and subscription topics 23 | subscriptions.insert("Bob", "Tech"); 24 | subscriptions.insert("Bob", "Math"); 25 | subscriptions.insert("Alice", "Tech"); 26 | subscriptions.insert("Alice", "Romance"); 27 | 28 | // retrieve topic by client-id (left to right) 29 | assert_eq!(subscriptions.get(&"Bob"), ["Math", "Tech"]); 30 | assert_eq!(subscriptions.get(&"Alice"), ["Romance", "Tech"]); 31 | 32 | // retrieve clients by topic (right to left) 33 | assert_eq!(subscriptions.rev_get(&"Tech"), ["Alice", "Bob"]); 34 | assert_eq!(subscriptions.rev_get(&"Math"), ["Bob"]); 35 | 36 | // check membership 37 | assert!(subscriptions.contains(&"Bob", &"Math")); 38 | assert!(!subscriptions.contains(&"Bob", &"Romance")); 39 | 40 | // check key/value existence 41 | assert!(subscriptions.key_exists(&"Alice")); 42 | assert!(subscriptions.value_exists(&"Tech")); 43 | ``` 44 | 45 | ## License 46 | BisetMap is licensed under the MIT license. 47 | 48 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! A fast and thread-safe two-way hash map of sets. It is best suited where you need to associate 2 | //! two collumns uniquely. Each key is associated to one or more other unique values. 3 | //! 4 | //! A `BisetMap` is a Multi-Hash-Map between values of type `L`, called left values, and values 5 | //! of type `R`, called right values. This means every left value is associated with one or more 6 | //! right values and vice versa. Compare this to a [`HashMap`], where every key is associated with 7 | //! exactly one value. 8 | //! 9 | //! The structure is interior mutable and all operations are thread safe. Each clone provides access 10 | //! to the same underlying data. Serialize and Deserialize from serde are also implemented. 11 | //! 12 | //! Internally, a `BisetMap` is composed of two `HashMap`s, one for the left-to-right direction and 13 | //! one for right-to-left. As such, the big-O performance of the `get`, `remove`, `insert`, and 14 | //! `contains` methods are the same as those of a `HashMap`. 15 | //! 16 | //! As with `HashMap`, it is considered a logic error to modify a value's hash while it is in the 17 | //! `BisetMap` using a `Cell`, `RefCell`, etc. 18 | //! 19 | //! # Examples 20 | //! 21 | //! ``` 22 | //! use bisetmap::BisetMap; 23 | //! 24 | //! let subscriptions = BisetMap::new(); 25 | //! 26 | //! // insert client-ids and subscription topics 27 | //! subscriptions.insert("Bob", "Tech"); 28 | //! subscriptions.insert("Bob", "Math"); 29 | //! subscriptions.insert("Alice", "Tech"); 30 | //! subscriptions.insert("Alice", "Romance"); 31 | //! 32 | //! // retrieve topic by client-id (left to right) 33 | //! assert_eq!(subscriptions.get(&"Bob"), ["Math", "Tech"]); 34 | //! assert_eq!(subscriptions.get(&"Alice"), ["Romance", "Tech"]); 35 | //! 36 | //! // retrieve clients by topic (right to left) 37 | //! assert_eq!(subscriptions.rev_get(&"Tech"), ["Alice", "Bob"]); 38 | //! assert_eq!(subscriptions.rev_get(&"Math"), ["Bob"]); 39 | //! 40 | //! // check membership 41 | //! assert!(subscriptions.contains(&"Bob", &"Math")); 42 | //! assert!(!subscriptions.contains(&"Bob", &"Romance")); 43 | //! 44 | //! // check key/value existence 45 | //! assert!(subscriptions.key_exists(&"Alice")); 46 | //! assert!(subscriptions.value_exists(&"Tech")); 47 | //! ``` 48 | //! 49 | //! ## Insertion and Uniqueness 50 | //! 51 | //! Consider the following example: 52 | //! 53 | //! ``` 54 | //! use bisetmap::BisetMap; 55 | //! 56 | //! let bmap = BisetMap::new(); 57 | //! bmap.insert('a', 1); 58 | //! bmap.insert('a', 1); // what to do here? 59 | //! ``` 60 | //! 61 | //! Duplicate key-value pairs are ignored and inserted only once 62 | //! 63 | //! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html 64 | 65 | extern crate serde; 66 | 67 | use std::collections::{HashMap, HashSet}; 68 | use std::marker::PhantomData; 69 | use std::sync::{Mutex, Arc}; 70 | use std::hash::Hash; 71 | use std::fmt; 72 | 73 | use serde::de::{Deserialize, Deserializer, Visitor, MapAccess}; 74 | use serde::ser::{Serialize, Serializer, SerializeMap}; 75 | 76 | 77 | /// A two-way map between keys (left) and values (right). 78 | /// 79 | /// See the [module-level documentation] for more details and examples. 80 | /// 81 | /// [module-level documentation]: index.html 82 | #[derive(Clone)] 83 | pub struct BisetMap { 84 | hh: Arc>, HashMap>)>> 85 | } 86 | 87 | 88 | fn insert_item(h: &mut HashMap>, k: L, v: R) { 89 | let s = h.entry(k).or_insert_with(HashSet::new); 90 | s.insert(v); 91 | } 92 | 93 | fn remove_item(h: &mut HashMap>, k: L, v: &R) { 94 | if let std::collections::hash_map::Entry::Occupied(mut e) = h.entry(k) { 95 | e.get_mut().remove(v); 96 | if e.get().is_empty() { 97 | e.remove_entry(); 98 | } 99 | } 100 | } 101 | 102 | fn get_item(h: &HashMap>, k: &L) -> Vec { 103 | match h.get(k) { 104 | Some(s) => s.iter().map(Clone::clone).collect(), 105 | None => vec![] 106 | } 107 | } 108 | 109 | fn remove_items(h1: &mut HashMap>, h2: &mut HashMap>, k: &L) -> Vec { 110 | match h1.remove(k) { 111 | Some(s) => { 112 | let r = s.iter().map(Clone::clone).collect(); 113 | for v in s { 114 | remove_item(h2, v, k) 115 | } 116 | r 117 | }, 118 | None => vec![] 119 | } 120 | } 121 | 122 | impl BisetMap { 123 | /// Creates an empty `BisetMap`. 124 | /// 125 | /// # Examples 126 | /// 127 | /// ``` 128 | /// use bisetmap::BisetMap; 129 | /// 130 | /// let bmap: BisetMap = BisetMap::new(); 131 | /// ``` 132 | pub fn new() -> BisetMap { 133 | BisetMap::default() 134 | } 135 | 136 | /// Creates an empty `BisetMap` with the given capacity. 137 | /// 138 | /// # Examples 139 | /// 140 | /// ``` 141 | /// use bisetmap::BisetMap; 142 | /// 143 | /// let bmap: BisetMap = BisetMap::with_capacity(5); 144 | /// ``` 145 | pub fn with_capacity(capacity: usize) -> BisetMap { 146 | BisetMap { 147 | hh: Arc::new(Mutex::new( (HashMap::with_capacity(capacity), HashMap::with_capacity(capacity)) )) 148 | } 149 | } 150 | 151 | /// Removes all key-value pairs from the `BisetMap`, but keeps the allocated memory for reuse. 152 | /// 153 | /// # Examples 154 | /// 155 | /// ``` 156 | /// use bisetmap::BisetMap; 157 | /// 158 | /// let bmap = BisetMap::new(); 159 | /// bmap.insert('a', 1); 160 | /// bmap.insert('b', 2); 161 | /// bmap.insert('c', 3); 162 | /// bmap.clear(); 163 | /// assert!(bmap.len() == 0); 164 | /// ``` 165 | pub fn clear(&self) { 166 | let (ref mut h1, ref mut h2) = *self.hh.lock().unwrap(); 167 | h1.clear(); 168 | h2.clear(); 169 | } 170 | 171 | /// Returns a new BisetMap where keys and values are swapped. 172 | /// 173 | /// # Examples 174 | /// 175 | /// ``` 176 | /// use bisetmap::BisetMap; 177 | /// 178 | /// let bmap = BisetMap::new(); 179 | /// bmap.insert('a', 1); 180 | /// bmap.insert('b', 2); 181 | /// bmap.insert('c', 3); 182 | /// let rmap = bmap.rev(); 183 | /// assert_eq!(rmap.get(&1), ['a']); 184 | /// ``` 185 | pub fn rev(&self) -> BisetMap { 186 | let (ref h1, ref h2) = *self.hh.lock().unwrap(); 187 | BisetMap { 188 | hh: Arc::new(Mutex::new( (h2.clone(), h1.clone()) )) 189 | } 190 | } 191 | 192 | /// Returns a vector of (key,values) pairs, where values itself is a vector. 193 | /// (Order of all pairs is unknown) 194 | /// 195 | /// # Examples 196 | /// 197 | /// ``` 198 | /// use bisetmap::BisetMap; 199 | /// 200 | /// let bmap = BisetMap::new(); 201 | /// bmap.insert('a', 1); 202 | /// bmap.insert('a', 2); 203 | /// bmap.insert('b', 3); 204 | /// assert_eq!(bmap.collect(), vec![('a',vec![1,2]), ('b',vec![3])]); 205 | /// ``` 206 | pub fn collect(&self) -> Vec<(L, Vec)> { 207 | self.hh.lock().unwrap().0 208 | .iter() 209 | .map(|(l, r)| (l.clone(), r.iter().map(Clone::clone).collect())) 210 | .collect() 211 | } 212 | 213 | /// Returns a vector of (key,value) pairs. 214 | /// (Order of pairs is unknown) 215 | /// 216 | /// # Examples 217 | /// 218 | /// ``` 219 | /// use bisetmap::BisetMap; 220 | /// 221 | /// let bmap = BisetMap::new(); 222 | /// bmap.insert('a', 1); 223 | /// bmap.insert('a', 2); 224 | /// bmap.insert('b', 3); 225 | /// assert_eq!(bmap.flat_collect(), [('a',1), ('a',2), ('b',3)]); 226 | /// ``` 227 | pub fn flat_collect(&self) -> Vec<(L, R)> { 228 | self.hh.lock().unwrap().0 229 | .iter() 230 | .flat_map(|(l, rs)| rs.iter().map(move |r| (l.clone(), r.clone()))) 231 | .collect() 232 | } 233 | 234 | /// Inserts the given key-value pair into the `BisetMap`. 235 | /// 236 | /// # Examples 237 | /// 238 | /// ``` 239 | /// use bisetmap::BisetMap; 240 | /// 241 | /// let bmap = BisetMap::new(); 242 | /// bmap.insert('a', 1); 243 | /// bmap.insert('a', 1); 244 | /// bmap.insert('a', 2); 245 | /// bmap.insert('b', 3); 246 | /// assert_eq!(bmap.flat_collect(), [('a',1), ('a',2), ('b',3)]); 247 | /// ``` 248 | pub fn insert(&self, k: L, v: R) { 249 | let (ref mut h1, ref mut h2) = *self.hh.lock().unwrap(); 250 | insert_item(h1, k.clone(), v.clone()); 251 | insert_item(h2, v, k); 252 | } 253 | 254 | /// Removes the specified key-value pair from the `BisetMap`. 255 | /// 256 | /// # Examples 257 | /// 258 | /// ``` 259 | /// use bisetmap::BisetMap; 260 | /// 261 | /// let bmap = BisetMap::new(); 262 | /// bmap.insert('a', 1); 263 | /// bmap.insert('a', 1); 264 | /// bmap.insert('a', 2); 265 | /// bmap.insert('c', 3); 266 | /// assert_eq!(bmap.len(), 2); 267 | /// assert_eq!(bmap.rev_len(), 3); 268 | /// bmap.remove(&'a', &2); 269 | /// assert_eq!(bmap.len(), 2); 270 | /// assert_eq!(bmap.rev_len(), 2); 271 | /// ``` 272 | pub fn remove(&self, k: &L, v: &R) { 273 | let (ref mut h1, ref mut h2) = *self.hh.lock().unwrap(); 274 | remove_item(h1, k.clone(), &v.clone()); 275 | remove_item(h2, v.clone(), &k.clone()); 276 | } 277 | 278 | /// Returns `true` if the map contains the given key-value pair and `false` otherwise. 279 | /// 280 | /// # Examples 281 | /// 282 | /// ``` 283 | /// use bisetmap::BisetMap; 284 | /// 285 | /// let bmap = BisetMap::new(); 286 | /// bmap.insert('a', 1); 287 | /// assert!(bmap.contains(&'a', &1)); 288 | /// assert!(!bmap.contains(&'b', &1)); 289 | /// assert!(!bmap.contains(&'a', &2)); 290 | /// ``` 291 | pub fn contains(&self, k: &L, v: &R) -> bool { 292 | match self.hh.lock().unwrap().0.get(k) { 293 | Some(s) => s.contains(v), 294 | None => false 295 | } 296 | } 297 | 298 | /// Returns `true` if the map contains the given key (left) value and `false` otherwise. 299 | /// 300 | /// # Examples 301 | /// 302 | /// ``` 303 | /// use bisetmap::BisetMap; 304 | /// 305 | /// let bmap = BisetMap::new(); 306 | /// bmap.insert('a', 1); 307 | /// assert!(bmap.key_exists(&'a')); 308 | /// assert!(!bmap.key_exists(&'b')); 309 | /// ``` 310 | pub fn key_exists(&self, k: &L) -> bool { 311 | self.hh.lock().unwrap().0.contains_key(k) 312 | } 313 | 314 | /// Returns `true` if the map contains the given value (right) and `false` otherwise. 315 | /// 316 | /// # Examples 317 | /// 318 | /// ``` 319 | /// use bisetmap::BisetMap; 320 | /// 321 | /// let bmap = BisetMap::new(); 322 | /// bmap.insert('a', 1); 323 | /// assert!(bmap.value_exists(&1)); 324 | /// assert!(!bmap.value_exists(&2)); 325 | /// ``` 326 | pub fn value_exists(&self, v: &R) -> bool { 327 | self.hh.lock().unwrap().1.contains_key(v) 328 | } 329 | 330 | /// Returns a vector of values (right) corresponding to the given key (left). 331 | /// 332 | /// # Examples 333 | /// 334 | /// ``` 335 | /// use bisetmap::BisetMap; 336 | /// 337 | /// let bmap = BisetMap::new(); 338 | /// bmap.insert('a', 1); 339 | /// assert_eq!(bmap.get(&'a'), [1]); 340 | /// assert_eq!(bmap.get(&'z'), []); 341 | /// ``` 342 | pub fn get(&self, k: &L) -> Vec { 343 | get_item(&self.hh.lock().unwrap().0, &k) 344 | } 345 | 346 | /// Returns a vector of keys (left) corresponding to the given value (right). 347 | /// 348 | /// # Examples 349 | /// 350 | /// ``` 351 | /// use bisetmap::BisetMap; 352 | /// 353 | /// let bmap = BisetMap::new(); 354 | /// bmap.insert('a', 1); 355 | /// assert_eq!(bmap.rev_get(&1), ['a']); 356 | /// assert_eq!(bmap.rev_get(&2), []); 357 | /// ``` 358 | pub fn rev_get(&self, v: &R) -> Vec { 359 | get_item(&self.hh.lock().unwrap().1, &v) 360 | } 361 | 362 | /// Removes the specified key and all values associated with it. 363 | /// 364 | /// Returns a vector of previous values associated with given key. 365 | /// 366 | /// # Examples 367 | /// 368 | /// ``` 369 | /// use bisetmap::BisetMap; 370 | /// 371 | /// let bmap = BisetMap::new(); 372 | /// bmap.insert('a', 1); 373 | /// bmap.insert('a', 2); 374 | /// bmap.insert('c', 3); 375 | /// assert_eq!(bmap.delete(&'a'), [1, 2]); 376 | /// assert_eq!(bmap.len(), 1); 377 | /// ``` 378 | pub fn delete(&self, k: &L) -> Vec { 379 | let (ref mut h1, ref mut h2) = *self.hh.lock().unwrap(); 380 | remove_items(h1, h2, &k) 381 | } 382 | 383 | /// Removes the specified value and all keys associated with it. 384 | /// 385 | /// Returns a vector of previous keys associated with given value. 386 | /// 387 | /// # Examples 388 | /// 389 | /// ``` 390 | /// use bisetmap::BisetMap; 391 | /// 392 | /// let bmap = BisetMap::new(); 393 | /// bmap.insert('a', 1); 394 | /// bmap.insert('b', 1); 395 | /// bmap.insert('c', 2); 396 | /// assert_eq!(bmap.rev_delete(&1), ['a', 'b']); 397 | /// assert_eq!(bmap.len(), 1); 398 | /// ``` 399 | pub fn rev_delete(&self, v: &R) -> Vec { 400 | let (ref mut h1, ref mut h2) = *self.hh.lock().unwrap(); 401 | remove_items(h2, h1, &v) 402 | } 403 | 404 | /// Returns the number of unique keys (left). 405 | /// 406 | /// # Examples 407 | /// 408 | /// ``` 409 | /// use bisetmap::BisetMap; 410 | /// 411 | /// let bmap = BisetMap::new(); 412 | /// bmap.insert('a', 1); 413 | /// bmap.insert('b', 2); 414 | /// bmap.insert('c', 3); 415 | /// bmap.insert('c', 4); 416 | /// assert_eq!(bmap.len(), 3); 417 | /// ``` 418 | pub fn len(&self) -> usize { 419 | self.hh.lock().unwrap().0.len() 420 | } 421 | 422 | /// Returns the number of unique values (right). 423 | /// 424 | /// # Examples 425 | /// 426 | /// ``` 427 | /// use bisetmap::BisetMap; 428 | /// 429 | /// let bmap = BisetMap::new(); 430 | /// bmap.insert('a', 1); 431 | /// bmap.insert('b', 2); 432 | /// bmap.insert('c', 3); 433 | /// bmap.insert('d', 3); 434 | /// assert_eq!(bmap.rev_len(), 3); 435 | /// ``` 436 | pub fn rev_len(&self) -> usize { 437 | self.hh.lock().unwrap().1.len() 438 | } 439 | 440 | /// Returns `true` if the map contains no key-value pairs, and `false` otherwise. 441 | /// 442 | /// # Examples 443 | /// 444 | /// ``` 445 | /// use bisetmap::BisetMap; 446 | /// 447 | /// let bmap = BisetMap::new(); 448 | /// assert!(bmap.is_empty()); 449 | /// bmap.insert('a', 1); 450 | /// assert!(!bmap.is_empty()); 451 | /// bmap.rev_delete(&1); 452 | /// assert!(bmap.is_empty()); 453 | /// ``` 454 | pub fn is_empty(&self) -> bool { 455 | self.hh.lock().unwrap().0.is_empty() 456 | } 457 | } 458 | 459 | 460 | impl Default for BisetMap { 461 | fn default() -> BisetMap { 462 | BisetMap { 463 | hh: Arc::new(Mutex::new( (HashMap::default(), HashMap::default()) )) 464 | } 465 | } 466 | } 467 | 468 | impl fmt::Debug for BisetMap { 469 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 470 | write!(f, "{{")?; 471 | for (i, (left, right)) in self.hh.lock().unwrap().0.iter().enumerate() { 472 | let comma = if i == 0 { "" } else { ", " }; 473 | write!(f, "{}{:?} => {:?}", comma, left, right)?; 474 | } 475 | write!(f, "}}")?; 476 | Ok(()) 477 | } 478 | } 479 | 480 | 481 | 482 | 483 | 484 | impl Serialize for BisetMap { 485 | fn serialize(&self, serializer: S) -> Result { 486 | let data = self.collect(); 487 | let mut map = serializer.serialize_map(Some(data.len()))?; 488 | for (k, v) in data { 489 | map.serialize_entry(&k, &v)?; 490 | } 491 | map.end() 492 | } 493 | } 494 | 495 | 496 | struct BisetMapVisitor { 497 | marker: PhantomData BisetMap> 498 | } 499 | 500 | impl BisetMapVisitor { 501 | fn new() -> Self { 502 | BisetMapVisitor { 503 | marker: PhantomData 504 | } 505 | } 506 | } 507 | 508 | impl<'de, L:Eq+Hash+Clone+Deserialize<'de>, R:Eq+Hash+Clone+Deserialize<'de>> Visitor<'de> for BisetMapVisitor { 509 | type Value = BisetMap; 510 | 511 | fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { 512 | formatter.write_str("a biset map") 513 | } 514 | 515 | fn visit_map>(self, mut access: M) -> Result { 516 | let bmap = BisetMap::with_capacity(access.size_hint().unwrap_or(0)); 517 | while let Some((key, values)) = access.next_entry::>()? { 518 | for value in values { 519 | bmap.insert(key.clone(), value); 520 | } 521 | } 522 | Ok(bmap) 523 | } 524 | } 525 | 526 | impl<'de, L:Eq+Hash+Clone+Deserialize<'de>, R:Eq+Hash+Clone+Deserialize<'de>> Deserialize<'de> for BisetMap { 527 | fn deserialize>(deserializer: D) -> Result { 528 | deserializer.deserialize_map(BisetMapVisitor::new()) 529 | } 530 | } 531 | 532 | 533 | 534 | 535 | 536 | 537 | #[cfg(test)] 538 | mod tests { 539 | use BisetMap; 540 | 541 | #[test] 542 | fn test1() { 543 | let h = BisetMap::new(); 544 | h.insert("sdf", "sdfsd"); 545 | h.insert("sdf", "sdfsd"); 546 | h.insert("a", "1"); 547 | h.insert("b", "1"); 548 | h.insert("c", "2"); 549 | h.insert("c", "3"); 550 | h.insert("c", "4"); 551 | 552 | println!("{:?}", h); 553 | println!("{:?}", h.rev()); 554 | println!("{:?}", h.collect()); 555 | } 556 | 557 | #[test] 558 | fn clone_works_with_same_internal_memory() { 559 | let h1 = BisetMap::new(); 560 | let h2 = h1.clone(); 561 | h1.insert("hello", "world"); 562 | assert_eq!(h2.get(&"hello"), ["world"]); 563 | } 564 | 565 | #[test] 566 | fn test_len_function() { 567 | let h = BisetMap::new(); 568 | assert_eq!(h.len(), 0); 569 | assert_eq!(h.rev_len(),0); 570 | 571 | h.insert("a", "1"); 572 | h.insert("b", "1"); 573 | h.insert("c", "2"); 574 | assert_eq!(h.len(), 3); 575 | assert_eq!(h.rev_len(),2); 576 | 577 | h.rev_delete(&"1"); 578 | assert_eq!(h.len(), 1); 579 | assert_eq!(h.rev_len(),1); 580 | } 581 | 582 | #[test] 583 | fn is_empty_after_removal() { 584 | let h = BisetMap::new(); 585 | assert!(h.is_empty()); 586 | 587 | h.insert("a", "1"); 588 | h.insert("b", "1"); 589 | h.insert("c", "2"); 590 | assert!(!h.is_empty()); 591 | 592 | h.rev_delete(&"1"); 593 | h.delete(&"c"); 594 | assert!(h.is_empty()); 595 | } 596 | } 597 | --------------------------------------------------------------------------------