1use dynamic_pool::DynamicPool;
2pub use dynamic_pool::{DynamicPoolItem, DynamicReset};
3use thiserror::Error;
4
5#[derive(Error, Debug)]
6pub enum SizedPoolError {
7 #[error("the given size exceeds the maximum allowed size of the pool")]
8 SizeExceedMaxSize,
9}
10
11pub trait SizedAllocatable {
12 fn new(size: usize) -> Self;
13 fn size(&self) -> usize;
14}
15
16pub struct SizedPool<T: SizedAllocatable + DynamicReset> {
17 sub_pools: Vec<DynamicPool<T>>,
19}
20
21impl<T: SizedAllocatable + DynamicReset> SizedPool<T> {
22 pub fn new(cap: usize, pool_size_power_of_two: u32, max_pool_size: usize) -> Self {
25 let mut pools = Vec::new();
26 for pool_power in 0..pool_size_power_of_two {
27 let pool =
28 DynamicPool::new(cap, max_pool_size, move || T::new(2_usize.pow(pool_power)));
29 pools.push(pool);
30 }
31 Self { sub_pools: pools }
32 }
33
34 fn get_subpool_location(&self, size: usize) -> usize {
35 (size.next_power_of_two().trailing_zeros()) as usize
36 }
37
38 fn get_subpool(&self, size: usize) -> Result<&DynamicPool<T>, SizedPoolError> {
39 self.sub_pools
40 .get(self.get_subpool_location(size))
41 .ok_or(SizedPoolError::SizeExceedMaxSize)
42 }
43
44 pub fn try_pull(&self, size: usize) -> Result<DynamicPoolItem<T>, SizedPoolError> {
45 let pool = self.get_subpool(size)?;
46 match pool.try_take() {
47 None => {
48 tracing::debug!("not enough items in pool, allocating");
49 Ok(pool.take())
50 }
51 Some(x) => Ok(x),
52 }
53 }
54}
55
56#[cfg(test)]
57mod test {
58 use super::*;
59
60 #[derive(Debug)]
61 struct TestItem {
62 size: usize,
63 }
64
65 impl SizedAllocatable for TestItem {
66 fn new(size: usize) -> Self {
67 Self { size }
68 }
69
70 fn size(&self) -> usize {
71 self.size
72 }
73 }
74
75 impl DynamicReset for TestItem {
76 fn reset(&mut self) {}
77 }
78
79 #[test]
80 fn test_allocate() {
81 let pool: SizedPool<TestItem> = SizedPool::new(0, 40, 1024);
82 let mut items = Vec::new();
83 for _ in 0..2048 {
84 items.push(pool.try_pull(10).unwrap());
85 }
86 }
87}