repository/
slab.rs

1//! Provides storage for a single data type with vacant entry support.
2
3use core::mem;
4
5/// Provides storage for a single data type with vacant entry support.
6#[derive(Debug)]
7pub(crate) struct Slab<T> {
8    vacant: usize,
9    items: Vec<Entry<T>>,
10}
11
12/// An entry in a `Slab`.
13#[derive(Debug)]
14enum Entry<T> {
15    Occupied(T),
16    Vacant(usize),
17}
18
19impl<T> Entry<T> {
20    #[inline]
21    fn is_occupied(&self) -> bool {
22        matches!(self, Entry::Occupied(_))
23    }
24}
25
26#[derive(Copy, Clone)]
27/// Type erased storage of a `Slab`.
28pub(crate) struct ErasedSlab {
29    data_vacant: usize,
30    data_ptr: usize,
31    data_len: usize,
32    data_capacity: usize,
33}
34
35/// convert a `Vec` into its raw parts
36fn vec_into_raw_parts<T>(me: Vec<T>) -> (*mut T, usize, usize) {
37    use std::mem::ManuallyDrop;
38    let mut me = ManuallyDrop::new(me);
39    (me.as_mut_ptr(), me.len(), me.capacity())
40}
41
42impl<T> Slab<T> {
43    pub(crate) fn new() -> Self {
44        Self::with_capacity(0)
45    }
46
47    pub(crate) fn with_capacity(capacity: usize) -> Self {
48        Slab {
49            vacant: capacity,
50            items: Vec::with_capacity(capacity),
51        }
52    }
53
54    pub(crate) fn into_erased_slab(self) -> ErasedSlab {
55        let (ptr, len, capacity) = vec_into_raw_parts(self.items);
56        ErasedSlab {
57            data_vacant: self.vacant,
58            data_ptr: ptr as usize,
59            data_len: len,
60            data_capacity: capacity,
61        }
62    }
63
64    pub(crate) unsafe fn from_erased_slab(erased_slab: ErasedSlab) -> Self {
65        Slab {
66            vacant: erased_slab.data_vacant,
67            items: Vec::from_raw_parts(
68                erased_slab.data_ptr as *mut Entry<T>,
69                erased_slab.data_len,
70                erased_slab.data_capacity,
71            ),
72        }
73    }
74
75    pub(crate) fn get(&self, index: usize) -> Option<&T> {
76        match self.items.get(index) {
77            Some(Entry::Occupied(v)) => Some(v),
78            _ => None,
79        }
80    }
81
82    #[allow(dead_code)]
83    pub(crate) fn get_mut(&mut self, index: usize) -> Option<&mut T> {
84        match self.items.get_mut(index) {
85            Some(Entry::Occupied(v)) => Some(v),
86            _ => None,
87        }
88    }
89
90    pub(crate) fn is_occupied(&self, index: usize) -> bool {
91        matches!(self.items.get(index), Some(Entry::Occupied(_)))
92    }
93
94    pub(crate) fn is_detached_vacant(&self, index: usize) -> bool {
95        matches!(self.items.get(index), Some(Entry::Vacant(usize::MAX)))
96    }
97
98    pub(crate) fn remove(&mut self, index: usize) -> Option<T> {
99        match self.items.get_mut(index) {
100            Some(e @ Entry::Occupied(_)) => {
101                let mut entry = Entry::Vacant(self.vacant);
102                mem::swap(e, &mut entry);
103                self.vacant = index;
104                match entry {
105                    Entry::Occupied(v) => Some(v),
106                    _ => unreachable!(),
107                }
108            }
109            _ => None,
110        }
111    }
112
113    pub(crate) fn push(&mut self, value: T) -> usize {
114        let index = self.vacant;
115        if let Some(e) = self.items.get_mut(self.vacant) {
116            let mut entry = Entry::Occupied(value);
117            mem::swap(e, &mut entry);
118            match entry {
119                Entry::Vacant(v) => self.vacant = v,
120                Entry::Occupied(_) => unreachable!(),
121            };
122            index
123        } else {
124            debug_assert_eq!(self.vacant, self.items.len());
125            let entry = Entry::Occupied(value);
126            self.items.push(entry);
127            self.vacant += 1;
128            index
129        }
130    }
131
132    pub(crate) fn detach_vacant(&mut self) -> usize {
133        let index = self.vacant;
134        if let Some(e) = self.items.get_mut(self.vacant) {
135            let mut entry = Entry::Vacant(usize::MAX);
136            mem::swap(e, &mut entry);
137            match entry {
138                Entry::Vacant(v) => self.vacant = v,
139                Entry::Occupied(_) => unreachable!(),
140            };
141            index
142        } else {
143            debug_assert_eq!(self.vacant, self.items.len());
144            let entry = Entry::Vacant(usize::MAX);
145            self.items.push(entry);
146            self.vacant += 1;
147            index
148        }
149    }
150
151    pub(crate) fn occupy_detached_vacant(
152        &mut self,
153        index: usize,
154        value: T,
155    ) -> Result<(), EntryError> {
156        let e = match self.items.get_mut(index) {
157            Some(e) => e,
158            None => return Err(EntryError::InvalidIdx),
159        };
160        if !matches!(e, Entry::Vacant(usize::MAX)) {
161            if e.is_occupied() {
162                return Err(EntryError::EntryIsOccupied);
163            } else {
164                return Err(EntryError::EntryIsVacant);
165            }
166        }
167        *e = Entry::Occupied(value);
168        Ok(())
169    }
170
171    pub(crate) fn reattach_vacant(&mut self, index: usize) -> Result<(), EntryError> {
172        let e = match self.items.get_mut(index) {
173            Some(e) => e,
174            None => return Err(EntryError::InvalidIdx),
175        };
176        if !matches!(e, Entry::Vacant(usize::MAX)) {
177            if e.is_occupied() {
178                return Err(EntryError::EntryIsOccupied);
179            } else {
180                return Err(EntryError::EntryIsVacant);
181            }
182        }
183        *e = Entry::Vacant(self.vacant);
184        self.vacant = index;
185        Ok(())
186    }
187}
188
189#[derive(Debug)]
190pub(crate) enum EntryError {
191    InvalidIdx,
192    EntryIsOccupied,
193    EntryIsVacant,
194    #[allow(dead_code)]
195    EntryIsDetachedVacant,
196}
197
198impl ErasedSlab {
199    #[allow(unused_unsafe)]
200    pub(crate) unsafe fn index<'a, T>(self, index: usize) -> &'a T {
201        use core::slice;
202        let slice =
203            unsafe { slice::from_raw_parts(self.data_ptr as *const Entry<T>, self.data_len) };
204        match &slice[index] {
205            Entry::Occupied(v) => v,
206            _ => unreachable!(),
207        }
208    }
209
210    #[allow(unused_unsafe)]
211    pub(crate) unsafe fn index_mut<'a, T>(self, index: usize) -> &'a mut T {
212        use core::slice;
213        let slice =
214            unsafe { slice::from_raw_parts_mut(self.data_ptr as *mut Entry<T>, self.data_len) };
215        match &mut slice[index] {
216            Entry::Occupied(v) => v,
217            _ => unreachable!(),
218        }
219    }
220}