111 lines
2.6 KiB
Markdown
111 lines
2.6 KiB
Markdown
|
# weak-table: weak hash maps and sets for Rust
|
|||
|
|
|||
|
[![Build Status](https://github.com/tov/weak-table-rs/actions/workflows/ci.yml/badge.svg)](https://github.com/tov/weak-table-rs/actions)
|
|||
|
[![Crates.io](https://img.shields.io/crates/v/weak-table.svg?maxAge=2592000)](https://crates.io/crates/weak-table)
|
|||
|
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)
|
|||
|
|
|||
|
This crate defines several kinds of weak hash maps and sets. See
|
|||
|
the [full API documentation](http://docs.rs/weak-table/) for details.
|
|||
|
|
|||
|
### Rust version support
|
|||
|
|
|||
|
This crate supports Rust version 1.46 and later.
|
|||
|
|
|||
|
### Crate features
|
|||
|
|
|||
|
`weak-table` is built with the `std` feature, which enables
|
|||
|
functionality dependent on the `std` library, enabled by default.
|
|||
|
Optionally, the following dependency may be enabled:
|
|||
|
|
|||
|
- `ahash`: use `ahash`’s hasher rather than the `std` hasher
|
|||
|
|
|||
|
If the `std` feature is disabled (for no_std) then the `ahash` dependency **must** be enabled.
|
|||
|
|
|||
|
### Examples
|
|||
|
|
|||
|
Here we create a weak hash map and demonstrate that it forgets mappings
|
|||
|
whose keys expire:
|
|||
|
|
|||
|
```rust
|
|||
|
use weak_table::WeakKeyHashMap;
|
|||
|
use std::sync::{Arc, Weak};
|
|||
|
|
|||
|
let mut table = <WeakKeyHashMap<Weak<str>, u32>>::new();
|
|||
|
let one = Arc::<str>::from("one");
|
|||
|
let two = Arc::<str>::from("two");
|
|||
|
|
|||
|
table.insert(one.clone(), 1);
|
|||
|
|
|||
|
assert_eq!( table.get("one"), Some(&1) );
|
|||
|
assert_eq!( table.get("two"), None );
|
|||
|
|
|||
|
table.insert(two.clone(), 2);
|
|||
|
*table.get_mut(&one).unwrap() += 10;
|
|||
|
|
|||
|
assert_eq!( table.get("one"), Some(&11) );
|
|||
|
assert_eq!( table.get("two"), Some(&2) );
|
|||
|
|
|||
|
drop(one);
|
|||
|
|
|||
|
assert_eq!( table.get("one"), None );
|
|||
|
assert_eq!( table.get("two"), Some(&2) );
|
|||
|
```
|
|||
|
|
|||
|
Here we use a weak hash set to implement a simple string interning facility:
|
|||
|
|
|||
|
```rust
|
|||
|
use weak_table::WeakHashSet;
|
|||
|
use std::ops::Deref;
|
|||
|
use std::rc::{Rc, Weak};
|
|||
|
|
|||
|
#[derive(Clone, Debug)]
|
|||
|
pub struct Symbol(Rc<str>);
|
|||
|
|
|||
|
impl PartialEq for Symbol {
|
|||
|
fn eq(&self, other: &Symbol) -> bool {
|
|||
|
Rc::ptr_eq(&self.0, &other.0)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
impl Eq for Symbol {}
|
|||
|
|
|||
|
impl Deref for Symbol {
|
|||
|
type Target = str;
|
|||
|
fn deref(&self) -> &str {
|
|||
|
&self.0
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#[derive(Debug, Default)]
|
|||
|
pub struct SymbolTable(WeakHashSet<Weak<str>>);
|
|||
|
|
|||
|
impl SymbolTable {
|
|||
|
pub fn new() -> Self {
|
|||
|
Self::default()
|
|||
|
}
|
|||
|
|
|||
|
pub fn intern(&mut self, name: &str) -> Symbol {
|
|||
|
if let Some(rc) = self.0.get(name) {
|
|||
|
Symbol(rc)
|
|||
|
} else {
|
|||
|
let rc = Rc::<str>::from(name);
|
|||
|
self.0.insert(Rc::clone(&rc));
|
|||
|
Symbol(rc)
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#[test]
|
|||
|
fn interning() {
|
|||
|
let mut tab = SymbolTable::new();
|
|||
|
|
|||
|
let a0 = tab.intern("a");
|
|||
|
let a1 = tab.intern("a");
|
|||
|
let b = tab.intern("b");
|
|||
|
|
|||
|
assert_eq!(a0, a1);
|
|||
|
assert_ne!(a0, b);
|
|||
|
}
|
|||
|
```
|
|||
|
|