1# weak-table: weak hash maps and sets for Rust 2 3[](https://github.com/tov/weak-table-rs/actions) 4[](https://crates.io/crates/weak-table) 5[](LICENSE-MIT) 6 7This crate defines several kinds of weak hash maps and sets. See 8the [full API documentation](http://docs.rs/weak-table/) for details. 9 10### Rust version support 11 12This crate supports Rust version 1.46 and later. 13 14### Crate features 15 16`weak-table` is built with the `std` feature, which enables 17functionality dependent on the `std` library, enabled by default. 18Optionally, the following dependency may be enabled: 19 20 - `ahash`: use `ahash`’s hasher rather than the `std` hasher 21 22If the `std` feature is disabled (for no_std) then the `ahash` dependency **must** be enabled. 23 24### Examples 25 26Here we create a weak hash map and demonstrate that it forgets mappings 27whose keys expire: 28 29```rust 30use weak_table::WeakKeyHashMap; 31use std::sync::{Arc, Weak}; 32 33let mut table = <WeakKeyHashMap<Weak<str>, u32>>::new(); 34let one = Arc::<str>::from("one"); 35let two = Arc::<str>::from("two"); 36 37table.insert(one.clone(), 1); 38 39assert_eq!( table.get("one"), Some(&1) ); 40assert_eq!( table.get("two"), None ); 41 42table.insert(two.clone(), 2); 43*table.get_mut(&one).unwrap() += 10; 44 45assert_eq!( table.get("one"), Some(&11) ); 46assert_eq!( table.get("two"), Some(&2) ); 47 48drop(one); 49 50assert_eq!( table.get("one"), None ); 51assert_eq!( table.get("two"), Some(&2) ); 52``` 53 54Here we use a weak hash set to implement a simple string interning facility: 55 56```rust 57use weak_table::WeakHashSet; 58use std::ops::Deref; 59use std::rc::{Rc, Weak}; 60 61#[derive(Clone, Debug)] 62pub struct Symbol(Rc<str>); 63 64impl PartialEq for Symbol { 65 fn eq(&self, other: &Symbol) -> bool { 66 Rc::ptr_eq(&self.0, &other.0) 67 } 68} 69 70impl Eq for Symbol {} 71 72impl Deref for Symbol { 73 type Target = str; 74 fn deref(&self) -> &str { 75 &self.0 76 } 77} 78 79#[derive(Debug, Default)] 80pub struct SymbolTable(WeakHashSet<Weak<str>>); 81 82impl SymbolTable { 83 pub fn new() -> Self { 84 Self::default() 85 } 86 87 pub fn intern(&mut self, name: &str) -> Symbol { 88 if let Some(rc) = self.0.get(name) { 89 Symbol(rc) 90 } else { 91 let rc = Rc::<str>::from(name); 92 self.0.insert(Rc::clone(&rc)); 93 Symbol(rc) 94 } 95 } 96} 97 98#[test] 99fn interning() { 100 let mut tab = SymbolTable::new(); 101 102 let a0 = tab.intern("a"); 103 let a1 = tab.intern("a"); 104 let b = tab.intern("b"); 105 106 assert_eq!(a0, a1); 107 assert_ne!(a0, b); 108} 109``` 110 111