1# weak-table: weak hash maps and sets for Rust
2
3[![Build Status](https://travis-ci.org/tov/weak-table-rs.svg?branch=master)](https://travis-ci.org/tov/weak-table-rs)
4[![Crates.io](https://img.shields.io/crates/v/weak-table.svg?maxAge=2592000)](https://crates.io/crates/weak-table)
5[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](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
10This crate supports Rust version 1.32 and later.
11
12### Examples
13
14Here we create a weak hash map and demonstrate that it forgets mappings
15whose keys expire:
16
17```rust
18use weak_table::WeakKeyHashMap;
19use std::sync::{Arc, Weak};
20
21let mut table = <WeakKeyHashMap<Weak<str>, u32>>::new();
22let one = Arc::<str>::from("one");
23let two = Arc::<str>::from("two");
24
25table.insert(one.clone(), 1);
26
27assert_eq!( table.get("one"), Some(&1) );
28assert_eq!( table.get("two"), None );
29
30table.insert(two.clone(), 2);
31*table.get_mut(&one).unwrap() += 10;
32
33assert_eq!( table.get("one"), Some(&11) );
34assert_eq!( table.get("two"), Some(&2) );
35
36drop(one);
37
38assert_eq!( table.get("one"), None );
39assert_eq!( table.get("two"), Some(&2) );
40```
41
42Here we use a weak hash set to implement a simple string interning facility:
43
44```rust
45use weak_table::WeakHashSet;
46use std::ops::Deref;
47use std::rc::{Rc, Weak};
48
49#[derive(Clone, Debug)]
50pub struct Symbol(Rc<str>);
51
52impl PartialEq for Symbol {
53    fn eq(&self, other: &Symbol) -> bool {
54        Rc::ptr_eq(&self.0, &other.0)
55    }
56}
57
58impl Eq for Symbol {}
59
60impl Deref for Symbol {
61    type Target = str;
62    fn deref(&self) -> &str {
63        &self.0
64    }
65}
66
67#[derive(Debug, Default)]
68pub struct SymbolTable(WeakHashSet<Weak<str>>);
69
70impl SymbolTable {
71    pub fn new() -> Self {
72        Self::default()
73    }
74
75    pub fn intern(&mut self, name: &str) -> Symbol {
76        if let Some(rc) = self.0.get(name) {
77            Symbol(rc)
78        } else {
79            let rc = Rc::<str>::from(name);
80            self.0.insert(Rc::clone(&rc));
81            Symbol(rc)
82        }
83    }
84}
85
86#[test]
87fn interning() {
88    let mut tab = SymbolTable::new();
89
90    let a0 = tab.intern("a");
91    let a1 = tab.intern("a");
92    let b  = tab.intern("b");
93
94    assert_eq!(a0, a1);
95    assert_ne!(a0, b);
96}
97```
98
99