oxihuman_core/
resource_pool.rs1#![allow(dead_code)]
4
5#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum ResourceState {
10 Available,
11 InUse,
12}
13
14#[derive(Debug)]
16pub struct ResourceSlot<T> {
17 pub resource: T,
18 pub state: ResourceState,
19 pub borrow_count: u32,
20}
21
22pub struct ResourcePool<T> {
24 slots: Vec<ResourceSlot<T>>,
25}
26
27#[allow(dead_code)]
28impl<T: Clone> ResourcePool<T> {
29 pub fn new(resources: Vec<T>) -> Self {
30 let slots = resources
31 .into_iter()
32 .map(|r| ResourceSlot {
33 resource: r,
34 state: ResourceState::Available,
35 borrow_count: 0,
36 })
37 .collect();
38 ResourcePool { slots }
39 }
40
41 pub fn acquire(&mut self) -> Option<usize> {
42 self.slots.iter_mut().enumerate().find_map(|(i, s)| {
43 if s.state == ResourceState::Available {
44 s.state = ResourceState::InUse;
45 s.borrow_count += 1;
46 Some(i)
47 } else {
48 None
49 }
50 })
51 }
52
53 pub fn release(&mut self, index: usize) -> bool {
54 if index >= self.slots.len() {
55 return false;
56 }
57 if self.slots[index].state == ResourceState::InUse {
58 self.slots[index].state = ResourceState::Available;
59 true
60 } else {
61 false
62 }
63 }
64
65 pub fn get(&self, index: usize) -> Option<&T> {
66 self.slots.get(index).map(|s| &s.resource)
67 }
68
69 pub fn get_mut(&mut self, index: usize) -> Option<&mut T> {
70 self.slots.get_mut(index).map(|s| &mut s.resource)
71 }
72
73 pub fn is_in_use(&self, index: usize) -> bool {
74 self.slots
75 .get(index)
76 .is_some_and(|s| s.state == ResourceState::InUse)
77 }
78
79 pub fn available_count(&self) -> usize {
80 self.slots
81 .iter()
82 .filter(|s| s.state == ResourceState::Available)
83 .count()
84 }
85
86 pub fn in_use_count(&self) -> usize {
87 self.slots
88 .iter()
89 .filter(|s| s.state == ResourceState::InUse)
90 .count()
91 }
92
93 pub fn total_count(&self) -> usize {
94 self.slots.len()
95 }
96
97 pub fn borrow_count(&self, index: usize) -> u32 {
98 self.slots.get(index).map(|s| s.borrow_count).unwrap_or(0)
99 }
100
101 pub fn release_all(&mut self) {
102 for s in &mut self.slots {
103 s.state = ResourceState::Available;
104 }
105 }
106
107 pub fn total_borrows(&self) -> u64 {
108 self.slots.iter().map(|s| s.borrow_count as u64).sum()
109 }
110}
111
112pub fn new_resource_pool<T: Clone>(resources: Vec<T>) -> ResourcePool<T> {
113 ResourcePool::new(resources)
114}
115
116#[cfg(test)]
117mod tests {
118 use super::*;
119
120 #[test]
121 fn acquire_available() {
122 let mut pool = new_resource_pool(vec![10i32, 20, 30]);
123 let idx = pool.acquire().expect("should succeed");
124 assert!(pool.is_in_use(idx));
125 }
126
127 #[test]
128 fn release_makes_available() {
129 let mut pool = new_resource_pool(vec![1i32]);
130 let idx = pool.acquire().expect("should succeed");
131 assert!(pool.release(idx));
132 assert!(!pool.is_in_use(idx));
133 }
134
135 #[test]
136 fn acquire_all_then_none() {
137 let mut pool = new_resource_pool(vec![1i32, 2]);
138 pool.acquire().expect("should succeed");
139 pool.acquire().expect("should succeed");
140 assert!(pool.acquire().is_none());
141 }
142
143 #[test]
144 fn available_count() {
145 let mut pool = new_resource_pool(vec![1i32, 2, 3]);
146 pool.acquire();
147 assert_eq!(pool.available_count(), 2);
148 assert_eq!(pool.in_use_count(), 1);
149 }
150
151 #[test]
152 fn get_resource() {
153 let pool = new_resource_pool(vec![42i32]);
154 assert_eq!(*pool.get(0).expect("should succeed"), 42);
155 }
156
157 #[test]
158 fn borrow_count_tracking() {
159 let mut pool = new_resource_pool(vec![1i32]);
160 pool.acquire();
161 pool.release(0);
162 pool.acquire();
163 assert_eq!(pool.borrow_count(0), 2);
164 }
165
166 #[test]
167 fn release_all() {
168 let mut pool = new_resource_pool(vec![1i32, 2, 3]);
169 pool.acquire();
170 pool.acquire();
171 pool.release_all();
172 assert_eq!(pool.available_count(), 3);
173 }
174
175 #[test]
176 fn total_borrows() {
177 let mut pool = new_resource_pool(vec![1i32, 2]);
178 pool.acquire();
179 pool.release(0);
180 pool.acquire();
181 pool.acquire();
182 assert_eq!(pool.total_borrows(), 3);
183 }
184
185 #[test]
186 fn out_of_bounds_release() {
187 let mut pool = new_resource_pool(vec![1i32]);
188 assert!(!pool.release(99));
189 }
190}