slabbable_slab/
lib.rs

1#![warn(
2    clippy::unwrap_used,
3    missing_docs,
4    rust_2018_idioms,
5    unused_lifetimes,
6    unused_qualifications
7)]
8#![allow(clippy::single_match, rustdoc::bare_urls)]
9#![cfg_attr(all(not(feature = "std"), not(test)), no_std)]
10#![doc = include_str!("../README.md")]
11
12use slab::Slab;
13use slabbable::{ReservedSlot, Slabbable, SlabbableError};
14
15#[derive(Debug)]
16enum ReserveStatus<Item> {
17    Reserved,
18    Taken(Item),
19}
20
21/// Holder
22#[derive(Debug)]
23pub struct SlabSlab<Item> {
24    inner: Slab<ReserveStatus<Item>>,
25}
26
27impl<Item> Slabbable<SlabSlab<Item>, Item> for SlabSlab<Item>
28where
29    Item: core::fmt::Debug + Clone,
30{
31    type Error = SlabbableError;
32    /// See trait
33    fn with_fixed_capacity(cap: usize) -> Result<Self, Self::Error> {
34        Ok(Self {
35            inner: Slab::with_capacity(cap),
36        })
37    }
38    /// See trait
39    #[inline]
40    fn reserve_next(&mut self) -> Result<ReservedSlot, Self::Error> {
41        // Slab re-allocators upon grow - we want stable addresses
42        if self.inner.capacity() < self.inner.len() + 1 {
43            return Err(SlabbableError::AtCapacity(self.inner.capacity()));
44        }
45        let ins = self.inner.insert(ReserveStatus::Reserved);
46        Ok(ReservedSlot::issue(ins))
47    }
48    /// See trait
49    #[inline]
50    fn take_reserved_with(
51        &mut self,
52        r_slot: ReservedSlot,
53        with: Item,
54    ) -> Result<usize, Self::Error> {
55        let slot = r_slot.id();
56
57        let v = match self.inner.get_mut(slot) {
58            Some(v) => match v {
59                ReserveStatus::Reserved => v,
60                _ => return Err(SlabbableError::InvalidIndex(slot)),
61            },
62            _ => return Err(SlabbableError::InvalidIndex(slot)),
63        };
64        *v = ReserveStatus::Taken(with);
65        Ok(slot)
66    }
67    /// See trait
68    #[inline]
69    fn take_next_with(&mut self, with: Item) -> Result<usize, Self::Error> {
70        let reserved_slot = self.reserve_next()?;
71        self.take_reserved_with(reserved_slot, with)
72    }
73    /// See trait
74    #[inline]
75    fn mark_for_reuse(&mut self, slot: usize) -> Result<Item, Self::Error> {
76        if slot > self.inner.capacity() {
77            return Err(SlabbableError::InvalidIndex(slot));
78        }
79        match self.inner.try_remove(slot) {
80            Some(ReserveStatus::Taken(i)) => Ok(i),
81            _ => Err(SlabbableError::InvalidIndex(slot)),
82        }
83    }
84    /// See trait
85    #[inline]
86    fn slot_get_ref(&self, slot: usize) -> Result<Option<&Item>, Self::Error> {
87        if slot > self.inner.capacity() {
88            return Err(SlabbableError::InvalidIndex(slot));
89        }
90        match self.inner.get(slot) {
91            Some(ReserveStatus::Taken(itm_ref)) => Ok(Some(itm_ref)),
92            _ => Err(SlabbableError::InvalidIndex(slot)),
93        }
94    }
95    /// See trait
96    #[inline]
97    fn slot_get_mut(&mut self, slot: usize) -> Result<Option<&mut Item>, Self::Error> {
98        if slot > self.inner.capacity() {
99            return Err(SlabbableError::InvalidIndex(slot));
100        }
101        match self.inner.get_mut(slot) {
102            Some(ReserveStatus::Taken(itm_ref)) => Ok(Some(itm_ref)),
103            _ => Err(SlabbableError::InvalidIndex(slot)),
104        }
105    }
106    /// See trait
107    #[inline]
108    fn capacity(&self) -> usize {
109        self.inner.capacity()
110    }
111    /// See trait
112    #[inline]
113    fn remaining(&self) -> Option<usize> {
114        let rem = self.inner.capacity() - self.inner.len();
115        match rem {
116            0 => None,
117            1_usize.. => Some(rem),
118        }
119    }
120    /// See trait
121    fn reap(&mut self) -> Option<usize> {
122        // We don't support it
123        None
124    }
125}