pub const DEFAULT_BUF_SIZE: usize = 4096;
pub const DEFAULT_POOL_SIZE: usize = 1024;
pub struct BufferPool {
slots: Box<[Box<[u8; DEFAULT_BUF_SIZE]>]>,
free: Vec<u32>,
buf_size: usize,
}
impl BufferPool {
#[must_use]
pub fn new(capacity: usize, buf_size: usize) -> Option<Self> {
if buf_size != DEFAULT_BUF_SIZE {
return None; }
let mut slots = Vec::with_capacity(capacity);
let mut free = Vec::with_capacity(capacity);
for i in 0..capacity {
slots.push(vec![0u8; buf_size].into_boxed_slice().try_into().ok()?);
free.push(i as u32);
}
Some(Self {
slots: slots.into_boxed_slice(),
free,
buf_size,
})
}
#[must_use]
#[inline]
pub fn buf_size(&self) -> usize {
self.buf_size
}
#[must_use]
#[inline]
pub fn capacity(&self) -> usize {
self.slots.len()
}
#[must_use]
#[inline]
pub fn free_slots(&self) -> usize {
self.free.len()
}
#[inline]
pub fn take(&mut self) -> Option<u32> {
self.free.pop()
}
#[inline]
pub fn release(&mut self, slot: u32) {
debug_assert!((slot as usize) < self.slots.len(), "slot out of range");
self.free.push(slot);
}
#[must_use]
#[inline]
pub fn slot(&self, slot: u32) -> &[u8; DEFAULT_BUF_SIZE] {
&self.slots[slot as usize]
}
#[inline]
pub fn slot_mut(&mut self, slot: u32) -> &mut [u8; DEFAULT_BUF_SIZE] {
&mut self.slots[slot as usize]
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn take_release() {
let mut pool = BufferPool::new(4, DEFAULT_BUF_SIZE).expect("default size");
assert_eq!(pool.free_slots(), 4);
let a = pool.take().expect("slot");
let b = pool.take().expect("slot");
assert_eq!(pool.free_slots(), 2);
pool.release(a);
assert_eq!(pool.free_slots(), 3);
let _c = pool.take();
let d = pool.take();
assert!(d.is_some());
pool.release(b); }
#[test]
fn exhaustion() {
let mut pool = BufferPool::new(2, DEFAULT_BUF_SIZE).expect("default size");
let _ = pool.take();
let _ = pool.take();
assert!(pool.take().is_none(), "pool exhausted");
}
}