stable_gen_map
A single-threaded, generational map that lets you:
- insert with
&selfinstead of&mut self, - keep
&Tstable across internal resizes, - and use generational keys to avoid use-after-free bugs.
It’s designed for patterns like graphs, self-referential structures, and arenas where you want to keep &T references around while still inserting new elements, and you want to be able to defer the removal of elements, such as, at the end of a videogame's frame, or turn.
Great for patterns that rely on shared mutability on a single thread.
Important: This crate is intentionally single-threaded. The map types are not
Sync, and are meant to be used from a single thread only.
Core types
-
StableGenMap<K, T>
A stable generational map storingTinline. This is generally what you would want -
StablePagedGenMap<K, T, const SLOTS_NUM_PER_PAGE: usize>
Same semantics asStableGenMap, but uses multiple slots in a page for better cache locality when you have lots of elements, at the exchange of a slower 'get' -
StableDerefGenMap<K, Derefable>
A stable generational map where each element is a smart pointer that implementsDerefGenMapPromise. You get stable references toDeref::Target, even if the underlyingVecreallocates.
This is the “advanced” variant forBox<T>,Rc<T>,Arc<T>,&T, or custom smart pointers. -
BoxStableDerefGenMap<K, T>
Type alias forStableDerefGenMap<K, Box<T>>.
This is the most ergonomic “owning” deref-based map: the map ownsTviaBox<T>, you still insert with&self, and you get stable&T/&mut Treferences. Best used if your element needs to be boxed anyways.
Keys implement the Key trait; you can use the provided DefaultKey or define your own (e.g. with smaller index / generation types).
What you get
insert(&self, value: T) -> (K, &T)insert_with_key(&self, f: impl FnOnce(K) -> T) -> (K, &T)try_insert_with_key(&self, f: impl FnOnce(K) -> Result<T, E>) -> Result<(K, &T), E>
All of these only need &self, not &mut self.
get(&self, key: K) -> Option<&T>get_mut(&mut self, key: K) -> Option<&mut T>remove(&mut self, key: K) -> Option<T>len(&self) -> usizeclear(&mut self)
Complexity
get/get_mut/removeare O(1).insertis O(1) amortized (O(1) unless a resize happens).
Lifetime / safety model
- You can hold
&Tfrom the map and still callinsert(which only needs&self). removeandclearneed&mut self, so you can’t free elements while there are outstanding borrows – enforced by the borrow-checker.- Generational keys (
Key::Gen) mean stale keys simply returnNoneinstead of aliasing newly inserted elements.
Basic example (using StableGenMap)
This shows the main selling point: insert with &self and indirect references via keys.
use ;
use DefaultKey;
use StableGenMap;