gen_map/lib.rs
1//! [`GenMap`] is a configurable generational map that stores each value in a slot
2//! and hands out a [`Key`] that points at that slot.
3//!
4//! When a value is removed, the map frees its slot and may reuse
5//! that slot for a value inserted later. The key of the removed value stops
6//! matching the slot when the value is removed, so it does not match the value
7//! the map later puts in that slot either. That makes keys safe to hold on to
8//! where plain indices or references are not, such as in graphs, entity
9//! systems and anything else that refers to values by handle.
10//! [How it works](#how-it-works) lists the few cases where a key can match a
11//! value other than the one it was handed out for.
12//!
13//! Inserting, removing and looking up a value are all O(1). The crate never
14//! uses `std`, and [Cargo features](#cargo-features) lists the features that
15//! need an allocator.
16//!
17//! # Examples
18//!
19//! ```
20//! use gen_map::GenMap;
21//!
22//! let mut map = GenMap::new();
23//! let a = map.insert("a");
24//! let b = map.insert("b");
25//! assert_eq!(map[a], "a");
26//!
27//! assert_eq!(map.remove(a), Some("a"));
28//! assert!(map.get(a).is_none());
29//!
30//! // The map puts "c" in the slot that "a" was removed from. The key `a`
31//! // stopped matching that slot when "a" was removed, so it does not match
32//! // "c".
33//! let c = map.insert("c");
34//! assert_eq!(c.idx(), a.idx());
35//! assert!(map.get(a).is_none());
36//! assert_eq!(map[c], "c");
37//!
38//! // The iterator yields each value with its key, in slot order. "c" is in the
39//! // first slot, so it comes before "b".
40//! let pairs: Vec<_> = map.iter().collect();
41//! assert_eq!(pairs, [(c, &"c"), (b, &"b")]);
42//! ```
43//!
44//! A [`SecondaryMap`] stores values under the keys a [`GenMap`] hands out.
45//!
46//! ```
47//! use gen_map::{GenMap, SecondaryMap};
48//!
49//! let mut people = GenMap::new();
50//! let mut ages = SecondaryMap::new();
51//! let alice = people.insert("Alice");
52//! ages.insert(alice, 30).unwrap();
53//! assert_eq!(ages[alice], 30);
54//! ```
55//!
56//! A config decides the size of a map's keys and the collection the map keeps
57//! its slots in.
58//!
59//! ```
60//! use gen_map::{GenMap, GenMapConfig, GenSlotItem, MapConfig, Split};
61//!
62//! /// Maps with this config hand out keys with a `u8` index and a `u8`
63//! /// generation, so each key is two bytes. A map with this config never gives
64//! /// a slot the index `u8::MAX`, so it holds at most 255 slots.
65//! struct Tiny;
66//!
67//! impl MapConfig for Tiny {
68//! type KeyConfig = Split<u8, u8>;
69//! }
70//!
71//! impl<S: GenSlotItem> GenMapConfig<S> for Tiny {
72//! type Storage = Vec<S>;
73//! }
74//!
75//! let mut map = GenMap::<u64, Tiny>::new_with_config();
76//! let key = map.insert(7);
77//! assert_eq!(core::mem::size_of_val(&key), 2);
78//! assert_eq!(map[key], 7);
79//! ```
80//!
81//! # How it works
82//!
83//! A key holds the index of its value's slot and the generation that slot had
84//! when the key was handed out. A key only matches its slot while the slot's
85//! generation equals the key's. A new slot starts at generation zero, and the
86//! map adds one to a slot's generation when it inserts a value into the slot
87//! and again when [`remove`](GenMap::remove) takes the value out. So the
88//! generation is odd while the slot holds a value and even while it does not.
89//! Once a value is removed, no copy of its key matches the slot, and the key
90//! the map hands out for the next value in that slot has a newer generation.
91//!
92//! The map keeps a slot after its value is removed, and it reuses freed slots
93//! before it adds new ones. Only [`reset`](GenMap::reset) removes slots. The
94//! iterators, [`retain`](GenMap::retain), [`drain`](GenMap::drain) and
95//! [`clear`](GenMap::clear) go through every slot, including the ones that
96//! hold no value, so the time they take follows
97//! [`slots_len`](GenMap::slots_len) rather than [`len`](GenMap::len).
98//!
99//! The map adds one to a slot's generation twice for each value, so a `u32`
100//! generation lets a slot hold over two billion values one after another, and
101//! a 4-bit generation lets it hold eight. When the map removes a value whose
102//! key has the largest generation its key config can hold, the slot has no
103//! generations left. By default, the map then retires the slot and never uses
104//! it again. When [`WRAP_ON_OVERFLOW`](GenMapConfig::WRAP_ON_OVERFLOW) is
105//! `true`, the map instead starts the slot's generation over at zero and keeps
106//! using the slot. The map then counts the slot's generation up through the
107//! same values again, so a key from before the wrap can match a new value once
108//! the slot's generation is back at the key's.
109//!
110//! Two methods also let a key match a value other than the one it was handed
111//! out for. [`reset`](GenMap::reset) removes every slot and starts the
112//! generations over, so a key from before the reset can match a value inserted
113//! after it. [`reattach`](GenMap::reattach) puts any value under a key whose
114//! value [`detach`](GenMap::detach) took out, and the key then matches that
115//! value.
116//!
117//! # Configuring the map
118//!
119//! A map's config is a type that implements [`MapConfig`] and
120//! [`GenMapConfig`]. The map only uses the config as a type and never creates
121//! a value of it, so an empty struct is enough. A config decides three things.
122//!
123//! - [`KeyConfig`](MapConfig::KeyConfig) decides the integer types of a key's
124//! index and generation, and how the key stores the two. [`Split`] keeps
125//! them as two fields, and [`Packed`] puts them in the bits of one integer.
126//! With either key config, `Option<Key>` is the same size as `Key`.
127//! - [`WRAP_ON_OVERFLOW`](GenMapConfig::WRAP_ON_OVERFLOW) decides whether the
128//! map retires a slot with no generations left or starts its generation over
129//! at zero.
130//! - [`Storage`](GenMapConfig::Storage) is the collection the map keeps its
131//! slots in. It can be a `Vec`, an `ArrayVec`, a `SmallVec` or any other
132//! type that implements [`SlotStorage`].
133//!
134//! When its `C` parameter is left out, as in `GenMap<T>`, a map uses
135//! [`DefaultMapConfig`]. Maps with that config hand out keys with a `u32`
136//! index and a `u32` generation, keep their slots in a `Vec` and retire a slot
137//! that has no generations left. [`GenMap::new`] only exists for the default
138//! config, so use [`GenMap::new_with_config`] for any other.
139//!
140//! Maps whose configs have the same key config share a key type. A key does
141//! not record which map handed it out, so a map also accepts keys from another
142//! map with the same key config, and it may hold an unrelated value under such
143//! a key.
144//!
145//! # Secondary maps
146//!
147//! Use a [`SecondaryMap`] to add data to the values of a [`GenMap`] without
148//! changing their type. A `SecondaryMap` can only use a `GenMap`'s keys when
149//! both configs have the same [`KeyConfig`](MapConfig::KeyConfig), because
150//! only then do the two maps share a key type.
151//!
152//! When a value is removed from the `GenMap`, the value stored under its key
153//! stays in the `SecondaryMap`. If the `GenMap` later puts a new value in the
154//! removed value's slot, the new value's key has the same index as the old key
155//! and a newer generation. The
156//! [`ReplaceStrategy`](SecondaryMapConfig::ReplaceStrategy) of the
157//! `SecondaryMap`'s config decides whether a value inserted under that newer
158//! key replaces the old value.
159//!
160//! # Cargo features
161//!
162//! - `alloc` is on by default. It adds the `Vec` storage and
163//! [`DefaultMapConfig`]. Without it, every map needs a config of its own.
164//! - `arrayvec` lets a config use `arrayvec::ArrayVec` as its storage. An
165//! `ArrayVec` has a fixed capacity and never allocates.
166//! - `smallvec` lets a config use `smallvec::SmallVec` as its storage. A
167//! `SmallVec` keeps its first slots inline and allocates when it needs room
168//! for more. This feature uses the 2.0 beta of `smallvec`. Until `smallvec`
169//! 2.0 is released, a newer beta or a new release of `gen_map` may break
170//! this feature, so it is not covered by semver.
171//!
172//! The crate only needs an allocator when `alloc` or `smallvec` is on. To use
173//! the crate without any allocator, turn default features off and `arrayvec`
174//! on.
175//!
176//! ```toml
177//! [dependencies]
178//! gen_map = { version = "0.3", default-features = false, features = ["arrayvec"] }
179//! ```
180//!
181//! # Minimum supported Rust version
182//!
183//! The crate builds on Rust 1.79 and later. The `smallvec` feature needs
184//! Rust 1.86, because the 2.0 beta of `smallvec` does.
185
186#![no_std]
187#![cfg_attr(docsrs, feature(doc_cfg))]
188#![warn(
189 missing_docs,
190 unsafe_op_in_unsafe_fn,
191 clippy::undocumented_unsafe_blocks
192)]
193
194#[cfg(feature = "alloc")]
195extern crate alloc;
196
197#[cfg(test)]
198extern crate std;
199
200mod config;
201mod error;
202mod key;
203mod key_layout;
204mod key_piece;
205mod map;
206mod parity;
207mod replace_strategy;
208mod secondary_map;
209mod slot;
210mod storage;
211
212#[cfg(feature = "alloc")]
213#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
214pub use config::DefaultMapConfig;
215pub use config::{
216 DefaultKeyConfig, GenMapConfig, KeyConfig, MapConfig, MapConfigFor, SecondaryMapConfig,
217 SecondaryMapConfigFor,
218};
219pub use error::{
220 FullError, GetDisjointMutAtError, GetDisjointMutError, InsertError, InsertWithError,
221 SecondaryInsertError,
222};
223pub use key::Key;
224pub use key_layout::{Packed, Split};
225pub use key_piece::KeyPiece;
226pub use map::{
227 Drain, GenMap, IntoIter, Iter, IterMut, Keys, MapGen, MapIdx, MapKeyConfig, MapSlot,
228 StorageError, VacantEntry, Values, ValuesMut,
229};
230pub use parity::{Even, Odd};
231pub use replace_strategy::{ExistingWins, NewerWins, ReplaceStrategy};
232pub use secondary_map::{
233 SecondaryDrain, SecondaryIntoIter, SecondaryIter, SecondaryIterMut, SecondaryKeys,
234 SecondaryMap, SecondaryMapSlot, SecondaryStorageError, SecondaryValues, SecondaryValuesMut,
235};
236pub use slot::{GenSlotItem, Parity, SecondarySlot, SecondarySlotItem, Slot};
237pub use storage::{ReserveStorage, SlotStorage};
238
239// The tests use `Vec` storage and the default config, so they need `alloc`.
240#[cfg(all(test, feature = "alloc"))]
241mod tests;