Skip to main content

obj_pool/
lib.rs

1//! A simple object pool.
2//!
3//! `ObjPool<T>` is basically just a `Vec<Option<T>>`, which allows you to:
4//!
5//! * Insert an object (reuse an existing `None` element, or append to the end) and get an `ObjId`
6//!   in return.
7//! * Remove object with a specified `ObjId`.
8//! * Access object with a specified `ObjId`.
9//! * Convert `ObjId` to index and back for specified `ObjPool`.
10//!
11//! # Limitations:
12//!
13//! * `ObjId` is always 32-bit long.
14//!
15//! # Debug-only misuse detection
16//!
17//! In debug builds every pool mixes a random pool-specific offset into the `ObjId`s it issues.
18//! An `ObjId` used with a different pool than the one that created it then decodes to a vacant
19//! or out-of-bounds slot with overwhelming probability, so the lookup returns `None` (or panics
20//! when indexing) instead of silently returning an unrelated object. Release builds skip the
21//! masking entirely: an `ObjId` is just the slot index plus one.
22//!
23//! # Examples
24//!
25//! Some data structures built using `ObjPool<T>`:
26//!
27//! * [Doubly linked list](https://github.com/artemshein/obj-pool/blob/master/examples/linked_list.rs)
28//! * [Splay tree](https://github.com/artemshein/obj-pool/blob/master/examples/splay_tree.rs)
29use std::{
30    fmt,
31    hint::unreachable_unchecked,
32    iter, mem,
33    num::{NonZeroU32, ParseIntError},
34    ops::{Index, IndexMut},
35    ptr,
36    str::FromStr,
37    vec,
38};
39
40use std::ops::Deref;
41use std::slice;
42
43#[cfg(feature = "serde_support")]
44use serde::{Deserialize, Serialize};
45
46mod par;
47pub use par::*;
48
49/// A slot, which is either vacant or occupied.
50///
51/// Vacant slots in object pool are linked together into a singly linked list. This allows the object pool to
52/// efficiently find a vacant slot before inserting a new object, or reclaiming a slot after
53/// removing an object.
54#[derive(Clone)]
55enum Slot<T> {
56    /// Vacant slot, containing index to the next slot in the linked list.
57    Vacant(u32),
58
59    /// Occupied slot, containing a value.
60    Occupied(T),
61}
62
63/// An id of the object in an `ObjPool`.
64///
65/// In release builds it is basically just an index in the underlying vector (plus one). In debug
66/// builds every pool additionally mixes a random pool-specific offset into each `ObjId` it
67/// issues, so an `ObjId` created by one pool is (with overwhelming probability) rejected when
68/// used with another pool instead of silently aliasing an unrelated object.
69#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
70#[cfg_attr(feature = "serde_support", derive(Serialize, Deserialize))]
71pub struct ObjId(pub NonZeroU32);
72
73impl ObjId {
74    /// Creates an `ObjId` from a raw index, without any pool-specific masking.
75    ///
76    /// Note: in debug builds every pool mixes a random pool-specific offset into the ids it
77    /// issues, so to create an id valid for a particular pool use
78    /// [`ObjPool::index_to_obj_id`] instead.
79    pub fn from_index(index: u32) -> Self {
80        debug_assert!(index < u32::MAX, "index out of range");
81        // SAFETY: index + 1 is non-zero for any index < u32::MAX, which the
82        // debug assertion above guarantees. Using unchecked here makes the
83        // function side-effect-free in release builds so the compiler can
84        // eliminate ObjId construction when the result is unused (e.g. in
85        // iterator benchmarks that discard the key with `_`).
86        Self(unsafe { NonZeroU32::new_unchecked(index + 1) })
87    }
88
89    /// Converts the `ObjId` into a raw index, without any pool-specific unmasking.
90    ///
91    /// Note: in debug builds every pool mixes a random pool-specific offset into the ids it
92    /// issues, so to get the slot index of an id use [`ObjPool::obj_id_to_index`] instead.
93    pub const fn into_index(self) -> u32 {
94        self.0.get() - 1
95    }
96}
97
98impl std::fmt::Display for ObjId {
99    fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
100        self.0.fmt(f)
101    }
102}
103
104impl FromStr for ObjId {
105    type Err = ParseIntError;
106
107    fn from_str(s: &str) -> Result<Self, Self::Err> {
108        Ok(ObjId(s.parse::<NonZeroU32>()?))
109    }
110}
111
112impl Deref for ObjId {
113    type Target = NonZeroU32;
114
115    fn deref(&self) -> &Self::Target {
116        &self.0
117    }
118}
119
120impl From<NonZeroU32> for ObjId {
121    fn from(v: NonZeroU32) -> ObjId {
122        ObjId(v)
123    }
124}
125
126/// Debug-only random per-pool offset which is mixed into every `ObjId` a pool issues.
127///
128/// An `ObjId` is rotated by the offset within the `NonZeroU32` value domain `[1, u32::MAX]`,
129/// so an id of one pool decodes to an (almost certainly out-of-bounds or vacant) garbage index
130/// in any other pool instead of silently aliasing an unrelated object. In release builds this
131/// is a zero-sized no-op.
132#[derive(Clone, Copy)]
133pub(crate) struct PoolTag {
134    #[cfg(debug_assertions)]
135    offset: u32,
136}
137
138impl PoolTag {
139    /// A tag with no offset assigned yet; ids pass through unchanged.
140    pub(crate) const fn empty() -> Self {
141        PoolTag {
142            #[cfg(debug_assertions)]
143            offset: 0,
144        }
145    }
146
147    /// A tag with a random offset already assigned (in debug builds).
148    pub(crate) fn random() -> Self {
149        let mut tag = Self::empty();
150        tag.randomize();
151        tag
152    }
153
154    /// Assigns a random offset if none is assigned yet (in debug builds).
155    #[inline]
156    pub(crate) fn randomize(&mut self) {
157        #[cfg(debug_assertions)]
158        if self.offset == 0 {
159            self.offset = random_offset();
160        }
161    }
162
163    /// Mixes the pool offset into a raw `ObjId`.
164    #[inline]
165    pub(crate) fn mask_id(self, obj_id: ObjId) -> ObjId {
166        #[cfg(debug_assertions)]
167        return ObjId(rotate_id(obj_id.0, self.offset as u64));
168        #[cfg(not(debug_assertions))]
169        obj_id
170    }
171
172    /// Removes the pool offset from an external `ObjId`.
173    #[inline]
174    pub(crate) fn unmask_id(self, obj_id: ObjId) -> ObjId {
175        #[cfg(debug_assertions)]
176        return ObjId(rotate_id(obj_id.0, ID_DOMAIN - self.offset as u64));
177        #[cfg(not(debug_assertions))]
178        obj_id
179    }
180}
181
182/// Size of the `NonZeroU32` value domain `[1, u32::MAX]` an `ObjId` lives in.
183#[cfg(debug_assertions)]
184const ID_DOMAIN: u64 = u32::MAX as u64;
185
186/// Rotates `value` by `offset` positions within the `NonZeroU32` value domain. This is a
187/// bijection on `[1, u32::MAX]` for any fixed `offset <= ID_DOMAIN`, and rotating back is
188/// rotating by `ID_DOMAIN - offset`.
189#[cfg(debug_assertions)]
190fn rotate_id(value: NonZeroU32, offset: u64) -> NonZeroU32 {
191    let rotated = ((value.get() as u64 - 1) + offset) % ID_DOMAIN;
192    NonZeroU32::new(rotated as u32 + 1).expect("rotation preserves non-zero")
193}
194
195/// Returns a random per-pool offset in `[1, u32::MAX - 1]`, so that it is never zero (the
196/// "not assigned yet" sentinel) and never a multiple of `ID_DOMAIN` (an identity rotation).
197#[cfg(debug_assertions)]
198fn random_offset() -> u32 {
199    use std::collections::hash_map::RandomState;
200    use std::hash::{BuildHasher, Hasher};
201    let random = RandomState::new().build_hasher().finish() as u32;
202    1 + random % (u32::MAX - 1)
203}
204
205/// An object pool.
206///
207/// `ObjPool<T>` holds an array of slots for storing objects.
208/// Every slot is always in one of two states: occupied or vacant.
209///
210/// Essentially, this is equivalent to `Vec<Option<T>>`.
211///
212/// # Insert and remove
213///
214/// When inserting a new object into object pool, a vacant slot is found and then the object is placed
215/// into the slot. If there are no vacant slots, the array is reallocated with bigger capacity.
216/// The cost of insertion is amortized `O(1)`.
217///
218/// When removing an object, the slot containing it is marked as vacant and the object is returned.
219/// The cost of removal is `O(1)`.
220///
221/// ```
222/// use obj_pool::ObjPool;
223///
224/// let mut obj_pool = ObjPool::new();
225/// let a = obj_pool.insert(10);
226/// assert_eq!(obj_pool.obj_id_to_index(a), 0);
227/// let b = obj_pool.insert(20);
228/// assert_eq!(obj_pool.obj_id_to_index(b), 1);
229///
230/// assert_ne!(a, b); // ids are not the same
231///
232/// assert_eq!(obj_pool.remove(a), Some(10));
233/// assert_eq!(obj_pool.get(a), None); // there is no object with this `ObjId` anymore
234///
235/// assert_eq!(obj_pool.insert(30), a); // slot is reused, got the same `ObjId`
236/// ```
237///
238/// # Indexing
239///
240/// You can also access objects in an object pool by `ObjId`.
241/// However, accessing an object with invalid `ObjId` will result in panic.
242///
243/// ```
244/// use obj_pool::ObjPool;
245///
246/// let mut obj_pool = ObjPool::new();
247/// let a = obj_pool.insert(10);
248/// let b = obj_pool.insert(20);
249///
250/// assert_eq!(obj_pool[a], 10);
251/// assert_eq!(obj_pool[b], 20);
252///
253/// obj_pool[a] += obj_pool[b];
254/// assert_eq!(obj_pool[a], 30);
255/// ```
256///
257/// To access slots without fear of panicking, use `get` and `get_mut`, which return `Option`s.
258pub struct ObjPool<T> {
259    /// Slots in which objects are stored.
260    slots: Vec<Slot<T>>,
261
262    /// Number of occupied slots in the object pool.
263    len: u32,
264
265    /// Index of the first vacant slot in the linked list.
266    head: u32,
267
268    /// Debug-only random tag mixed into every `ObjId` of this pool.
269    tag: PoolTag,
270}
271
272impl<T> AsRef<ObjPool<T>> for ObjPool<T> {
273    fn as_ref(&self) -> &ObjPool<T> {
274        self
275    }
276}
277
278impl<T> AsMut<ObjPool<T>> for ObjPool<T> {
279    fn as_mut(&mut self) -> &mut ObjPool<T> {
280        self
281    }
282}
283
284impl<T> ObjPool<T> {
285    /// Constructs a new, empty object pool.
286    ///
287    /// The object pool will not allocate until objects are inserted into it.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// use obj_pool::ObjPool;
293    ///
294    /// let mut obj_pool: ObjPool<i32> = ObjPool::new();
295    /// ```
296    #[inline]
297    pub const fn new() -> Self {
298        ObjPool {
299            slots: Vec::new(),
300            len: 0,
301            head: u32::MAX,
302            // `new` is const, so the random tag is assigned lazily on the first insertion.
303            tag: PoolTag::empty(),
304        }
305    }
306
307    /// Get an index in the `ObjPool` for the given `ObjId`.
308    ///
309    /// In debug builds this removes the pool-specific random offset from the id, so the result
310    /// is only meaningful for ids issued by this pool.
311    #[inline]
312    pub fn obj_id_to_index(&self, obj_id: ObjId) -> u32 {
313        self.tag.unmask_id(obj_id).into_index()
314    }
315
316    /// Make an `ObjId` from an index in this `ObjPool`.
317    ///
318    /// In debug builds the id is masked with the pool-specific random offset. For a pool created
319    /// with `ObjPool::new` the offset is assigned on the first insertion, so ids created before
320    /// that are not valid afterwards.
321    #[inline]
322    pub fn index_to_obj_id(&self, index: u32) -> ObjId {
323        self.tag.mask_id(ObjId::from_index(index))
324    }
325
326    /// Constructs a new, empty object pool with the specified capacity (number of slots).
327    ///
328    /// The object pool will be able to hold exactly `capacity` objects without reallocating.
329    /// If `capacity` is 0, the object pool will not allocate.
330    ///
331    /// # Examples
332    ///
333    /// ```
334    /// use obj_pool::ObjPool;
335    ///
336    /// let mut obj_pool = ObjPool::with_capacity(10);
337    ///
338    /// assert_eq!(obj_pool.len(), 0);
339    /// assert_eq!(obj_pool.capacity(), 10);
340    ///
341    /// // These inserts are done without reallocating...
342    /// for i in 0..10 {
343    ///     obj_pool.insert(i);
344    /// }
345    /// assert_eq!(obj_pool.capacity(), 10);
346    ///
347    /// // ... but this one will reallocate.
348    /// obj_pool.insert(11);
349    /// assert!(obj_pool.capacity() > 10);
350    /// ```
351    #[inline]
352    pub fn with_capacity(cap: usize) -> Self {
353        ObjPool {
354            slots: Vec::with_capacity(cap),
355            len: 0,
356            head: u32::MAX,
357            tag: PoolTag::random(),
358        }
359    }
360
361    /// Returns the number of slots in the object pool.
362    ///
363    /// # Examples
364    ///
365    /// ```
366    /// use obj_pool::ObjPool;
367    ///
368    /// let obj_pool: ObjPool<i32> = ObjPool::with_capacity(10);
369    /// assert_eq!(obj_pool.capacity(), 10);
370    /// ```
371    #[inline]
372    pub fn capacity(&self) -> usize {
373        self.slots.capacity()
374    }
375
376    /// Returns the number of occupied slots in the object pool.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// use obj_pool::ObjPool;
382    ///
383    /// let mut obj_pool = ObjPool::new();
384    /// assert_eq!(obj_pool.len(), 0);
385    ///
386    /// for i in 0..10 {
387    ///     obj_pool.insert(());
388    ///     assert_eq!(obj_pool.len(), i + 1);
389    /// }
390    /// ```
391    #[inline]
392    pub fn len(&self) -> u32 {
393        self.len
394    }
395
396    /// Returns `true` if all slots are vacant.
397    ///
398    /// # Examples
399    ///
400    /// ```
401    /// use obj_pool::ObjPool;
402    ///
403    /// let mut obj_pool = ObjPool::new();
404    /// assert!(obj_pool.is_empty());
405    ///
406    /// obj_pool.insert(1);
407    /// assert!(!obj_pool.is_empty());
408    /// ```
409    #[inline]
410    pub fn is_empty(&self) -> bool {
411        self.len == 0
412    }
413
414    /// Returns the `ObjId` of the next inserted object if no other
415    /// mutating calls take place in between.
416    ///
417    /// # Examples
418    ///
419    /// ```
420    /// use obj_pool::ObjPool;
421    ///
422    /// let mut obj_pool = ObjPool::new();
423    ///
424    /// let a = obj_pool.next_vacant();
425    /// let b = obj_pool.insert(1);
426    /// assert_eq!(a, b);
427    /// let c = obj_pool.next_vacant();
428    /// let d = obj_pool.insert(2);
429    /// assert_eq!(c, d);
430    /// ```
431    #[inline]
432    pub fn next_vacant(&mut self) -> ObjId {
433        self.tag.randomize();
434        self.index_to_obj_id(if self.head == u32::MAX {
435            self.len
436        } else {
437            self.head
438        })
439    }
440
441    /// Inserts an object into the object pool and returns the `ObjId` of this object.
442    /// The object pool will reallocate if it's full.
443    ///
444    /// # Examples
445    ///
446    /// ```
447    /// use obj_pool::ObjPool;
448    ///
449    /// let mut obj_pool = ObjPool::new();
450    ///
451    /// let a = obj_pool.insert(1);
452    /// let b = obj_pool.insert(2);
453    /// assert!(a != b);
454    /// ```
455    pub fn insert(&mut self, object: T) -> ObjId {
456        self.tag.randomize();
457        self.len += 1;
458
459        if self.head == u32::MAX {
460            self.slots.push(Slot::Occupied(object));
461            self.index_to_obj_id(self.len - 1)
462        } else {
463            let index = self.head;
464            match self.slots[index as usize] {
465                Slot::Vacant(next) => {
466                    self.head = next;
467                    self.slots[index as usize] = Slot::Occupied(object);
468                }
469                Slot::Occupied(_) => unreachable!(),
470            }
471            self.index_to_obj_id(index)
472        }
473    }
474
475    /// Removes the object stored by `ObjId` from the object pool and returns it.
476    ///
477    /// `None` is returned in case the there is no object with such an `ObjId`.
478    ///
479    /// # Examples
480    ///
481    /// ```
482    /// use obj_pool::ObjPool;
483    ///
484    /// let mut obj_pool = ObjPool::new();
485    /// let a = obj_pool.insert("hello");
486    ///
487    /// assert_eq!(obj_pool.len(), 1);
488    /// assert_eq!(obj_pool.remove(a), Some("hello"));
489    ///
490    /// assert_eq!(obj_pool.len(), 0);
491    /// assert_eq!(obj_pool.remove(a), None);
492    /// ```
493    pub fn remove(&mut self, obj_id: ObjId) -> Option<T> {
494        let index = self.obj_id_to_index(obj_id);
495        match self.slots.get_mut(index as usize) {
496            None => None,
497            Some(&mut Slot::Vacant(_)) => None,
498            Some(slot @ &mut Slot::Occupied(_)) => {
499                if let Slot::Occupied(object) = mem::replace(slot, Slot::Vacant(self.head)) {
500                    self.head = index;
501                    self.len -= 1;
502                    Some(object)
503                } else {
504                    unreachable!();
505                }
506            }
507        }
508    }
509
510    /// Clears the object pool, removing and dropping all objects it holds, and releases the
511    /// allocated memory.
512    ///
513    /// # Examples
514    ///
515    /// ```
516    /// use obj_pool::ObjPool;
517    ///
518    /// let mut obj_pool = ObjPool::new();
519    /// for i in 0..10 {
520    ///     obj_pool.insert(i);
521    /// }
522    ///
523    /// assert_eq!(obj_pool.len(), 10);
524    /// obj_pool.clear();
525    /// assert_eq!(obj_pool.len(), 0);
526    /// assert_eq!(obj_pool.capacity(), 0);
527    /// ```
528    #[inline]
529    pub fn clear(&mut self) {
530        self.slots.clear();
531        self.slots.shrink_to_fit();
532        self.len = 0;
533        self.head = u32::MAX;
534    }
535
536    /// Returns a reference to the object by its `ObjId`.
537    ///
538    /// If object is not found with given `obj_id`, `None` is returned.
539    ///
540    /// # Examples
541    ///
542    /// ```
543    /// use obj_pool::ObjPool;
544    ///
545    /// let mut obj_pool = ObjPool::new();
546    /// let obj_id = obj_pool.insert("hello");
547    ///
548    /// assert_eq!(obj_pool.get(obj_id), Some(&"hello"));
549    /// obj_pool.remove(obj_id);
550    /// assert_eq!(obj_pool.get(obj_id), None);
551    /// ```
552    pub fn get(&self, obj_id: ObjId) -> Option<&T> {
553        let index = self.obj_id_to_index(obj_id) as usize;
554        match self.slots.get(index) {
555            None => None,
556            Some(&Slot::Vacant(_)) => None,
557            Some(Slot::Occupied(object)) => Some(object),
558        }
559    }
560
561    /// Returns a mutable reference to the object by its `ObjId`.
562    ///
563    /// If object can't be found, `None` is returned.
564    ///
565    /// # Examples
566    ///
567    /// ```
568    /// use obj_pool::ObjPool;
569    ///
570    /// let mut obj_pool = ObjPool::new();
571    /// let obj_id = obj_pool.insert(7);
572    ///
573    /// assert_eq!(obj_pool.get_mut(obj_id), Some(&mut 7));
574    /// *obj_pool.get_mut(obj_id).unwrap() *= 10;
575    /// assert_eq!(obj_pool.get_mut(obj_id), Some(&mut 70));
576    /// ```
577    #[inline]
578    pub fn get_mut(&mut self, obj_id: ObjId) -> Option<&mut T> {
579        let index = self.obj_id_to_index(obj_id) as usize;
580        match self.slots.get_mut(index) {
581            None => None,
582            Some(&mut Slot::Vacant(_)) => None,
583            Some(&mut Slot::Occupied(ref mut object)) => Some(object),
584        }
585    }
586
587    /// Returns a reference to the object by its `ObjId`.
588    ///
589    /// # Safety
590    ///
591    /// Behavior is undefined if object can't be found.
592    ///
593    /// # Examples
594    ///
595    /// ```
596    /// use obj_pool::ObjPool;
597    ///
598    /// let mut obj_pool = ObjPool::new();
599    /// let obj_id = obj_pool.insert("hello");
600    ///
601    /// unsafe { assert_eq!(&*obj_pool.get_unchecked(obj_id), &"hello") }
602    /// ```
603    pub unsafe fn get_unchecked(&self, obj_id: ObjId) -> &T {
604        match self.slots.get(self.obj_id_to_index(obj_id) as usize) {
605            None => unsafe { unreachable_unchecked() },
606            Some(Slot::Vacant(_)) => unsafe { unreachable_unchecked() },
607            Some(Slot::Occupied(object)) => object,
608        }
609    }
610
611    /// Returns a mutable reference to the object by its `ObjId`.
612    ///
613    /// # Safety
614    ///
615    /// Behavior is undefined if object can't be found.
616    ///
617    /// # Examples
618    ///
619    /// ```
620    /// use obj_pool::ObjPool;
621    ///
622    /// let mut obj_pool = ObjPool::new();
623    /// let obj_id = obj_pool.insert("hello");
624    ///
625    /// unsafe { assert_eq!(&*obj_pool.get_unchecked_mut(obj_id), &"hello") }
626    /// ```
627    pub unsafe fn get_unchecked_mut(&mut self, obj_id: ObjId) -> &mut T {
628        let index = self.obj_id_to_index(obj_id) as usize;
629        match self.slots.get_mut(index) {
630            Some(&mut Slot::Vacant(_)) => unsafe { unreachable_unchecked() },
631            Some(&mut Slot::Occupied(ref mut object)) => object,
632            _ => unsafe { unreachable_unchecked() },
633        }
634    }
635
636    /// Swaps two objects in the object pool.
637    ///
638    /// The two `ObjId`s are `a` and `b`.
639    ///
640    /// # Panics
641    ///
642    /// Panics if any of the `ObjId`s is invalid.
643    ///
644    /// # Examples
645    ///
646    /// ```
647    /// use obj_pool::ObjPool;
648    ///
649    /// let mut obj_pool = ObjPool::new();
650    /// let a = obj_pool.insert(7);
651    /// let b = obj_pool.insert(8);
652    ///
653    /// obj_pool.swap(a, b);
654    /// assert_eq!(obj_pool.get(a), Some(&8));
655    /// assert_eq!(obj_pool.get(b), Some(&7));
656    /// ```
657    #[inline]
658    pub fn swap(&mut self, a: ObjId, b: ObjId) {
659        unsafe {
660            let fst = self.get_mut(a).unwrap() as *mut _;
661            let snd = self.get_mut(b).unwrap() as *mut _;
662            if a != b {
663                ptr::swap(fst, snd);
664            }
665        }
666    }
667
668    /// Reserves capacity for at least `additional` more objects to be inserted. The object pool may
669    /// reserve more space to avoid frequent reallocations.
670    ///
671    /// # Panics
672    ///
673    /// Panics if the new capacity overflows `u32`.
674    ///
675    /// # Examples
676    ///
677    /// ```
678    /// use obj_pool::ObjPool;
679    ///
680    /// let mut obj_pool = ObjPool::new();
681    /// obj_pool.insert("hello");
682    ///
683    /// obj_pool.reserve(10);
684    /// assert!(obj_pool.capacity() >= 11);
685    /// ```
686    pub fn reserve(&mut self, additional: u32) {
687        let vacant = self.slots.len() as u32 - self.len;
688        if additional > vacant {
689            self.slots.reserve((additional - vacant) as usize);
690        }
691    }
692
693    /// Reserves the minimum capacity for exactly `additional` more objects to be inserted.
694    ///
695    /// Note that the allocator may give the object pool more space than it requests.
696    ///
697    /// # Panics
698    ///
699    /// Panics if the new capacity overflows `u32`.
700    ///
701    /// # Examples
702    ///
703    /// ```
704    /// use obj_pool::ObjPool;
705    ///
706    /// let mut obj_pool = ObjPool::new();
707    /// obj_pool.insert("hello");
708    ///
709    /// obj_pool.reserve_exact(10);
710    /// assert!(obj_pool.capacity() >= 11);
711    /// ```
712    pub fn reserve_exact(&mut self, additional: u32) {
713        let vacant = self.slots.len() as u32 - self.len;
714        if additional > vacant {
715            self.slots.reserve_exact((additional - vacant) as usize);
716        }
717    }
718
719    /// Returns an iterator over occupied slots.
720    ///
721    /// # Examples
722    ///
723    /// ```
724    /// use obj_pool::ObjPool;
725    ///
726    /// let mut obj_pool = ObjPool::new();
727    /// obj_pool.insert(1);
728    /// obj_pool.insert(2);
729    /// obj_pool.insert(4);
730    ///
731    /// let mut iterator = obj_pool.iter();
732    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(0), &1)));
733    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(1), &2)));
734    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(2), &4)));
735    /// ```
736    #[inline]
737    pub fn iter(&self) -> Iter<'_, T> {
738        Iter {
739            len: self.len as usize,
740            slots: self.slots.iter().enumerate(),
741            tag: self.tag,
742        }
743    }
744
745    /// Returns an iterator that returns mutable references to objects.
746    ///
747    /// # Examples
748    ///
749    /// ```
750    /// use obj_pool::ObjPool;
751    ///
752    /// let mut obj_pool = ObjPool::new();
753    /// let a = obj_pool.insert("zero".to_string());
754    /// obj_pool.insert("one".to_string());
755    /// obj_pool.insert("two".to_string());
756    ///
757    /// for (obj_id, object) in obj_pool.iter_mut() {
758    ///     if obj_id == a {
759    ///         *object += "!";
760    ///     } else {
761    ///         *object += "?";
762    ///     }
763    /// }
764    ///
765    /// let mut iterator = obj_pool.iter();
766    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(0), &"zero!".to_string())));
767    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(1), &"one?".to_string())));
768    /// assert_eq!(iterator.next(), Some((obj_pool.index_to_obj_id(2), &"two?".to_string())));
769    /// ```
770    #[inline]
771    pub fn iter_mut(&mut self) -> IterMut<'_, T> {
772        IterMut {
773            len: self.len as usize,
774            slots: self.slots.iter_mut().enumerate(),
775            tag: self.tag,
776        }
777    }
778
779    /// Shrinks the capacity of the object pool as much as possible.
780    ///
781    /// It will drop down as close as possible to the length but the allocator may still inform
782    /// the object pool that there is space for a few more elements.
783    ///
784    /// # Examples
785    ///
786    /// ```
787    /// use obj_pool::ObjPool;
788    ///
789    /// let mut obj_pool = ObjPool::with_capacity(10);
790    /// obj_pool.insert("first".to_string());
791    /// obj_pool.insert("second".to_string());
792    /// obj_pool.insert("third".to_string());
793    /// assert_eq!(obj_pool.capacity(), 10);
794    /// obj_pool.shrink_to_fit();
795    /// assert!(obj_pool.capacity() >= 3);
796    /// ```
797    pub fn shrink_to_fit(&mut self) {
798        self.slots.shrink_to_fit();
799    }
800}
801
802impl<T> fmt::Debug for ObjPool<T> {
803    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
804        write!(f, "ObjPool {{ ... }}")
805    }
806}
807
808impl<T> Index<ObjId> for ObjPool<T> {
809    type Output = T;
810
811    #[inline]
812    fn index(&self, obj_id: ObjId) -> &T {
813        self.get(obj_id).expect("object not found")
814    }
815}
816
817impl<T> IndexMut<ObjId> for ObjPool<T> {
818    #[inline]
819    fn index_mut(&mut self, obj_id: ObjId) -> &mut T {
820        self.get_mut(obj_id).expect("object not found")
821    }
822}
823
824impl<T> Default for ObjPool<T> {
825    fn default() -> Self {
826        ObjPool::new()
827    }
828}
829
830impl<T: Clone> Clone for ObjPool<T> {
831    fn clone(&self) -> Self {
832        ObjPool {
833            slots: self.slots.clone(),
834            len: self.len,
835            head: self.head,
836            // The clone keeps the tag, so ids issued by the original pool stay valid for it.
837            tag: self.tag,
838        }
839    }
840}
841
842/// An iterator over the occupied slots in a `ObjPool`.
843pub struct IntoIter<T> {
844    slots: iter::Enumerate<vec::IntoIter<Slot<T>>>,
845    len: usize,
846    tag: PoolTag,
847}
848
849impl<T> Iterator for IntoIter<T> {
850    type Item = (ObjId, T);
851
852    #[inline]
853    fn next(&mut self) -> Option<Self::Item> {
854        for (index, slot) in self.slots.by_ref() {
855            if let Slot::Occupied(object) = slot {
856                self.len -= 1;
857                return Some((self.tag.mask_id(ObjId::from_index(index as u32)), object));
858            }
859        }
860        None
861    }
862
863    fn size_hint(&self) -> (usize, Option<usize>) {
864        (self.len, Some(self.len))
865    }
866}
867
868impl<T> ExactSizeIterator for IntoIter<T> {
869    fn len(&self) -> usize {
870        self.len
871    }
872}
873
874impl<T> iter::FusedIterator for IntoIter<T> {}
875
876impl<T> IntoIterator for ObjPool<T> {
877    type Item = (ObjId, T);
878    type IntoIter = IntoIter<T>;
879
880    #[inline]
881    fn into_iter(self) -> Self::IntoIter {
882        IntoIter {
883            len: self.len as usize,
884            tag: self.tag,
885            slots: self.slots.into_iter().enumerate(),
886        }
887    }
888}
889
890impl<T> iter::FromIterator<T> for ObjPool<T> {
891    fn from_iter<U: IntoIterator<Item = T>>(iter: U) -> ObjPool<T> {
892        let iter = iter.into_iter();
893        let mut obj_pool = ObjPool::with_capacity(iter.size_hint().0);
894        for i in iter {
895            obj_pool.insert(i);
896        }
897        obj_pool
898    }
899}
900
901impl<T> fmt::Debug for IntoIter<T> {
902    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
903        write!(f, "IntoIter {{ ... }}")
904    }
905}
906
907/// An iterator over references to the occupied slots in a `ObjPool`.
908pub struct Iter<'a, T: 'a> {
909    slots: iter::Enumerate<slice::Iter<'a, Slot<T>>>,
910    len: usize,
911    tag: PoolTag,
912}
913
914impl<'a, T> Iterator for Iter<'a, T> {
915    type Item = (ObjId, &'a T);
916
917    #[inline]
918    fn next(&mut self) -> Option<Self::Item> {
919        for (index, slot) in self.slots.by_ref() {
920            if let Slot::Occupied(ref object) = *slot {
921                self.len -= 1;
922                return Some((self.tag.mask_id(ObjId::from_index(index as u32)), object));
923            }
924        }
925        None
926    }
927
928    fn size_hint(&self) -> (usize, Option<usize>) {
929        (self.len, Some(self.len))
930    }
931}
932
933impl<T> ExactSizeIterator for Iter<'_, T> {
934    fn len(&self) -> usize {
935        self.len
936    }
937}
938
939impl<T> iter::FusedIterator for Iter<'_, T> {}
940
941impl<'a, T> IntoIterator for &'a ObjPool<T> {
942    type Item = (ObjId, &'a T);
943    type IntoIter = Iter<'a, T>;
944
945    #[inline]
946    fn into_iter(self) -> Self::IntoIter {
947        self.iter()
948    }
949}
950
951impl<'a, T> fmt::Debug for Iter<'a, T> {
952    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
953        write!(f, "Iter {{ ... }}")
954    }
955}
956
957/// An iterator over mutable references to the occupied slots in a `Arena`.
958pub struct IterMut<'a, T: 'a> {
959    slots: iter::Enumerate<slice::IterMut<'a, Slot<T>>>,
960    len: usize,
961    tag: PoolTag,
962}
963
964impl<'a, T> Iterator for IterMut<'a, T> {
965    type Item = (ObjId, &'a mut T);
966
967    #[inline]
968    fn next(&mut self) -> Option<Self::Item> {
969        for (index, slot) in self.slots.by_ref() {
970            if let Slot::Occupied(ref mut object) = *slot {
971                self.len -= 1;
972                return Some((self.tag.mask_id(ObjId::from_index(index as u32)), object));
973            }
974        }
975        None
976    }
977
978    fn size_hint(&self) -> (usize, Option<usize>) {
979        (self.len, Some(self.len))
980    }
981}
982
983impl<T> ExactSizeIterator for IterMut<'_, T> {
984    fn len(&self) -> usize {
985        self.len
986    }
987}
988
989impl<T> iter::FusedIterator for IterMut<'_, T> {}
990
991impl<'a, T> IntoIterator for &'a mut ObjPool<T> {
992    type Item = (ObjId, &'a mut T);
993    type IntoIter = IterMut<'a, T>;
994
995    #[inline]
996    fn into_iter(self) -> Self::IntoIter {
997        self.iter_mut()
998    }
999}
1000
1001impl<'a, T> fmt::Debug for IterMut<'a, T> {
1002    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1003        write!(f, "IterMut {{ ... }}")
1004    }
1005}
1006
1007#[cfg(test)]
1008mod tests {
1009    use super::*;
1010
1011    #[test]
1012    fn new() {
1013        let obj_pool = ObjPool::<i32>::new();
1014        assert!(obj_pool.is_empty());
1015        assert_eq!(obj_pool.len(), 0);
1016        assert_eq!(obj_pool.capacity(), 0);
1017    }
1018
1019    #[test]
1020    fn insert() {
1021        let mut obj_pool = ObjPool::new();
1022
1023        for i in 0..10 {
1024            let a = obj_pool.insert(i * 10);
1025            assert_eq!(obj_pool[a], i * 10);
1026        }
1027        assert!(!obj_pool.is_empty());
1028        assert_eq!(obj_pool.len(), 10);
1029    }
1030
1031    #[test]
1032    fn with_capacity() {
1033        let mut obj_pool = ObjPool::with_capacity(10);
1034        assert_eq!(obj_pool.capacity(), 10);
1035
1036        for _ in 0..10 {
1037            obj_pool.insert(());
1038        }
1039        assert_eq!(obj_pool.len(), 10);
1040        assert_eq!(obj_pool.capacity(), 10);
1041
1042        obj_pool.insert(());
1043        assert_eq!(obj_pool.len(), 11);
1044        assert!(obj_pool.capacity() > 10);
1045    }
1046
1047    #[test]
1048    fn remove() {
1049        let mut obj_pool = ObjPool::new();
1050
1051        let a = obj_pool.insert(0);
1052        let b = obj_pool.insert(10);
1053        let c = obj_pool.insert(20);
1054        obj_pool.insert(30);
1055        assert_eq!(obj_pool.len(), 4);
1056
1057        assert_eq!(obj_pool.remove(b), Some(10));
1058        assert_eq!(obj_pool.remove(c), Some(20));
1059        assert_eq!(obj_pool.len(), 2);
1060
1061        obj_pool.insert(-1);
1062        obj_pool.insert(-1);
1063        assert_eq!(obj_pool.len(), 4);
1064
1065        assert_eq!(obj_pool.remove(a), Some(0));
1066        obj_pool.insert(-1);
1067        assert_eq!(obj_pool.len(), 4);
1068
1069        obj_pool.insert(400);
1070        assert_eq!(obj_pool.len(), 5);
1071    }
1072
1073    #[test]
1074    fn clear() {
1075        let mut obj_pool = ObjPool::new();
1076        obj_pool.insert(10);
1077        obj_pool.insert(20);
1078
1079        assert!(!obj_pool.is_empty());
1080        assert_eq!(obj_pool.len(), 2);
1081
1082        obj_pool.clear();
1083
1084        assert!(obj_pool.is_empty());
1085        assert_eq!(obj_pool.len(), 0);
1086        assert_eq!(obj_pool.capacity(), 0);
1087    }
1088
1089    #[test]
1090    fn indexing() {
1091        let mut obj_pool = ObjPool::new();
1092
1093        let a = obj_pool.insert(10);
1094        let b = obj_pool.insert(20);
1095        let c = obj_pool.insert(30);
1096
1097        obj_pool[b] += obj_pool[c];
1098        assert_eq!(obj_pool[a], 10);
1099        assert_eq!(obj_pool[b], 50);
1100        assert_eq!(obj_pool[c], 30);
1101    }
1102
1103    #[test]
1104    #[should_panic]
1105    fn indexing_vacant() {
1106        let mut obj_pool = ObjPool::new();
1107
1108        let _ = obj_pool.insert(10);
1109        let b = obj_pool.insert(20);
1110        let _ = obj_pool.insert(30);
1111
1112        obj_pool.remove(b);
1113        obj_pool[b];
1114    }
1115
1116    #[test]
1117    #[should_panic]
1118    fn invalid_indexing() {
1119        let mut obj_pool = ObjPool::new();
1120
1121        obj_pool.insert(10);
1122        obj_pool.insert(20);
1123        let a = obj_pool.insert(30);
1124        obj_pool.remove(a);
1125
1126        obj_pool[a];
1127    }
1128
1129    #[test]
1130    fn get() {
1131        let mut obj_pool = ObjPool::new();
1132
1133        let a = obj_pool.insert(10);
1134        let b = obj_pool.insert(20);
1135        let c = obj_pool.insert(30);
1136
1137        *obj_pool.get_mut(b).unwrap() += *obj_pool.get(c).unwrap();
1138        assert_eq!(obj_pool.get(a), Some(&10));
1139        assert_eq!(obj_pool.get(b), Some(&50));
1140        assert_eq!(obj_pool.get(c), Some(&30));
1141
1142        obj_pool.remove(b);
1143        assert_eq!(obj_pool.get(b), None);
1144        assert_eq!(obj_pool.get_mut(b), None);
1145    }
1146
1147    #[test]
1148    fn reserve() {
1149        let mut obj_pool = ObjPool::new();
1150        obj_pool.insert(1);
1151        obj_pool.insert(2);
1152
1153        obj_pool.reserve(10);
1154        assert!(obj_pool.capacity() >= 11);
1155    }
1156
1157    #[test]
1158    fn reserve_exact() {
1159        let mut obj_pool = ObjPool::new();
1160        obj_pool.insert(1);
1161        obj_pool.insert(2);
1162        obj_pool.reserve(10);
1163        assert!(obj_pool.capacity() >= 11);
1164    }
1165
1166    #[test]
1167    fn iter() {
1168        let mut arena = ObjPool::new();
1169        let a = arena.insert(10);
1170        let b = arena.insert(20);
1171        let c = arena.insert(30);
1172        let d = arena.insert(40);
1173
1174        arena.remove(b);
1175
1176        let mut it = arena.iter();
1177        assert_eq!(it.next(), Some((a, &10)));
1178        assert_eq!(it.next(), Some((c, &30)));
1179        assert_eq!(it.next(), Some((d, &40)));
1180        assert_eq!(it.next(), None);
1181    }
1182
1183    #[test]
1184    fn iter_mut() {
1185        let mut obj_pool = ObjPool::new();
1186        let a = obj_pool.insert(10);
1187        let b = obj_pool.insert(20);
1188        let c = obj_pool.insert(30);
1189        let d = obj_pool.insert(40);
1190
1191        obj_pool.remove(b);
1192
1193        {
1194            let mut it = obj_pool.iter_mut();
1195            assert_eq!(it.next(), Some((a, &mut 10)));
1196            assert_eq!(it.next(), Some((c, &mut 30)));
1197            assert_eq!(it.next(), Some((d, &mut 40)));
1198            assert_eq!(it.next(), None);
1199        }
1200
1201        for (obj_id, value) in &mut obj_pool {
1202            *value += obj_id.get();
1203        }
1204
1205        let mut it = obj_pool.iter_mut();
1206        assert_eq!(*it.next().unwrap().1, 10 + a.get());
1207        assert_eq!(*it.next().unwrap().1, 30 + c.get());
1208        assert_eq!(*it.next().unwrap().1, 40 + d.get());
1209        assert_eq!(it.next(), None);
1210    }
1211
1212    #[test]
1213    fn from_iter() {
1214        let obj_pool: ObjPool<usize> = [10, 20, 30, 40].iter().cloned().collect();
1215
1216        let mut it = obj_pool.iter();
1217        assert_eq!(it.next(), Some((obj_pool.index_to_obj_id(0), &10)));
1218        assert_eq!(it.next(), Some((obj_pool.index_to_obj_id(1), &20)));
1219        assert_eq!(it.next(), Some((obj_pool.index_to_obj_id(2), &30)));
1220        assert_eq!(it.next(), Some((obj_pool.index_to_obj_id(3), &40)));
1221        assert_eq!(it.next(), None);
1222    }
1223
1224    #[test]
1225    fn obj_id_index_round_trip() {
1226        let mut obj_pool = ObjPool::new();
1227        let a = obj_pool.insert(10);
1228        let b = obj_pool.insert(20);
1229
1230        assert_eq!(obj_pool.obj_id_to_index(a), 0);
1231        assert_eq!(obj_pool.obj_id_to_index(b), 1);
1232        assert_eq!(obj_pool.index_to_obj_id(0), a);
1233        assert_eq!(obj_pool.index_to_obj_id(1), b);
1234    }
1235
1236    #[cfg(debug_assertions)]
1237    #[test]
1238    fn foreign_obj_id_is_rejected() {
1239        let mut a = ObjPool::new();
1240        let id = a.insert(10);
1241
1242        let mut b = ObjPool::new();
1243        b.insert(20);
1244        // Make sure the pools did not roll the same random offset, so the check
1245        // below is deterministic: `id` unmasks in `b` to a non-zero index, which
1246        // is out of bounds for a pool with a single slot.
1247        while b.tag.offset == a.tag.offset {
1248            b = ObjPool::new();
1249            b.insert(20);
1250        }
1251
1252        assert_eq!(b.get(id), None);
1253        assert_eq!(b.get_mut(id), None);
1254        assert_eq!(b.remove(id), None);
1255        assert_eq!(b.get(b.index_to_obj_id(0)), Some(&20));
1256    }
1257
1258    #[test]
1259    fn free_list_is_lifo() {
1260        let mut obj_pool = ObjPool::new();
1261        let a = obj_pool.insert(1);
1262        let b = obj_pool.insert(2);
1263        let c = obj_pool.insert(3);
1264
1265        obj_pool.remove(a);
1266        obj_pool.remove(c);
1267
1268        // Vacant slots are reused most-recently-removed first.
1269        assert_eq!(obj_pool.next_vacant(), c);
1270        assert_eq!(obj_pool.insert(30), c);
1271        assert_eq!(obj_pool.next_vacant(), a);
1272        assert_eq!(obj_pool.insert(10), a);
1273
1274        // No vacant slots left: the next insert appends.
1275        let next = obj_pool.next_vacant();
1276        assert_eq!(obj_pool.obj_id_to_index(next), 3);
1277        assert_eq!(obj_pool.insert(4), next);
1278        assert_eq!(obj_pool.len(), 4);
1279        assert_eq!(obj_pool.get(b), Some(&2));
1280    }
1281
1282    #[test]
1283    fn unknown_id_is_not_found() {
1284        let mut obj_pool = ObjPool::new();
1285        obj_pool.insert(1);
1286
1287        let unknown = obj_pool.index_to_obj_id(100);
1288        assert_eq!(obj_pool.get(unknown), None);
1289        assert_eq!(obj_pool.get_mut(unknown), None);
1290        assert_eq!(obj_pool.remove(unknown), None);
1291        assert_eq!(obj_pool.len(), 1);
1292    }
1293
1294    #[test]
1295    fn clear_then_insert_reuses_ids() {
1296        let mut obj_pool = ObjPool::new();
1297        let a = obj_pool.insert(1);
1298        obj_pool.insert(2);
1299        obj_pool.clear();
1300
1301        // Stale ids decode out of bounds after a clear.
1302        assert_eq!(obj_pool.get(a), None);
1303        assert_eq!(obj_pool.remove(a), None);
1304
1305        // The pool keeps its tag, so freshly inserted objects get the same ids again.
1306        let b = obj_pool.insert(3);
1307        assert_eq!(b, a);
1308        assert_eq!(obj_pool.get(b), Some(&3));
1309        assert_eq!(obj_pool.len(), 1);
1310    }
1311
1312    #[test]
1313    fn into_iter_skips_vacant() {
1314        let mut obj_pool = ObjPool::new();
1315        let a = obj_pool.insert(10);
1316        let b = obj_pool.insert(20);
1317        let c = obj_pool.insert(30);
1318        obj_pool.remove(b);
1319
1320        let items: Vec<_> = obj_pool.into_iter().collect();
1321        assert_eq!(items, [(a, 10), (c, 30)]);
1322    }
1323
1324    #[test]
1325    fn iterate_with_vacant_ends() {
1326        let mut obj_pool = ObjPool::new();
1327        let a = obj_pool.insert(10);
1328        let b = obj_pool.insert(20);
1329        let c = obj_pool.insert(30);
1330        obj_pool.remove(a);
1331        obj_pool.remove(c);
1332
1333        let items: Vec<_> = obj_pool.iter().map(|(k, &v)| (k, v)).collect();
1334        assert_eq!(items, [(b, 20)]);
1335    }
1336
1337    #[test]
1338    fn iterate_empty_and_fully_vacant() {
1339        let mut obj_pool: ObjPool<i32> = ObjPool::new();
1340        assert_eq!(obj_pool.iter().next(), None);
1341        assert_eq!(obj_pool.iter().size_hint(), (0, Some(0)));
1342
1343        let keys: Vec<_> = (0..4).map(|v| obj_pool.insert(v)).collect();
1344        for k in keys {
1345            obj_pool.remove(k);
1346        }
1347        assert!(obj_pool.is_empty());
1348        assert_eq!(obj_pool.iter().size_hint(), (0, Some(0)));
1349        assert_eq!(obj_pool.iter().next(), None);
1350        assert_eq!(obj_pool.iter_mut().next(), None);
1351        assert_eq!(obj_pool.into_iter().next(), None);
1352    }
1353
1354    #[test]
1355    fn iterator_len_and_fuse() {
1356        let mut obj_pool = ObjPool::new();
1357        obj_pool.insert(10);
1358        let b = obj_pool.insert(20);
1359        obj_pool.insert(30);
1360        obj_pool.remove(b);
1361
1362        let mut it = obj_pool.iter();
1363        assert_eq!(it.len(), 2);
1364        assert_eq!(it.size_hint(), (2, Some(2)));
1365        it.next();
1366        assert_eq!(it.len(), 1);
1367        it.next();
1368        assert_eq!(it.len(), 0);
1369        assert_eq!(it.next(), None);
1370        // Fused: keeps returning `None` after the end.
1371        assert_eq!(it.next(), None);
1372
1373        let mut it = obj_pool.iter_mut();
1374        assert_eq!(it.len(), 2);
1375        it.next();
1376        assert_eq!(it.size_hint(), (1, Some(1)));
1377
1378        let mut it = obj_pool.into_iter();
1379        assert_eq!(it.len(), 2);
1380        it.next();
1381        assert_eq!(it.len(), 1);
1382    }
1383
1384    #[test]
1385    fn clone_preserves_ids_and_free_list() {
1386        let mut original = ObjPool::new();
1387        let a = original.insert(1);
1388        let b = original.insert(2);
1389        let c = original.insert(3);
1390        original.remove(b);
1391
1392        let mut clone = original.clone();
1393        // Ids issued by the original resolve to the same objects in the clone.
1394        assert_eq!(clone.get(a), Some(&1));
1395        assert_eq!(clone.get(b), None);
1396        assert_eq!(clone.get(c), Some(&3));
1397        assert_eq!(clone.len(), original.len());
1398
1399        // The free list is cloned too: both pools reuse the same vacant slot,
1400        // then append, issuing equal ids.
1401        assert_eq!(clone.insert(20), original.insert(20));
1402        assert_eq!(clone.insert(4), original.insert(4));
1403    }
1404
1405    #[test]
1406    fn swap_with_itself() {
1407        let mut obj_pool = ObjPool::new();
1408        let a = obj_pool.insert(7);
1409        obj_pool.swap(a, a);
1410        assert_eq!(obj_pool.get(a), Some(&7));
1411    }
1412
1413    #[test]
1414    #[should_panic]
1415    fn swap_removed_id_panics() {
1416        let mut obj_pool = ObjPool::new();
1417        let a = obj_pool.insert(1);
1418        let b = obj_pool.insert(2);
1419        obj_pool.remove(b);
1420        obj_pool.swap(a, b);
1421    }
1422
1423    #[test]
1424    fn reserve_accounts_for_vacant_slots() {
1425        let mut obj_pool = ObjPool::with_capacity(2);
1426        let a = obj_pool.insert(1);
1427        obj_pool.insert(2);
1428        obj_pool.remove(a);
1429
1430        // One slot is vacant, so reserving room for one object needs no new memory.
1431        obj_pool.reserve(1);
1432        assert_eq!(obj_pool.capacity(), 2);
1433        obj_pool.reserve_exact(1);
1434        assert_eq!(obj_pool.capacity(), 2);
1435    }
1436
1437    #[test]
1438    fn obj_id_display_from_str_round_trip() {
1439        let mut obj_pool = ObjPool::new();
1440        let a = obj_pool.insert(7);
1441
1442        let parsed: ObjId = a.to_string().parse().unwrap();
1443        assert_eq!(parsed, a);
1444        assert_eq!(obj_pool.get(parsed), Some(&7));
1445
1446        assert!("0".parse::<ObjId>().is_err());
1447        assert!("".parse::<ObjId>().is_err());
1448        assert!("abc".parse::<ObjId>().is_err());
1449        assert!("4294967296".parse::<ObjId>().is_err()); // u32::MAX + 1
1450    }
1451
1452    #[test]
1453    fn obj_id_raw_round_trip() {
1454        for index in [0, 1, 42, u32::MAX - 1] {
1455            assert_eq!(ObjId::from_index(index).into_index(), index);
1456        }
1457    }
1458
1459    #[cfg(debug_assertions)]
1460    #[test]
1461    #[should_panic(expected = "index out of range")]
1462    fn from_index_max_panics_in_debug() {
1463        let _ = ObjId::from_index(u32::MAX);
1464    }
1465}