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