1use std::collections::VecDeque;
3
4use nanoservices_utils::errors::{NanoServiceError, NanoServiceErrorStatus};
5
6#[derive(Debug)]
13pub struct Allocator<T: Clone> {
14 pub connection_pool: Vec<Option<T>>,
15 pub free_connections: VecDeque<usize>,
16 pub allocated_connections: VecDeque<usize>,
17}
18
19impl<T: Clone> Default for Allocator<T> {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl<T: Clone> Allocator<T> {
26 pub fn new() -> Self {
31 Self {
32 connection_pool: Vec::new(),
33 free_connections: VecDeque::new(),
34 allocated_connections: VecDeque::new(),
35 }
36 }
37
38 pub fn allocate(&mut self, connection: T) -> usize {
46 if let Some(index) = self.free_connections.pop_front() {
47 self.connection_pool[index] = Some(connection);
48 self.allocated_connections.push_back(index);
49 index
50 } else {
51 self.connection_pool.push(Some(connection));
52 self.allocated_connections.push_back(self.connection_pool.len() - 1);
53 self.connection_pool.len() - 1
54 }
55 }
56
57 pub fn yield_next_allocated_index(&mut self) -> Option<usize> {
62 #[allow(unused_assignments)]
65 let mut index: Option<usize> = None;
66
67 loop {
68 index = self.allocated_connections.pop_front();
69 if index.is_none() {
70 break;
71 }
72 let i = index.unwrap();
73 let connection = self.connection_pool[i].as_ref();
74 match connection {
75 Some(_) => {
76 self.allocated_connections.push_back(i);
77 break;
78 }
79 None => continue,
80 }
81 }
82 index
83 }
84
85 pub fn extract_connection(&self, index: usize) -> Result<(T, usize), NanoServiceError> {
93 if index + 1 > self.connection_pool.len() {
94 return Err(NanoServiceError::new(
95 format!("Connection at index {index} is unavailable"),
96 NanoServiceErrorStatus::Unknown,
97 ));
98 }
99 let connection = self.connection_pool[index].as_ref();
100 match connection {
101 Some(c) => Ok((c.clone(), index)),
102 None => Err(NanoServiceError::new(
103 format!("Connection at index {index} is deallocated"),
104 NanoServiceErrorStatus::Unknown,
105 )),
106 }
107 }
108
109 pub fn deallocate(&mut self, index: usize) -> Result<T, NanoServiceError> {
114 if index + 1 > self.connection_pool.len() {
115 return Err(NanoServiceError::new(
116 format!("Connection at index {index} is unavailable"),
117 NanoServiceErrorStatus::Unknown,
118 ));
119 }
120 let placeholder = self.connection_pool[index].take();
121 if placeholder.is_none() {
122 return Err(NanoServiceError::new(
123 format!("Connection at index {index} is already deallocated"),
124 NanoServiceErrorStatus::Unknown,
125 ));
126 }
127 self.free_connections.push_back(index);
128 Ok(placeholder.unwrap())
129 }
130
131 pub fn yield_connections(&self) -> Vec<T> {
136 let mut connections = Vec::new();
137 for i in &self.allocated_connections {
138 let connection = self.connection_pool[*i].as_ref();
139 match connection {
140 Some(c) => connections.push(c.clone()),
141 None => continue,
142 }
143 }
144 connections
145 }
146}
147
148#[cfg(test)]
149mod tests {
150
151 use super::*;
152
153 #[test]
154 fn test_new() {
155 let allocator = Allocator::<usize>::new();
156 assert_eq!(allocator.connection_pool.len(), 0);
157 assert_eq!(allocator.free_connections.len(), 0);
158 assert_eq!(allocator.allocated_connections.len(), 0);
159 }
160
161 #[test]
162 fn test_allocate() {
163 let mut allocator = Allocator::<usize>::new();
164 let index = allocator.allocate(5);
165 assert_eq!(index, 0);
166 assert_eq!(allocator.connection_pool[index], Some(5));
167 assert_eq!(allocator.allocated_connections.len(), 1);
168 assert_eq!(allocator.free_connections.len(), 0);
169 assert_eq!(allocator.connection_pool.len(), 1);
170
171 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
173 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
174 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
175
176 let index = allocator.allocate(6);
177 assert_eq!(index, 1);
178 assert_eq!(allocator.connection_pool[index], Some(6));
179 assert_eq!(allocator.allocated_connections.len(), 2);
180 assert_eq!(allocator.free_connections.len(), 0);
181
182 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
184 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
185 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
186 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
187 }
188
189 #[test]
190 fn test_deallocate() {
191 let mut allocator = Allocator::<usize>::new();
192 let index = allocator.allocate(5);
193 let index_two = allocator.allocate(6);
194
195 assert_eq!(index, 0);
196 assert_eq!(index_two, 1);
197 assert_eq!(allocator.connection_pool[index_two], Some(6));
198 assert_eq!(allocator.allocated_connections.len(), 2);
199 assert_eq!(allocator.free_connections.len(), 0);
200
201 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
203 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
204 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
205 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
206
207 assert_eq!(Ok(5), allocator.deallocate(0));
208 assert_eq!(allocator.connection_pool[0], None);
209 assert_eq!(allocator.allocated_connections.len(), 2);
210 assert_eq!(allocator.free_connections.len(), 1);
211 assert_eq!(allocator.free_connections[0], 0);
212
213 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
215 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
216 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
217 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
218 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
219
220 let index = allocator.allocate(7);
222 assert_eq!(index, 0);
223 assert_eq!(allocator.connection_pool[index], Some(7));
224
225 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
227 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
228 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
229 assert_eq!(allocator.yield_next_allocated_index(), Some(0));
230 assert_eq!(allocator.yield_next_allocated_index(), Some(1));
231
232 let result = allocator.deallocate(20);
234 assert!(result.is_err());
235 if let Err(e) = result {
236 assert_eq!(e.message, "Connection at index 20 is unavailable");
237 }
238 }
239
240 #[test]
241 fn test_double_deallocate() {
242 let mut allocator = Allocator::<usize>::new();
243 let _ = allocator.allocate(5);
244 let _ = allocator.allocate(6);
245
246 assert_eq!(Ok(5), allocator.deallocate(0));
247 assert_eq!(Ok(6), allocator.deallocate(1));
248
249 assert_eq!(allocator.connection_pool[0], None);
250 assert_eq!(allocator.connection_pool[1], None);
251 assert_eq!(allocator.allocated_connections.len(), 2);
252 assert_eq!(allocator.free_connections.len(), 2);
253 assert_eq!(allocator.free_connections[0], 0);
254 assert_eq!(allocator.free_connections[1], 1);
255
256 let result = allocator.deallocate(0);
258 assert!(result.is_err());
259 if let Err(e) = result {
260 assert_eq!(e.message, "Connection at index 0 is already deallocated");
261 }
262 }
263
264 #[test]
265 fn test_extract_connection() {
266 let mut allocator = Allocator::<usize>::new();
267
268 let outcome = allocator.extract_connection(20);
269 assert!(outcome.is_err());
270 if let Err(e) = outcome {
271 assert_eq!(e.message, "Connection at index 20 is unavailable");
272 }
273
274 let index = allocator.allocate(5);
275 let connection = allocator.extract_connection(index);
276 let result = connection.unwrap();
277 assert_eq!(result.0, 5);
278 assert_eq!(result.1, 0);
279
280 let _ = allocator.deallocate(index);
281 let outcome = allocator.extract_connection(index);
282 assert!(outcome.is_err());
283 if let Err(e) = outcome {
284 assert_eq!(e.message, "Connection at index 0 is deallocated");
285 }
286 }
287
288 #[test]
289 fn test_yield_connections() {
290 let mut allocator = Allocator::<usize>::new();
291 let _ = allocator.allocate(5);
292 let _ = allocator.allocate(6);
293
294 let connections = allocator.yield_connections();
295 assert_eq!(connections.len(), 2);
296 assert_eq!(connections[0], 5);
297 assert_eq!(connections[1], 6);
298
299 let _ = allocator.deallocate(0);
300 let connections = allocator.yield_connections();
301 assert_eq!(connections.len(), 1);
302 assert_eq!(connections[0], 6);
303 }
304}