gen_map/lib.rs
1//! A generational map with a configurable key.
2//!
3//! [`GenMap`] stores values and hands out a [`Key`] for each one. A key stays
4//! valid until its value is removed, and by default it never matches a value
5//! that later takes the same slot. The only exceptions are a config that
6//! wraps generations and [`reset`](GenMap::reset), both described below.
7//! That makes keys safe to hold on to where plain indices or references are
8//! not, such as in graphs, entity systems and anything else that refers to
9//! values by handle.
10//!
11//! Inserting, removing and looking up a value are all O(1). The crate is
12//! `no_std`, and it only needs an allocator for storage that uses the heap,
13//! such as `Vec`. The `Vec` storage comes from the `alloc` feature, which is
14//! on by default and can be turned off. See [Cargo features](#cargo-features).
15//!
16//! # Examples
17//!
18//! ```
19//! use gen_map::GenMap;
20//!
21//! let mut map = GenMap::new();
22//! let a = map.insert("a");
23//! let b = map.insert("b");
24//! assert_eq!(map[a], "a");
25//!
26//! assert_eq!(map.remove(a), Some("a"));
27//! assert!(map.get(a).is_none());
28//!
29//! // `c` takes the slot `a` had, but `a` still does not match the new value.
30//! let c = map.insert("c");
31//! assert_eq!(c.idx(), a.idx());
32//! assert!(map.get(a).is_none());
33//! assert_eq!(map[c], "c");
34//!
35//! for (key, value) in &map {
36//! assert!(key == b || key == c);
37//! assert!(*value == "b" || *value == "c");
38//! }
39//! ```
40//!
41//! # How it works
42//!
43//! The map keeps its values in a list of slots. A key is the index of a slot
44//! together with the slot's generation at the time the key was handed out,
45//! and [`Key::idx`] and [`Key::generation`] read the two back. A slot's
46//! generation goes up by one on every insert and every remove, so it is odd
47//! while the slot holds a value and even while it does not. A key only
48//! matches its slot while the two generations are equal, so removing a value
49//! invalidates every copy of its key at once, and the next value in that
50//! slot gets a key with a newer generation.
51//!
52//! Freed slots go on a free list and are reused before the map adds new
53//! ones, so the map only grows when no slot is free.
54//!
55//! # Configuring the map
56//!
57//! A [`Config`] decides four things.
58//!
59//! - [`Idx`](Config::Idx) and [`Gen`](Config::Gen) are the integer types of
60//! the index and the generation. Any type that implements [`KeyPiece`]
61//! works, which is every unsigned integer from `u8` to `u128`, and
62//! `usize`.
63//! - [`Layout`](Config::Layout) is how a key stores the generation and index. [`Split`] keeps
64//! them as two fields and [`Packed`] puts them in the bits of one integer.
65//! - [`Storage`](Config::Storage) is the collection the slots live in, such
66//! as a `Vec`.
67//! - [`WRAP_ON_OVERFLOW`](Config::WRAP_ON_OVERFLOW) says what happens to a
68//! slot whose generation runs out.
69//!
70//! [`DefaultConfig`] is the config a [`GenMap`] uses when none is named. Its
71//! keys are a `u32` index and a `u32` generation stored as two fields, its
72//! slots live in a `Vec`, and a slot retires when its generation runs out.
73//!
74//! A config is only used as a type parameter and never created as a value,
75//! so an empty struct is enough.
76//!
77//! ```
78//! use gen_map::{Config, GenMap, Split};
79//!
80//! /// A `u8` index and a `u8` generation, so keys are two bytes and the map
81//! /// holds at most 256 slots.
82//! struct Tiny;
83//!
84//! impl Config for Tiny {
85//! type Idx = u8;
86//! type Gen = u8;
87//! type Layout = Split;
88//! type Storage<S> = Vec<S>;
89//! }
90//!
91//! let mut map = GenMap::<u64, Tiny>::new_with_config();
92//! let key = map.insert(7);
93//! assert_eq!(core::mem::size_of_val(&key), 2);
94//! assert_eq!(map[key], 7);
95//! ```
96//!
97//! [`GenMap::new`] only exists for the default config. Rust does not use a
98//! default type parameter when it infers types, so a `new` that took any
99//! config would need the config written out on every call. Any other config
100//! goes through [`GenMap::new_with_config`].
101//!
102//! ## Key layouts
103//!
104//! [`Split`] stores the index and the generation as two fields, so a key is
105//! as large as the two together, plus any padding their alignment needs.
106//! The index and the generation can each use every value of their type.
107//!
108//! [`Packed`] stores them in the bits of one integer instead. `Packed<R,
109//! GEN_BITS>` gives the low `GEN_BITS` bits of an `R` to the generation and
110//! the bits above them to the index, so a key is as large as `R`, and the two
111//! parts can have any bit counts that add up to the bits of `R`. The config's
112//! `Idx` and `Gen` only have to be wide enough for their parts, and a config
113//! whose bit counts do not add up fails to compile.
114//!
115//! ```
116//! use gen_map::{Config, GenMap, Key, Packed};
117//!
118//! /// Four byte keys with 24 bits of index and 8 bits of generation.
119//! struct Compact;
120//!
121//! impl Config for Compact {
122//! type Idx = u32;
123//! type Gen = u8;
124//! type Layout = Packed<u32, 8>;
125//! type Storage<S> = Vec<S>;
126//! }
127//!
128//! let mut map = GenMap::<&str, Compact>::new_with_config();
129//! let key = map.insert("a");
130//! assert_eq!(core::mem::size_of::<Key<Compact>>(), 4);
131//! assert_eq!(map[key], "a");
132//! ```
133//!
134//! With either layout, `Option<Key>` is the same size as `Key`.
135//!
136//! ## When a generation runs out
137//!
138//! A slot's generation can only go up to the largest one its key can hold,
139//! which is `Gen::MAX` for [`Split`] and the largest value of the generation
140//! part for [`Packed`]. Each value a slot holds uses up two generations, one
141//! when it is inserted and one when it is removed, so a `u32` generation lets
142//! a slot hold over two billion values, while a 4 bit generation lets it hold
143//! eight. What happens to a slot after that is up to
144//! [`WRAP_ON_OVERFLOW`](Config::WRAP_ON_OVERFLOW).
145//!
146//! By default, the slot retires. It stays in the storage but is never used
147//! again, so no stale key can ever match a new value.
148//!
149//! When `WRAP_ON_OVERFLOW` is `true`, the generation wraps back to zero and
150//! the slot is reused. No slot is ever lost, but a key that is old enough can
151//! match a new value once the generation wraps around to it again.
152//!
153//! [`retire`](GenMap::retire) removes a value and retires its slot, no
154//! matter how the map is configured. Code built on a map that wraps can use
155//! it to keep the slots it chooses from wrapping, and
156//! [`Key::is_max_generation`] can be used to determine when a slot has reached that point.
157//!
158//! ## Storage
159//!
160//! The slots can live in any collection that implements [`SlotStorage`]. A
161//! `Vec` does, and so do two collections from other crates when their
162//! features are on. `ArrayVec` from `arrayvec` has a fixed capacity and
163//! never allocates, and `SmallVec` from `smallvec` keeps a few slots inline
164//! before it allocates. [`SlotStorage`] is an unsafe trait, because the map
165//! relies on the storage behaving like a `Vec` when it reads slots without
166//! bounds checks.
167//!
168//! The methods that make room ahead of time, which are
169//! [`reserve`](GenMap::reserve), [`try_reserve`](GenMap::try_reserve),
170//! [`with_capacity`](GenMap::with_capacity) and
171//! [`with_capacity_and_config`](GenMap::with_capacity_and_config), only
172//! exist when the storage also implements [`ReserveStorage`], as `Vec` and
173//! `SmallVec` do.
174//!
175//! # When the map is full
176//!
177//! A map is full when none of its slots are free, and it can not add another
178//! one, either because its keys have no index left for a new slot or because
179//! the storage can not make room for one. A `u8` index, for example, allows
180//! 256 slots.
181//!
182//! [`insert`](GenMap::insert) panics on a full map. The other ways to insert
183//! report a full map as an error.
184//!
185//! - [`try_insert`](GenMap::try_insert) returns an [`InsertError`] that hands
186//! the value back.
187//! - [`vacant_entry`](GenMap::vacant_entry) picks the slot before the value
188//! exists, and returns a [`FullError`] if there is none. The entry's
189//! [`key`](VacantEntry::key) is the key the value will get, and dropping
190//! the entry leaves the map as it was.
191//! - [`try_insert_with_key`](GenMap::try_insert_with_key) runs a closure that
192//! may fail, and returns an [`InsertWithError`] if the map is full or the
193//! closure fails.
194//!
195//! When a `Vec` can not allocate, these methods also return a
196//! [`StorageFull`](FullError::StorageFull) error instead of panicking.
197//!
198//! ```
199//! use gen_map::{Config, GenMap, InsertError, Split};
200//!
201//! struct Tiny;
202//!
203//! impl Config for Tiny {
204//! type Idx = u8;
205//! type Gen = u8;
206//! type Layout = Split;
207//! type Storage<S> = Vec<S>;
208//! }
209//!
210//! let mut map = GenMap::<u32, Tiny>::new_with_config();
211//! for i in 0..256 {
212//! map.insert(i);
213//! }
214//! match map.try_insert(256) {
215//! Err(InsertError::IndexExhausted(value)) => assert_eq!(value, 256),
216//! _ => unreachable!(),
217//! }
218//! ```
219//!
220//! # Values that know their own key
221//!
222//! [`insert_with_key`](GenMap::insert_with_key) gives a closure the new
223//! value's key before the value is stored, which helps with values that
224//! refer to themselves, such as the nodes of a graph.
225//!
226//! ```
227//! use gen_map::{GenMap, Key};
228//!
229//! struct Node {
230//! me: Key,
231//! edges: Vec<Key>,
232//! }
233//!
234//! let mut graph = GenMap::new();
235//! let a = graph.insert_with_key(|me| Node { me, edges: Vec::new() });
236//! let b = graph.insert_with_key(|me| Node { me, edges: vec![a] });
237//! assert_eq!(graph[b].me, b);
238//! assert_eq!(graph[b].edges, [a]);
239//! ```
240//!
241//! # Taking a value out for a while
242//!
243//! [`detach`](GenMap::detach) moves a value out of the map but keeps its slot
244//! reserved for its key, and [`reattach`](GenMap::reattach) puts a value back
245//! under that same key. In between, the key is invalid and no insert can
246//! take the slot. This lets code take a value out, change it while borrowing
247//! the rest of the map, and put it back under the same key.
248//!
249//! ```
250//! use gen_map::GenMap;
251//!
252//! let mut map = GenMap::new();
253//! let a = map.insert(1);
254//! let b = map.insert(2);
255//!
256//! let mut value = map.detach(a).unwrap();
257//! value += map[b];
258//! map.reattach(a, value);
259//! assert_eq!(map[a], 3);
260//! ```
261//!
262//! # Several values at once
263//!
264//! [`get_disjoint_mut`](GenMap::get_disjoint_mut) hands out mutable
265//! references to several values at once, after checking that every key is
266//! valid and that no two keys point at the same slot.
267//! [`get_disjoint_mut_at`](GenMap::get_disjoint_mut_at) does the same with
268//! slot indices, and hands each key back with its value.
269//!
270//! ```
271//! use gen_map::GenMap;
272//!
273//! let mut map = GenMap::new();
274//! let a = map.insert(1);
275//! let b = map.insert(2);
276//!
277//! let [x, y] = map.get_disjoint_mut([a, b]).unwrap();
278//! core::mem::swap(x, y);
279//! assert_eq!((map[a], map[b]), (2, 1));
280//! ```
281//!
282//! # Looking a slot up by its index
283//!
284//! [`key_at`](GenMap::key_at) and [`get_at`](GenMap::get_at) find the value
285//! in the slot at an index along with its current key, for code that only
286//! kept the index. [`generation_at`](GenMap::generation_at) returns a slot's
287//! generation whether it holds a value or not.
288//!
289//! # Iterating and removing in bulk
290//!
291//! Every iterator visits the values in slot order, which is also the order
292//! of their keys. [`iter`](GenMap::iter), [`iter_mut`](GenMap::iter_mut),
293//! [`keys`](GenMap::keys), [`values`](GenMap::values),
294//! [`values_mut`](GenMap::values_mut) and the owning `into_iter` all know
295//! their exact length and can run from both ends.
296//!
297//! [`retain`](GenMap::retain), [`drain`](GenMap::drain) and
298//! [`clear`](GenMap::clear) remove values but keep every slot and its
299//! generation, so old keys stay invalid. [`reset`](GenMap::reset) removes
300//! the slots too while keeping the allocation. The generations start over
301//! after a reset, so a key from before the reset can match a value inserted
302//! after it.
303//!
304//! # Unchecked access
305//!
306//! Every lookup has an `_unchecked` form, such as
307//! [`get_unchecked`](GenMap::get_unchecked), that skips the checks the
308//! normal form makes, for code that already knows its key or index is valid.
309//! Calling one with an invalid key or index is undefined behavior.
310//!
311//! [`Key::from_raw_parts`] builds a key from an index and a generation. It
312//! is unsafe because the generation must be odd and both parts must fit the
313//! layout, and looking up a key that breaks either rule is undefined
314//! behavior.
315//!
316//! # Cargo features
317//!
318//! - `alloc` is on by default. It adds the `Vec` storage, [`DefaultConfig`]
319//! and [`GenMap::new`], and makes [`DefaultConfig`] the config that
320//! [`GenMap`] and [`Key`] use when none is named. Without it the crate
321//! needs no allocator, and every map needs a config whose storage does not
322//! allocate, such as an `ArrayVec`.
323//! - `arrayvec` lets a config use `arrayvec::ArrayVec` as its storage.
324//! - `smallvec` lets a config use `smallvec::SmallVec` as its storage. It
325//! uses the 2.0 beta of `smallvec`, which needs an allocator and Rust 1.86.
326//! Until smallvec 2.0 is released, a newer smallvec beta or a new release
327//! of gen_map may break this feature, so it is not covered by semver.
328//!
329//! To use the map without any allocator, turn `alloc` off and `arrayvec` on.
330//!
331//! ```toml
332//! [dependencies]
333//! gen_map = { version = "0.2", default-features = false, features = ["arrayvec"] }
334//! ```
335//!
336//! # Minimum supported Rust version
337//!
338//! The crate builds on Rust 1.79 and later. The `smallvec` feature needs
339//! Rust 1.86, because the 2.0 beta of `smallvec` does.
340
341#![no_std]
342#![warn(missing_docs)]
343
344#[cfg(feature = "alloc")]
345extern crate alloc;
346
347#[cfg(test)]
348extern crate std;
349
350mod config;
351mod error;
352mod key;
353mod key_layout;
354mod key_piece;
355mod map;
356mod storage;
357
358pub use config::Config;
359#[cfg(feature = "alloc")]
360pub use config::DefaultConfig;
361pub use error::{
362 FullError, GetDisjointMutAtError, GetDisjointMutError, InsertError, InsertWithError,
363};
364pub use key::Key;
365pub use key_layout::{KeyLayout, Packed, PackedRepr, Split, SplitRepr};
366pub use key_piece::KeyPiece;
367pub use map::{
368 Drain, GenMap, IntoIter, Iter, IterMut, Keys, Slot, StorageError, VacantEntry, Values,
369 ValuesMut,
370};
371pub use storage::{ReserveStorage, SlotStorage};
372
373// The tests use `Vec` storage and the default config, so they need `alloc`.
374#[cfg(all(test, feature = "alloc"))]
375mod tests;