1use core::mem;
4
5#[derive(Debug)]
7pub(crate) struct Slab<T> {
8 vacant: usize,
9 items: Vec<Entry<T>>,
10}
11
12#[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)]
27pub(crate) struct ErasedSlab {
29 data_vacant: usize,
30 data_ptr: usize,
31 data_len: usize,
32 data_capacity: usize,
33}
34
35fn 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}