1 #![deny(warnings, missing_docs, missing_debug_implementations)]
2 #![doc(html_root_url = "https://docs.rs/slotmap/0.4.0")]
3 #![crate_name = "slotmap"]
4 #![cfg_attr(feature = "unstable", feature(untagged_unions, try_reserve))]
5 
6 //! # slotmap
7 //!
8 //! This library provides a container with persistent unique keys to access
9 //! stored values, [`SlotMap`]. Upon insertion a key is returned that can be
10 //! used to later access or remove the values. Insertion, removal and access all
11 //! take O(1) time with low overhead. Great for storing collections of objects
12 //! that need stable, safe references but have no clear ownership otherwise,
13 //! such as game entities or graph nodes.
14 //!
15 //! The difference between a [`BTreeMap`] or [`HashMap`] and a slot map is
16 //! that the slot map generates and returns the key when inserting a value. A
17 //! key is always unique and will only refer to the value that was inserted.
18 //! A slot map's main purpose is to simply own things in a safe and efficient
19 //! manner.
20 //!
21 //! You can also create (multiple) secondary maps that can map the keys returned
22 //! by [`SlotMap`] to other values, to associate arbitrary data with objects
23 //! stored in slot maps, without hashing required - it's direct indexing under
24 //! the hood.
25 //!
26 //! # Examples
27 //!
28 //! ```
29 //! # use slotmap::*;
30 //! let mut sm = SlotMap::new();
31 //! let foo = sm.insert("foo");  // Key generated on insert.
32 //! let bar = sm.insert("bar");
33 //! assert_eq!(sm[foo], "foo");
34 //! assert_eq!(sm[bar], "bar");
35 //!
36 //! sm.remove(bar);
37 //! let reuse = sm.insert("reuse");  // Space from bar reused.
38 //! assert_eq!(sm.contains_key(bar), false);  // After deletion a key stays invalid.
39 //!
40 //! let mut sec = SecondaryMap::new();
41 //! sec.insert(foo, "noun");  // We provide the key for secondary maps.
42 //! sec.insert(reuse, "verb");
43 //!
44 //! for (key, val) in sm {
45 //!     println!("{} is a {}", val, sec[key]);
46 //! }
47 //! ```
48 //!
49 //! # Serialization through [`serde`]
50 //!
51 //! Both keys and the slot maps have full (de)seralization support through
52 //! the [`serde`] library. A key remains valid for a slot map even after one or
53 //! both have been serialized and deserialized! This makes storing or
54 //! transferring complicated referential structures and graphs a breeze. Care has
55 //! been taken such that deserializing keys and slot maps from untrusted sources
56 //! is safe. If you wish to use these features you must enable the `serde`
57 //! feature flag for `slotmap` in your `Cargo.toml`.
58 //!
59 //! ```text
60 //! slotmap = { version = "...", features = ["serde"] }
61 //! ```
62 //!
63 //! # Why not [`slab`]?
64 //!
65 //! Unlike [`slab`], the keys returned by [`SlotMap`] are versioned. This means
66 //! that once a key is removed, it stays removed, even if the physical storage
67 //! inside the slotmap is reused for new elements. The key is a
68 //! permanently unique<sup>*</sup> reference to the inserted value. Despite
69 //! supporting versioning, a [`SlotMap`] is not slower than [`slab`], by
70 //! internally using carefully checked unsafe code. A [`HopSlotMap`]
71 //! also provides faster iteration than [`slab`] does, and [`DenseSlotMap`] even
72 //! faster still. Additionally, at the time of writing [`slab`] does not support
73 //! serialization.
74 //!
75 //! # Performance characteristics and implementation details
76 //!
77 //! Insertion, access and deletion is all O(1) with low overhead by storing the
78 //! elements inside a [`Vec`]. Unlike references or indices into a vector,
79 //! unless you remove a key it is never invalidated. Behind the scenes each
80 //! slot in the vector is a `(value, version)` tuple. After insertion the
81 //! returned key also contains a version. Only when the stored version and
82 //! version in a key match is a key valid. This allows us to reuse space in the
83 //! vector after deletion without letting removed keys point to spurious new
84 //! elements. <sup>*</sup>After 2<sup>31</sup> deletions and insertions to the
85 //! same underlying slot the version wraps around and such a spurious reference
86 //! could potentially occur. It is incredibly unlikely however, and in all
87 //! circumstances is the behavior safe. A slot map can hold up to
88 //! 2<sup>32</sup> - 2 elements at a time.
89 //!
90 //! The memory usage for each slot in [`SlotMap`] is `4 + max(sizeof(T), 4)`
91 //! rounded up to the alignment of `T`. Similarly it is `4 + max(sizeof(T), 12)`
92 //! for [`HopSlotMap`]. [`DenseSlotMap`] has an overhead of 8 bytes per element
93 //! and 8 bytes per slot.
94 //!
95 //! # Choosing `SlotMap`, `HopSlotMap` or `DenseSlotMap`
96 //!
97 //! A [`SlotMap`] can never shrink the size of its underlying storage, because
98 //! for each storage slot it must remember what the latest stored version was,
99 //! even if the slot is empty now. This means that iteration can be slow as it
100 //! must iterate over potentially a lot of empty slots.
101 //!
102 //! [`HopSlotMap`] solves this by maintaining more information on
103 //! insertion/removal, allowing it to iterate only over filled slots by 'hopping
104 //! over' contiguous blocks of vacant slots. This can give it significantly
105 //! better iteration speed.  If you expect to iterate over all elements in a
106 //! [`SlotMap`] a lot, choose [`HopSlotMap`]. The downside is that insertion and
107 //! removal is roughly twice as slow. Random access is the same speed for both.
108 //!
109 //! [`DenseSlotMap`] goes even further and stores all elements on a contiguous
110 //! block of memory. It uses two indirects per random access; the slots contain
111 //! indices used to access the contiguous memory. This means random access is
112 //! slower than both [`SlotMap`] and [`HopSlotMap`], but iteration is
113 //! significantly faster. Finally, there is no trait requirement on the value
114 //! type of a [`DenseSlotMap`], see [`Slottable`] for more details.
115 //!
116 //! # Choosing `SecondaryMap` or `SparseSecondaryMap`
117 //!
118 //! You want to associate extra data with objects stored in a slot map, so you
119 //! use (multiple) secondary maps to map keys to that data.
120 //!
121 //! A [`SecondaryMap`] is simply a [`Vec`] of slots like slot map is, and
122 //! essentially provides all the same guarantees as [`SlotMap`] does for its
123 //! operations (with the exception that you provide the keys as produced by the
124 //! primary slot map). This does mean that even if you associate data to only
125 //! a single element from the primary slot map, you could need and have to
126 //! initialize as much memory as the original.
127 //!
128 //! A [`SparseSecondaryMap`] is like a [`HashMap`] from keys to objects, however
129 //! it automatically removes outdated keys for slots that had their space
130 //! reused. You should use this variant if you expect to store some associated
131 //! data for only a small portion of the primary slot map.
132 //!
133 //! # Custom key types
134 //!
135 //! If you have multiple slot maps it's an error to use the key of one slot map
136 //! on another slot map. The result is safe, but unspecified, and can not be
137 //! detected at runtime, so it can lead to a hard to find bug.
138 //!
139 //! To prevent this, slot maps allow you to specify what the type is of the key
140 //! they return, as long as that type implements the [`Key`] trait. To aid with
141 //! this, the [`new_key_type!`] macro is provided that builds such a type for
142 //! you. The resulting type is exactly like [`DefaultKey`]. So instead of simply
143 //! using `SlotMap<DefaultKey, Player>` you would use:
144 //!
145 //! ```
146 //! # use slotmap::*;
147 //! # #[derive(Copy, Clone)]
148 //! # struct Player;
149 //! new_key_type! { struct PlayerKey; }
150 //! let sm: SlotMap<PlayerKey, Player> = SlotMap::with_key();
151 //! ```
152 //!
153 //! [`Vec`]: https://doc.rust-lang.org/std/vec/struct.Vec.html
154 //! [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
155 //! [`HashMap`]: https://doc.rust-lang.org/std/collections/struct.HashMap.html
156 //! [`SlotMap`]: struct.SlotMap.html
157 //! [`HopSlotMap`]: hop/struct.HopSlotMap.html
158 //! [`DenseSlotMap`]: dense/struct.DenseSlotMap.html
159 //! [`SecondaryMap`]: secondary/struct.SecondaryMap.html
160 //! [`SparseSecondaryMap`]: sparse_secondary/struct.SparseSecondaryMap.html
161 //! [`Slottable`]: trait.Slottable.html
162 //! [`Key`]: trait.Key.html
163 //! [`new_key_type!`]: macro.new_key_type.html
164 //! [`serde`]: https://github.com/serde-rs/serde
165 //! [`slab`]: https://github.com/carllerche/slab
166 //! [`DefaultKey`]: struct.DefaultKey.html
167 
168 #[cfg(feature = "serde")]
169 extern crate serde;
170 
171 // So our macros can refer to these.
172 #[cfg(feature = "serde")]
173 #[doc(hidden)]
174 pub mod __impl {
175     pub use serde::{Deserialize, Deserializer, Serialize, Serializer};
176 }
177 
178 #[cfg(test)]
179 #[macro_use]
180 extern crate quickcheck;
181 
182 #[cfg(test)]
183 extern crate serde_json;
184 
185 pub(crate) mod normal;
186 pub use crate::normal::*;
187 
188 pub mod dense;
189 pub use crate::dense::DenseSlotMap;
190 
191 pub mod hop;
192 pub use crate::hop::HopSlotMap;
193 
194 pub mod secondary;
195 pub use crate::secondary::SecondaryMap;
196 
197 pub mod sparse_secondary;
198 pub use crate::sparse_secondary::SparseSecondaryMap;
199 
200 use std::fmt::{self, Debug, Formatter};
201 use std::num::NonZeroU32;
202 
203 /// A trait for items that can go in a [`SlotMap`] or [`HopSlotMap`]. Due to
204 /// current stable Rust restrictions a type must be [`Copy`] to be placed in one
205 /// of those slot maps. This restriction does not apply to [`DenseSlotMap`],
206 /// [`SecondaryMap`] or [`SparseSecondaryMap`]. It also does not apply if you
207 /// use nightly Rust and enable the `unstable` feature for `slotmap` by editing
208 /// your `Cargo.toml`:
209 ///
210 /// ```text
211 /// slotmap = { version = "...", features = ["unstable"] }
212 /// ```
213 ///
214 /// This trait should already be automatically implemented for any type that is
215 /// slottable.
216 ///
217 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
218 /// [`SecondaryMap`]: secondary/struct.SecondaryMap.html
219 /// [`SparseSecondaryMap`]: sparse_secondary/struct.SparseSecondaryMap.html
220 /// [`SlotMap`]: struct.SlotMap.html
221 /// [`HopSlotMap`]: hop/struct.HopSlotMap.html
222 /// [`DenseSlotMap`]: dense/struct.DenseSlotMap.html
223 #[cfg(not(feature = "unstable"))]
224 pub trait Slottable: Copy {}
225 
226 /// A trait for items that can go in a [`SlotMap`] or [`HopSlotMap`]. Due to
227 /// current stable Rust restrictions a type must be [`Copy`] to be placed in one
228 /// of those slot maps. This restriction does not apply to [`DenseSlotMap`],
229 /// [`SecondaryMap`] or [`SparseSecondaryMap`]. It also does not apply if you
230 /// use nightly Rust and enable the `unstable` feature for `slotmap` by editing
231 /// your `Cargo.toml`:
232 ///
233 /// ```text
234 /// slotmap = { version = "...", features = ["unstable"] }
235 /// ```
236 ///
237 /// This trait should already be automatically implemented for any type that is
238 /// slottable.
239 ///
240 /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
241 /// [`SecondaryMap`]: secondary/struct.SecondaryMap.html
242 /// [`SparseSecondaryMap`]: sparse_secondary/struct.SparseSecondaryMap.html
243 /// [`SlotMap`]: struct.SlotMap.html
244 /// [`HopSlotMap`]: hop/struct.HopSlotMap.html
245 /// [`DenseSlotMap`]: dense/struct.DenseSlotMap.html
246 #[cfg(feature = "unstable")]
247 pub trait Slottable {}
248 
249 #[cfg(not(feature = "unstable"))]
250 impl<T: Copy> Slottable for T {}
251 
252 #[cfg(feature = "unstable")]
253 impl<T> Slottable for T {}
254 
255 /// The actual data stored in a [`Key`].
256 ///
257 /// This implements `Ord` so keys can be stored in e.g. [`BTreeMap`], but the
258 /// order of keys is unspecified.
259 ///
260 /// [`Key`]: trait.Key.html
261 /// [`BTreeMap`]: https://doc.rust-lang.org/std/collections/struct.BTreeMap.html
262 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
263 pub struct KeyData {
264     idx: u32,
265     version: NonZeroU32,
266 }
267 
268 impl KeyData {
new(idx: u32, version: u32) -> Self269     fn new(idx: u32, version: u32) -> Self {
270         Self {
271             idx,
272             version: NonZeroU32::new(version).expect("KeyData constructed with zero version"),
273         }
274     }
275 
null() -> Self276     fn null() -> Self {
277         Self::new(std::u32::MAX, 1)
278     }
279 
is_null(self) -> bool280     fn is_null(self) -> bool {
281         self.idx == std::u32::MAX
282     }
283 
284     /// Returns the key data as a 64-bit integer. No guarantees about its value
285     /// are made other than that passing it to `from_ffi` will return a key
286     /// equal to the original.
287     ///
288     /// With this you can easily pass slot map keys as opaque handles to foreign
289     /// code. After you get them back you can confidently use them in your slot
290     /// map without worrying about unsafe behavior as you would with passing and
291     /// receiving back references or pointers.
292     ///
293     /// This is not a substitute for proper serialization, use [`serde`] for
294     /// that. If you are not doing FFI, you almost surely do not need this
295     /// function.
296     ///
297     /// [`serde`]: index.html#serialization-through-serde
as_ffi(self) -> u64298     pub fn as_ffi(self) -> u64 {
299         (u64::from(self.version.get()) << 32) | u64::from(self.idx)
300     }
301 
302     /// Iff `value` is a value received from `k.as_ffi()`, returns a key equal
303     /// to `k`. Otherwise the behavior is safe but unspecified.
from_ffi(value: u64) -> Self304     pub fn from_ffi(value: u64) -> Self {
305         let idx = value & 0xffff_ffff;
306         let version = (value >> 32) | 1; // Ensure version is odd.
307         Self::new(idx as u32, version as u32)
308     }
309 }
310 
311 impl Debug for KeyData {
fmt(&self, f: &mut Formatter) -> fmt::Result312     fn fmt(&self, f: &mut Formatter) -> fmt::Result {
313         write!(f, "{}v{}", self.idx, self.version.get())
314     }
315 }
316 
317 impl Default for KeyData {
default() -> Self318     fn default() -> Self {
319         Self::null()
320     }
321 }
322 
323 /// Key used to access stored values in a slot map.
324 ///
325 /// Do not use a key from one slot map in another. The behavior is safe but
326 /// non-sensical (and might panic in case of out-of-bounds).
327 ///
328 /// To prevent this, it is suggested to have a unique key type for each slot
329 /// map. The easiest way to do this is through [`new_key_type!`], which
330 /// makes a new type identical to [`DefaultKey`], just with a different name.
331 ///
332 /// [`new_key_type!`]: macro.new_key_type.html
333 /// [`DefaultKey`]: struct.DefaultKey.html
334 pub trait Key: From<KeyData> + Into<KeyData> + Clone {
335     /// Creates a new key that is always invalid and distinct from any non-null
336     /// key. A null key can only be created through this method (or default
337     /// initialization of keys made with [`new_key_type!`], which calls this
338     /// method).
339     ///
340     /// A null key is always invalid, but an invalid key (that is, a key that
341     /// has been removed from the slot map) does not become a null key. A null
342     /// is safe to use with any safe method of any slot map instance.
343     ///
344     /// # Examples
345     ///
346     /// ```
347     /// # use slotmap::*;
348     /// let mut sm = SlotMap::new();
349     /// let k = sm.insert(42);
350     /// let nk = DefaultKey::null();
351     /// assert!(nk.is_null());
352     /// assert!(k != nk);
353     /// assert_eq!(sm.get(nk), None);
354     /// ```
355     ///
356     /// [`new_key_type!`]: macro.new_key_type.html
null() -> Self357     fn null() -> Self {
358         KeyData::null().into()
359     }
360 
361     /// Checks if a key is null. There is only a single null key, that is
362     /// `a.is_null() && b.is_null()` implies `a == b`.
363     ///
364     /// # Examples
365     ///
366     /// ```
367     /// # use slotmap::*;
368     /// new_key_type! { struct MyKey; }
369     /// let a = MyKey::null();
370     /// let b = MyKey::default();
371     /// assert_eq!(a, b);
372     /// assert!(a.is_null());
373     /// ```
is_null(self) -> bool374     fn is_null(self) -> bool {
375         self.into().is_null()
376     }
377 }
378 
379 /// A helper macro to conveniently create new key types. If you use a new key
380 /// type for each slot map you create you can entirely prevent using the wrong
381 /// key on the wrong slot map.
382 ///
383 /// The type constructed by this macro is identical to [`DefaultKey`], just with
384 /// a different name.
385 ///
386 /// [`DefaultKey`]: struct.DefaultKey.html
387 ///
388 /// # Examples
389 ///
390 /// ```
391 /// # extern crate slotmap;
392 /// # use slotmap::*;
393 /// new_key_type! {
394 ///     struct EntityKey;
395 ///
396 ///     /// Key for the Player slot map.
397 ///     pub struct PlayerKey;
398 /// }
399 ///
400 /// fn main() {
401 ///     let mut players = SlotMap::with_key();
402 ///     let mut entities: SlotMap<EntityKey, (f64, f64)> = SlotMap::with_key();
403 ///     let bob: PlayerKey = players.insert("bobby");
404 ///     // Now this is a type error because entities.get expects an EntityKey:
405 ///     // entities.get(bob);
406 /// }
407 /// ```
408 #[macro_export(local_inner_macros)]
409 macro_rules! new_key_type {
410     ( $(#[$outer:meta])* $vis:vis struct $name:ident; $($rest:tt)* ) => {
411         $(#[$outer])*
412         #[derive(Copy, Clone, Default,
413                  Eq, PartialEq, Ord, PartialOrd,
414                  Hash, Debug)]
415         #[repr(transparent)]
416         $vis struct $name($crate::KeyData);
417 
418         impl From<$crate::KeyData> for $name {
419             fn from(k: $crate::KeyData) -> Self {
420                 $name(k)
421             }
422         }
423 
424         impl From<$name> for $crate::KeyData {
425             fn from(k: $name) -> Self {
426                 k.0
427             }
428         }
429 
430         impl $crate::Key for $name { }
431 
432         $crate::__serialize_key!($name);
433 
434         $crate::new_key_type!($($rest)*);
435     };
436 
437     () => {}
438 }
439 
440 #[cfg(feature = "serde")]
441 #[doc(hidden)]
442 #[macro_export]
443 macro_rules! __serialize_key {
444     ( $name:ty ) => {
445         impl $crate::__impl::Serialize for $name {
446             fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
447             where
448                 S: $crate::__impl::Serializer,
449             {
450                 $crate::KeyData::from(*self).serialize(serializer)
451             }
452         }
453 
454         impl<'de> $crate::__impl::Deserialize<'de> for $name {
455             fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
456             where
457                 D: $crate::__impl::Deserializer<'de>,
458             {
459                 let key_data: $crate::KeyData =
460                     $crate::__impl::Deserialize::deserialize(deserializer)?;
461                 Ok(key_data.into())
462             }
463         }
464     };
465 }
466 
467 #[cfg(not(feature = "serde"))]
468 #[doc(hidden)]
469 #[macro_export]
470 macro_rules! __serialize_key {
471     ( $name:ty ) => {};
472 }
473 
474 new_key_type! {
475     /// The default slot map key type.
476     pub struct DefaultKey;
477 }
478 
479 // Returns if a is an older version than b, taking into account wrapping of
480 // versions.
is_older_version(a: u32, b: u32) -> bool481 fn is_older_version(a: u32, b: u32) -> bool {
482     let diff = a.wrapping_sub(b);
483     diff >= (1 << 31)
484 }
485 
486 // Serialization with serde.
487 #[cfg(feature = "serde")]
488 mod serialize {
489     use super::*;
490     use serde::{Deserialize, Deserializer, Serialize, Serializer};
491 
492     #[derive(Serialize, Deserialize)]
493     pub struct SerKey {
494         idx: u32,
495         version: u32,
496     }
497 
498     impl Serialize for KeyData {
serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer,499         fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
500         where
501             S: Serializer,
502         {
503             let ser_key = SerKey {
504                 idx: self.idx,
505                 version: self.version.get(),
506             };
507             ser_key.serialize(serializer)
508         }
509     }
510 
511     impl<'de> Deserialize<'de> for KeyData {
deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de>,512         fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
513         where
514             D: Deserializer<'de>,
515         {
516             let mut ser_key: SerKey = Deserialize::deserialize(deserializer)?;
517 
518             // Ensure a.is_null() && b.is_null() implies a == b.
519             if ser_key.idx == std::u32::MAX {
520                 ser_key.version = 1;
521             }
522 
523             ser_key.version |= 1; // Ensure version is odd.
524             Ok(Self::new(ser_key.idx, ser_key.version))
525         }
526     }
527 }
528 
529 #[cfg(test)]
530 mod tests {
531     use super::*;
532 
533     #[test]
check_is_older_version()534     fn check_is_older_version() {
535         let is_older = |a, b| is_older_version(a, b);
536         assert!(!is_older(42, 42));
537         assert!(is_older(0, 1));
538         assert!(is_older(0, 1 << 31));
539         assert!(!is_older(0, (1 << 31) + 1));
540         assert!(is_older((-1i32) as u32, 0));
541     }
542 
543     #[cfg(feature = "serde")]
544     #[test]
key_serde()545     fn key_serde() {
546         // Check round-trip through serde.
547         let mut sm = SlotMap::new();
548         let k = sm.insert(42);
549         let ser = serde_json::to_string(&k).unwrap();
550         let de: DefaultKey = serde_json::from_str(&ser).unwrap();
551         assert_eq!(k, de);
552 
553         // Even if a malicious entity sends up even (unoccupied) versions in the
554         // key, we make the version point to the occupied version.
555         let malicious: KeyData = serde_json::from_str(&r#"{"idx":0,"version":4}"#).unwrap();
556         assert_eq!(malicious.version.get(), 5);
557     }
558 }
559