1#[derive(Debug, Clone, Default)]
11pub struct IdPool {
12 pub(crate) free_array: Vec<i32>,
13 pub(crate) next_index: i32,
14}
15
16impl IdPool {
17 pub fn new() -> IdPool {
19 IdPool {
20 free_array: Vec::with_capacity(32),
22 next_index: 0,
23 }
24 }
25
26 pub fn destroy(&mut self) {
28 *self = IdPool {
29 free_array: Vec::new(),
30 next_index: 0,
31 };
32 }
33
34 pub fn alloc_id(&mut self) -> i32 {
36 if let Some(id) = self.free_array.pop() {
37 return id;
38 }
39
40 let id = self.next_index;
41 self.next_index += 1;
42 id
43 }
44
45 pub fn free_id(&mut self, id: i32) {
47 debug_assert!(self.next_index > 0);
48 debug_assert!(0 <= id && id < self.next_index);
49 self.free_array.push(id);
50 }
51
52 pub fn id_count(&self) -> i32 {
54 self.next_index - self.free_array.len() as i32
55 }
56
57 pub fn id_capacity(&self) -> i32 {
59 self.next_index
60 }
61
62 pub fn id_bytes(&self) -> i32 {
64 (self.free_array.capacity() * core::mem::size_of::<i32>()) as i32
65 }
66
67 pub fn validate_free_id(&self, id: i32) {
69 if !cfg!(debug_assertions) {
71 return;
72 }
73
74 if self.free_array.contains(&id) {
75 return;
76 }
77
78 debug_assert!(false, "id {id} is not free");
79 }
80
81 pub fn validate_used_id(&self, id: i32) {
83 if !cfg!(debug_assertions) {
85 return;
86 }
87
88 debug_assert!(!self.free_array.contains(&id), "id {id} is free");
89 }
90}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
99 fn alloc_free_recycle() {
100 let mut pool = IdPool::new();
101
102 assert_eq!(pool.alloc_id(), 0);
103 assert_eq!(pool.alloc_id(), 1);
104 assert_eq!(pool.alloc_id(), 2);
105 assert_eq!(pool.id_count(), 3);
106 assert_eq!(pool.id_capacity(), 3);
107
108 pool.free_id(1);
110 pool.validate_free_id(1);
111 pool.validate_used_id(2);
112 assert_eq!(pool.id_count(), 2);
113
114 assert_eq!(pool.alloc_id(), 1);
115 assert_eq!(pool.id_count(), 3);
116
117 assert_eq!(pool.alloc_id(), 3);
119 assert_eq!(pool.id_capacity(), 4);
120
121 pool.destroy();
122 assert_eq!(pool.id_count(), 0);
123 }
124}