An interning crate for Rust with no dependencies and no unsafe code
(#![forbid(unsafe_code)]
). Most existing interning crates only offer interning
strings. This crate allows interning paths and byte buffers as well.
This crate uses a HashSet
and a Vec
to store its entries. When a value is
looked up, if it cannot be found in the HashSet
, it is assigned a slot in the
Vec
. Future lookups will return a clone to the Arc
-wrapped data.
When the final reference to a Pooled<T>
value is dropped, the pool's HashMap
has the value removed and the Vec
's slot is made available for re-use.
This crate does not do sub-value interning. Each value is stored independently with its own allocation.
Hash
for Pooled ValuesThe Pooled<T>
type implements Hash
by hashing its internal unique id rather
than using T::hash()
. This allows pooled objects to be used as efficent keys
in hash maps and sets.
Because T::hash()
is different than Pooled<T>::hash()
, Pooled<T>
does not
implement Borrow<T>
. This prevents using an &str
to look up a value in a
HashMap
.
Another important caveat of using Pooled<T>
values as keys in a hash-based
collection is that all Pooled<T>
values must be from the same pool. Using
values from separate pools will cause lookups to be unable to find the contained
keys in most situations. When using this unsupported flow, incorrect matches
will never occur because Pooled<T>::eq()
is implemented to verify the values
are from the same pool, otherwise the underlying values are compared.
```rust use interner::global::{GlobalString, GlobalPool};
static STRINGS: GlobalPool
let mystring = STRINGS.get("hello"); let othercopy = STRINGS.get(String::from("hello"));
// Both my_string
and other_copy
are pointing to the same underlying string.
assert!(GlobalString::ptreq(&mystring, &other_copy));
```
```rust use interner::shared::{StringPool, SharedString};
let pool = StringPool::default(); let mystring = pool.get("hello"); let othercopy = pool.get(String::from("hello"));
// Both my_string
and other_copy
are pointing to the same underlying string.
assert!(SharedString::ptreq(&mystring, &other_copy));
```
```rust use std::path::{Path, PathBuf}; use interner::global::{GlobalPath, GlobalPool};
static PATHS: GlobalPool
let mypath = PATHS.get(Path::new("hello")); let othercopy = PATHS.get(PathBuf::from("hello"));
// Both my_path
and other_copy
are pointing to the same underlying path.
assert!(GlobalPath::ptreq(&mypath, &other_copy));
```
```rust use std::path::{Path, PathBuf}; use interner::shared::{PathPool, SharedPath};
let pool = PathPool::default(); let mystring = pool.get(Path::new("hello")); let othercopy = pool.get(PathBuf::from("hello"));
// Both my_path
and other_copy
are pointing to the same underlying path.
assert!(SharedPath::ptreq(&mystring, &other_copy));
```
```rust use interner::global::{GlobalBuffer, GlobalPool};
static BUFFERS: GlobalPool
let mybuffer = BUFFERS.get(&b"hello"[..]); let othercopy = BUFFERS.get(b"hello".to_vec());
// Both my_buffer
and other_copy
are pointing to the same underlying path.
assert!(GlobalBuffer::ptreq(&mybuffer, &other_copy));
```
```rust use interner::shared::{BufferPool, SharedBuffer};
let pool = BufferPool::default(); let mybuffer = pool.get(&b"hello"[..]); let othercopy = pool.get(b"hello".to_vec());
// Both my_path
and other_copy
are pointing to the same underlying path.
assert!(SharedBuffer::ptreq(&mybuffer, &other_copy));
```
This project, like all projects from Khonsu Labs, are open-source. This repository is available under the MIT License or the Apache License 2.0.
To learn more about contributing, please see CONTRIBUTING.md.