1use alloc::vec::Vec;
14
15struct Slot<T> {
17 value: Option<T>,
18 generation: u32,
20}
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
28pub struct PoolHandle {
29 index: u32,
30 generation: u32,
31}
32
33impl PoolHandle {
34 pub const fn from_parts(index: u32, generation: u32) -> Self {
39 Self { index, generation }
40 }
41
42 pub const fn index(self) -> usize {
44 self.index as usize
45 }
46
47 pub const fn generation(self) -> u32 {
49 self.generation
50 }
51}
52
53pub struct Pool<T> {
55 slots: Vec<Slot<T>>,
56 free: Vec<u32>,
58 len: usize,
59}
60
61impl<T> Pool<T> {
62 pub fn with_capacity(capacity: usize) -> Self {
65 let mut slots = Vec::with_capacity(capacity);
66 let mut free = Vec::with_capacity(capacity);
67 for index in 0..capacity {
68 slots.push(Slot {
69 value: None,
70 generation: 0,
71 });
72 free.push((capacity - 1 - index) as u32);
75 }
76 Self {
77 slots,
78 free,
79 len: 0,
80 }
81 }
82
83 pub fn capacity(&self) -> usize {
85 self.slots.len()
86 }
87
88 pub fn len(&self) -> usize {
90 self.len
91 }
92
93 pub fn is_empty(&self) -> bool {
95 self.len == 0
96 }
97
98 #[cfg(test)]
99 pub(crate) fn is_full(&self) -> bool {
100 self.free.is_empty()
101 }
102
103 pub fn reserved_bytes(&self) -> u64 {
106 (self.capacity() * size_of::<Slot<T>>()) as u64
107 }
108
109 pub fn insert(&mut self, value: T) -> Option<PoolHandle> {
112 let index = self.free.pop()?;
113 let slot = &mut self.slots[index as usize];
114 slot.value = Some(value);
115 self.len += 1;
116 Some(PoolHandle {
117 index,
118 generation: slot.generation,
119 })
120 }
121
122 pub fn remove(&mut self, handle: PoolHandle) -> Option<T> {
125 let slot = self.slots.get_mut(handle.index as usize)?;
126 if slot.generation != handle.generation {
127 return None;
128 }
129 let value = slot.value.take()?;
130 slot.generation = slot.generation.wrapping_add(1);
131 self.free.push(handle.index);
132 self.len -= 1;
133 Some(value)
134 }
135
136 pub fn get(&self, handle: PoolHandle) -> Option<&T> {
138 let slot = self.slots.get(handle.index as usize)?;
139 (slot.generation == handle.generation).then_some(slot.value.as_ref()?)
140 }
141
142 pub fn get_mut(&mut self, handle: PoolHandle) -> Option<&mut T> {
144 let slot = self.slots.get_mut(handle.index as usize)?;
145 if slot.generation != handle.generation {
146 return None;
147 }
148 slot.value.as_mut()
149 }
150
151 pub fn get_at(&self, index: usize) -> Option<&T> {
157 self.slots.get(index)?.value.as_ref()
158 }
159
160 pub fn get_at_mut(&mut self, index: usize) -> Option<&mut T> {
162 self.slots.get_mut(index)?.value.as_mut()
163 }
164
165 pub fn handle_at(&self, index: usize) -> Option<PoolHandle> {
168 let slot = self.slots.get(index)?;
169 slot.value.as_ref()?;
170 Some(PoolHandle {
171 index: index as u32,
172 generation: slot.generation,
173 })
174 }
175
176 pub fn contains(&self, handle: PoolHandle) -> bool {
178 self.get(handle).is_some()
179 }
180
181 pub fn iter(&self) -> impl Iterator<Item = (PoolHandle, &T)> {
183 self.slots.iter().enumerate().filter_map(|(index, slot)| {
184 let value = slot.value.as_ref()?;
185 Some((
186 PoolHandle {
187 index: index as u32,
188 generation: slot.generation,
189 },
190 value,
191 ))
192 })
193 }
194
195 pub fn iter_mut(&mut self) -> impl Iterator<Item = (PoolHandle, &mut T)> {
197 self.slots
198 .iter_mut()
199 .enumerate()
200 .filter_map(|(index, slot)| {
201 let generation = slot.generation;
202 let value = slot.value.as_mut()?;
203 Some((
204 PoolHandle {
205 index: index as u32,
206 generation,
207 },
208 value,
209 ))
210 })
211 }
212
213 pub fn clear(&mut self) {
216 self.free.clear();
217 for (index, slot) in self.slots.iter_mut().enumerate().rev() {
218 if slot.value.take().is_some() {
219 slot.generation = slot.generation.wrapping_add(1);
220 }
221 self.free.push(index as u32);
222 }
223 self.len = 0;
224 }
225}
226
227#[cfg(test)]
228mod tests {
229 use super::*;
230
231 #[test]
232 fn inserts_read_back_through_their_handles() {
233 let mut pool = Pool::with_capacity(4);
234 let a = pool.insert("a").expect("room");
235 let b = pool.insert("b").expect("room");
236
237 assert_eq!(pool.get(a), Some(&"a"));
238 assert_eq!(pool.get(b), Some(&"b"));
239 assert_eq!(pool.len(), 2);
240 assert_eq!(pool.capacity(), 4);
241 }
242
243 #[test]
244 fn a_fresh_pool_fills_its_slots_in_order() {
245 let mut pool = Pool::with_capacity(3);
246 for expected in 0..3 {
247 assert_eq!(pool.insert(expected).expect("room").index(), expected);
248 }
249 }
250
251 #[test]
252 fn removal_frees_the_slot_for_reuse() {
253 let mut pool = Pool::with_capacity(2);
254 let a = pool.insert(1).expect("room");
255 let b = pool.insert(2).expect("room");
256 assert!(pool.is_full());
257
258 assert_eq!(pool.remove(a), Some(1));
259 assert_eq!(pool.len(), 1);
260 let c = pool.insert(3).expect("the freed slot");
261 assert_eq!(c.index(), a.index(), "the vacated slot is reused");
262 assert_eq!(pool.get(b), Some(&2));
263 assert_eq!(pool.get(c), Some(&3));
264 }
265
266 #[test]
269 fn a_slot_hands_back_the_handle_naming_its_occupant() {
270 let mut pool = Pool::with_capacity(2);
271 let a = pool.insert("a").expect("room");
272 assert_eq!(pool.handle_at(a.index()), Some(a));
273 assert_eq!(pool.handle_at(1), None, "vacant");
274 assert_eq!(pool.handle_at(99), None, "out of range");
275
276 pool.remove(a);
277 assert_eq!(pool.handle_at(a.index()), None);
278 let b = pool.insert("b").expect("the freed slot");
279 assert_eq!(pool.handle_at(b.index()), Some(b));
280 assert_ne!(
281 pool.handle_at(b.index()),
282 Some(a),
283 "the generation moved on"
284 );
285 }
286
287 #[test]
290 fn a_stale_handle_does_not_reach_the_slots_new_occupant() {
291 let mut pool = Pool::with_capacity(1);
292 let old = pool.insert("first").expect("room");
293 assert_eq!(pool.remove(old), Some("first"));
294 let new = pool.insert("second").expect("the freed slot");
295
296 assert_eq!(new.index(), old.index());
297 assert_eq!(pool.get(old), None);
298 assert!(!pool.contains(old));
299 assert_eq!(pool.get_mut(old), None);
300 assert_eq!(pool.remove(old), None);
301 assert_eq!(pool.get(new), Some(&"second"));
302 }
303
304 #[test]
307 fn slot_access_reaches_the_occupant_and_skips_the_vacancies() {
308 let mut pool = Pool::with_capacity(3);
309 let a = pool.insert(1).expect("room");
310 let b = pool.insert(2).expect("room");
311 assert_eq!(pool.get_at(a.index()), Some(&1));
312 assert_eq!(pool.get_at(b.index()), Some(&2));
313 assert_eq!(pool.get_at(2), None);
314 assert_eq!(pool.get_at(99), None);
315
316 *pool.get_at_mut(b.index()).expect("live") = 20;
317 assert_eq!(pool.get(b), Some(&20));
318 pool.remove(a);
319 assert_eq!(pool.get_at(a.index()), None);
320 assert_eq!(pool.get_at_mut(99), None);
321 }
322
323 #[test]
324 fn a_full_pool_declines_rather_than_growing() {
325 let mut pool = Pool::with_capacity(2);
326 assert!(pool.insert(1).is_some());
327 assert!(pool.insert(2).is_some());
328 assert!(pool.insert(3).is_none());
329 assert_eq!(pool.capacity(), 2);
330 assert_eq!(pool.len(), 2);
331 }
332
333 #[test]
334 fn a_zero_capacity_pool_holds_nothing() {
335 let mut pool = Pool::with_capacity(0);
336 assert!(pool.is_full());
337 assert!(pool.insert(1).is_none());
338 assert_eq!(pool.iter().count(), 0);
339 }
340
341 #[test]
342 fn objects_can_be_mutated_in_place() {
343 let mut pool = Pool::with_capacity(2);
344 let h = pool.insert(10).expect("room");
345 *pool.get_mut(h).expect("live") += 5;
346 assert_eq!(pool.get(h), Some(&15));
347
348 for (_, value) in pool.iter_mut() {
349 *value *= 2;
350 }
351 assert_eq!(pool.get(h), Some(&30));
352 }
353
354 #[test]
355 fn iteration_visits_live_objects_only() {
356 let mut pool = Pool::with_capacity(4);
357 let a = pool.insert(1).expect("room");
358 let _b = pool.insert(2).expect("room");
359 let c = pool.insert(3).expect("room");
360 pool.remove(a);
361
362 let live: alloc::vec::Vec<i32> = pool.iter().map(|(_, v)| *v).collect();
363 assert_eq!(live, [2, 3]);
364 let (handle, _) = pool.iter().next().expect("a live object");
366 assert_eq!(pool.get(handle), Some(&2));
367 assert_eq!(pool.get(c), Some(&3));
368 }
369
370 #[test]
371 fn clear_empties_the_pool_and_stales_its_handles() {
372 let mut pool = Pool::with_capacity(3);
373 let a = pool.insert(1).expect("room");
374 let b = pool.insert(2).expect("room");
375 pool.clear();
376
377 assert!(pool.is_empty());
378 assert_eq!(pool.capacity(), 3);
379 assert_eq!(pool.get(a), None);
380 assert_eq!(pool.get(b), None);
381 assert_eq!(pool.insert(9).expect("room").index(), 0);
383 }
384
385 #[test]
388 fn handles_rebuild_from_their_parts() {
389 let mut pool = Pool::with_capacity(2);
390 let a = pool.insert("a").expect("room");
391 let rebuilt = PoolHandle::from_parts(a.index() as u32, a.generation());
392 assert_eq!(rebuilt, a);
393 assert_eq!(pool.get(rebuilt), Some(&"a"));
394
395 assert_eq!(pool.get(PoolHandle::from_parts(0, 7)), None);
396 assert_eq!(pool.get(PoolHandle::from_parts(99, 0)), None);
397 }
398
399 #[test]
400 fn a_reused_slot_reports_a_later_generation() {
401 let mut pool = Pool::with_capacity(1);
402 let first = pool.insert(1).expect("room");
403 assert_eq!(first.generation(), 0);
404 pool.remove(first);
405 let second = pool.insert(2).expect("the freed slot");
406 assert_eq!(second.index(), first.index());
407 assert_eq!(second.generation(), 1);
408 }
409
410 #[test]
413 fn reserved_bytes_counts_the_reservation_not_the_occupancy() {
414 let mut pool = Pool::<u64>::with_capacity(16);
415 let reserved = pool.reserved_bytes();
416 assert!(reserved >= 16 * size_of::<u64>() as u64);
417 pool.insert(1);
418 assert_eq!(pool.reserved_bytes(), reserved);
419 }
420
421 #[test]
423 fn occupants_are_dropped_with_the_pool() {
424 use alloc::rc::Rc;
425
426 let witness = Rc::new(());
427 {
428 let mut pool = Pool::with_capacity(2);
429 pool.insert(Rc::clone(&witness));
430 assert_eq!(Rc::strong_count(&witness), 2);
431 }
432 assert_eq!(Rc::strong_count(&witness), 1);
433 }
434
435 #[test]
437 fn a_removed_occupant_is_handed_back_intact() {
438 use alloc::rc::Rc;
439
440 let witness = Rc::new(());
441 let mut pool = Pool::with_capacity(2);
442 let h = pool.insert(Rc::clone(&witness)).expect("room");
443 let taken = pool.remove(h).expect("live");
444 assert_eq!(Rc::strong_count(&witness), 2);
445 drop(taken);
446 assert_eq!(Rc::strong_count(&witness), 1);
447 }
448}