1#![allow(dead_code)]
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
9#[allow(dead_code)]
10pub struct Id(pub u64);
11
12#[derive(Debug)]
14#[allow(dead_code)]
15pub struct IdPool {
16 next: u64,
17 recycled: Vec<u64>,
18 active: std::collections::HashSet<u64>,
19}
20
21#[allow(dead_code)]
23pub fn new_id_pool(start: u64) -> IdPool {
24 IdPool {
25 next: start,
26 recycled: Vec::new(),
27 active: std::collections::HashSet::new(),
28 }
29}
30
31#[allow(dead_code)]
33pub fn id_alloc(pool: &mut IdPool) -> Id {
34 if let Some(id) = pool.recycled.pop() {
35 pool.active.insert(id);
36 Id(id)
37 } else {
38 let id = pool.next;
39 pool.next += 1;
40 pool.active.insert(id);
41 Id(id)
42 }
43}
44
45#[allow(dead_code)]
47pub fn id_release(pool: &mut IdPool, id: Id) -> bool {
48 if pool.active.remove(&id.0) {
49 pool.recycled.push(id.0);
50 true
51 } else {
52 false
53 }
54}
55
56#[allow(dead_code)]
58pub fn id_is_active(pool: &IdPool, id: Id) -> bool {
59 pool.active.contains(&id.0)
60}
61
62#[allow(dead_code)]
64pub fn id_active_count(pool: &IdPool) -> usize {
65 pool.active.len()
66}
67
68#[allow(dead_code)]
70pub fn id_recycled_count(pool: &IdPool) -> usize {
71 pool.recycled.len()
72}
73
74#[allow(dead_code)]
76pub fn id_peek_next(pool: &IdPool) -> u64 {
77 pool.next
78}
79
80#[allow(dead_code)]
82pub fn id_release_all(pool: &mut IdPool) {
83 let ids: Vec<u64> = pool.active.drain().collect();
84 pool.recycled.extend(ids);
85}
86
87#[allow(dead_code)]
89pub fn id_total(pool: &IdPool) -> usize {
90 pool.active.len() + pool.recycled.len()
91}
92
93#[cfg(test)]
94mod tests {
95 use super::*;
96
97 #[test]
98 fn test_alloc_sequential() {
99 let mut pool = new_id_pool(1);
100 let a = id_alloc(&mut pool);
101 let b = id_alloc(&mut pool);
102 assert_eq!(a.0, 1);
103 assert_eq!(b.0, 2);
104 }
105
106 #[test]
107 fn test_release_and_reuse() {
108 let mut pool = new_id_pool(0);
109 let a = id_alloc(&mut pool);
110 id_release(&mut pool, a);
111 let b = id_alloc(&mut pool);
112 assert_eq!(b.0, a.0);
113 }
114
115 #[test]
116 fn test_is_active() {
117 let mut pool = new_id_pool(0);
118 let id = id_alloc(&mut pool);
119 assert!(id_is_active(&pool, id));
120 id_release(&mut pool, id);
121 assert!(!id_is_active(&pool, id));
122 }
123
124 #[test]
125 fn test_double_release() {
126 let mut pool = new_id_pool(0);
127 let id = id_alloc(&mut pool);
128 assert!(id_release(&mut pool, id));
129 assert!(!id_release(&mut pool, id));
130 }
131
132 #[test]
133 fn test_active_count() {
134 let mut pool = new_id_pool(0);
135 id_alloc(&mut pool);
136 id_alloc(&mut pool);
137 assert_eq!(id_active_count(&pool), 2);
138 }
139
140 #[test]
141 fn test_recycled_count() {
142 let mut pool = new_id_pool(0);
143 let id = id_alloc(&mut pool);
144 id_release(&mut pool, id);
145 assert_eq!(id_recycled_count(&pool), 1);
146 }
147
148 #[test]
149 fn test_release_all() {
150 let mut pool = new_id_pool(0);
151 id_alloc(&mut pool);
152 id_alloc(&mut pool);
153 id_release_all(&mut pool);
154 assert_eq!(id_active_count(&pool), 0);
155 assert_eq!(id_recycled_count(&pool), 2);
156 }
157
158 #[test]
159 fn test_peek_next() {
160 let pool = new_id_pool(10);
161 assert_eq!(id_peek_next(&pool), 10);
162 }
163
164 #[test]
165 fn test_total() {
166 let mut pool = new_id_pool(0);
167 id_alloc(&mut pool);
168 let b = id_alloc(&mut pool);
169 id_release(&mut pool, b);
170 assert_eq!(id_total(&pool), 2);
171 }
172}