rc_hashmap/lib.rs
1//! rc-hashmap: A single-threaded, handle-based map with Rc-like
2//! references to entries that allow fast access and cleanup on drop.
3//!
4//! Internal Design:
5//!
6//! Summary
7//! - Goal: build RcHashMap in safe, verifiable layers so each piece can
8//! be reasoned about independently.
9//! - Layers:
10//! - HandleHashMap<K, V, S>: structural map that returns stable
11//! handles for O(1) average access without re-hashing; includes a
12//! debug-only reentrancy guard to keep internals consistent while
13//! mutating.
14//! - CountedHashMap<K, V, S>: wraps HandleHashMap and adds per-entry
15//! reference counting (increments on get/clone, decrements on put).
16//! - RcHashMap<K, V, S>: public API that exposes `Ref` handles; drops
17//! free entries when the last `Ref` is dropped.
18//!
19//! Constraints
20//! - Single-threaded: `!Send`/`!Sync` by design (no atomics).
21//! - No per-entry heap allocations beyond the map’s own storage.
22//! - Stable, generational keys behind small `Handle` wrappers.
23//! - O(1) average lookups with unique keys; duplicate inserts fail.
24//! - Reentrancy: disallowed during critical sections of HandleHashMap
25//! (only `K: Eq/Hash` may run); allowed elsewhere.
26//!
27//! Why this split?
28//! - Localize invariants: each layer has a small, precise contract.
29//! - Minimize unsafe: raw-pointer handling is isolated in `tokens::RcCount`;
30//! structural indexing uses safe Rust.
31//! - Clear failure boundaries: HandleHashMap never calls into user code
32//! once the structure is consistent.
33//!
34//! Reentrancy policy and interior mutability
35//! - HandleHashMap employs an internal exclusive-access discipline and a
36//! debug-only reentrancy guard at the start of each method to prevent
37//! nested entry while its internal state can be transiently
38//! inconsistent. These methods only invoke user code via `K: Eq/Hash`
39//! during probing.
40//! - Upper layers (CountedHashMap, RcHashMap) rely on HandleHashMap’s
41//! guarantees and do not need their own guard. After
42//! `HandleHashMap::remove` returns `(K, V)`, the structure is again
43//! consistent; `Drop` for `K`/`V` may reenter safely.
44//!
45//! Overflow semantics
46//! - Reference-count overflow is considered undefined behavior, matching
47//! `Rc`. The crate assumes there are fewer than `usize::MAX` references
48//! to any entry; no runtime checks are performed.
49//!
50//! Hasher and rehashing invariants
51//! - Each entry stores a precomputed `u64` hash and indexing always uses
52//! the stored hash; `K: Hash` is never invoked after insertion. This
53//! avoids rehash-time calls into user code.
54//!
55//! Notes and non-goals
56//! - Still single-threaded; enforced with marker types on `Ref`/`Inner`.
57//! - No weak handles (could be added later).
58//! - No explicit `clear()`/`remove()`/`drain()` on RcHashMap; removal
59//! occurs when the last `Ref` is dropped to preserve refcount
60//! semantics.
61//! - RcHashMap does not implement `Clone`.
62//! - Keys are immutable post-insert; there is no `key_mut`.
63//! - Public API surface is `RcHashMap` and its `Ref`; lower layers are
64//! implementation details.
65//!
66//! Implementation note
67//! - The internal `RcCount<T>` helper (in `tokens`) encapsulates the
68//! raw-pointer based use of `std::rc::Rc` increment/decrement APIs.
69
70pub mod counted_hash_map;
71pub mod handle_hash_map;
72mod handle_hash_map_proptest;
73pub mod hash;
74mod rc_hash_map;
75mod reentrancy;
76pub mod tokens;
77
78// Public surface
79pub use handle_hash_map::InsertError;
80pub use hash::DefaultHashBuilder;
81pub use rc_hash_map::{RcHashMap, Ref};