#![allow(dead_code)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BufferDesc {
pub size_bytes: usize,
pub alignment: usize,
pub pool_id: u32,
}
impl BufferDesc {
#[must_use]
pub fn new(size_bytes: usize, alignment: usize, pool_id: u32) -> Self {
Self {
size_bytes,
alignment,
pool_id,
}
}
#[must_use]
pub fn is_page_aligned(&self) -> bool {
self.alignment == 4096
}
#[must_use]
pub fn slots_needed(&self, slot_size: usize) -> usize {
assert!(slot_size > 0, "slot_size must be non-zero");
self.size_bytes.div_ceil(slot_size)
}
}
#[derive(Debug)]
pub struct PooledBuffer {
pub id: u64,
pub data: Vec<u8>,
pub desc: BufferDesc,
pub in_use: bool,
}
impl PooledBuffer {
#[must_use]
pub fn new(id: u64, desc: BufferDesc) -> Self {
let data = vec![0u8; desc.size_bytes];
Self {
id,
data,
desc,
in_use: false,
}
}
pub fn reset(&mut self) {
self.data.fill(0);
self.in_use = false;
}
#[must_use]
pub fn available_size(&self) -> usize {
self.data.len()
}
}
#[derive(Debug)]
pub struct BufferPool {
pub buffers: Vec<PooledBuffer>,
pub next_id: u64,
}
impl BufferPool {
#[must_use]
pub fn new(count: usize, buf_size: usize) -> Self {
let mut buffers = Vec::with_capacity(count);
for id in 0..count as u64 {
let desc = BufferDesc::new(buf_size, 64, 0);
buffers.push(PooledBuffer::new(id, desc));
}
Self {
buffers,
next_id: count as u64,
}
}
#[must_use]
pub fn acquire(&mut self) -> Option<u64> {
for buf in &mut self.buffers {
if !buf.in_use {
buf.in_use = true;
return Some(buf.id);
}
}
None
}
pub fn release(&mut self, id: u64) {
if let Some(buf) = self.buffers.iter_mut().find(|b| b.id == id) {
buf.reset();
}
}
#[must_use]
pub fn available_count(&self) -> usize {
self.buffers.iter().filter(|b| !b.in_use).count()
}
#[must_use]
pub fn total_count(&self) -> usize {
self.buffers.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_desc_new() {
let desc = BufferDesc::new(1024, 64, 1);
assert_eq!(desc.size_bytes, 1024);
assert_eq!(desc.alignment, 64);
assert_eq!(desc.pool_id, 1);
}
#[test]
fn test_buffer_desc_is_page_aligned_true() {
let desc = BufferDesc::new(8192, 4096, 0);
assert!(desc.is_page_aligned());
}
#[test]
fn test_buffer_desc_is_page_aligned_false() {
let desc = BufferDesc::new(8192, 64, 0);
assert!(!desc.is_page_aligned());
}
#[test]
fn test_buffer_desc_slots_needed_exact() {
let desc = BufferDesc::new(1024, 64, 0);
assert_eq!(desc.slots_needed(512), 2);
}
#[test]
fn test_buffer_desc_slots_needed_round_up() {
let desc = BufferDesc::new(1025, 64, 0);
assert_eq!(desc.slots_needed(512), 3);
}
#[test]
fn test_buffer_desc_slots_needed_single_slot() {
let desc = BufferDesc::new(100, 64, 0);
assert_eq!(desc.slots_needed(200), 1);
}
#[test]
fn test_pooled_buffer_initial_state() {
let desc = BufferDesc::new(256, 64, 0);
let buf = PooledBuffer::new(42, desc);
assert_eq!(buf.id, 42);
assert!(!buf.in_use);
assert_eq!(buf.available_size(), 256);
assert!(buf.data.iter().all(|&b| b == 0));
}
#[test]
fn test_pooled_buffer_reset() {
let desc = BufferDesc::new(4, 64, 0);
let mut buf = PooledBuffer::new(1, desc);
buf.in_use = true;
buf.data[0] = 0xFF;
buf.reset();
assert!(!buf.in_use);
assert!(buf.data.iter().all(|&b| b == 0));
}
#[test]
fn test_pooled_buffer_available_size() {
let desc = BufferDesc::new(512, 64, 0);
let buf = PooledBuffer::new(0, desc);
assert_eq!(buf.available_size(), 512);
}
#[test]
fn test_pool_new() {
let pool = BufferPool::new(4, 1024);
assert_eq!(pool.total_count(), 4);
assert_eq!(pool.available_count(), 4);
}
#[test]
fn test_pool_acquire_returns_id() {
let mut pool = BufferPool::new(2, 256);
let id = pool.acquire();
assert!(id.is_some());
}
#[test]
fn test_pool_acquire_exhausts_buffers() {
let mut pool = BufferPool::new(2, 256);
let _id1 = pool.acquire().expect("acquire should succeed");
let _id2 = pool.acquire().expect("acquire should succeed");
assert!(pool.acquire().is_none());
}
#[test]
fn test_pool_available_count_decrements_on_acquire() {
let mut pool = BufferPool::new(3, 64);
assert_eq!(pool.available_count(), 3);
let _ = pool.acquire();
assert_eq!(pool.available_count(), 2);
let _ = pool.acquire();
assert_eq!(pool.available_count(), 1);
}
#[test]
fn test_pool_release_makes_buffer_available() {
let mut pool = BufferPool::new(1, 64);
let id = pool.acquire().expect("acquire should succeed");
assert_eq!(pool.available_count(), 0);
pool.release(id);
assert_eq!(pool.available_count(), 1);
}
#[test]
fn test_pool_release_unknown_id_is_noop() {
let mut pool = BufferPool::new(2, 64);
let before = pool.available_count();
pool.release(999);
assert_eq!(pool.available_count(), before);
}
#[test]
fn test_pool_total_count_unchanged_after_ops() {
let mut pool = BufferPool::new(5, 128);
let ids: Vec<u64> = (0..5).filter_map(|_| pool.acquire()).collect();
assert_eq!(pool.total_count(), 5);
for id in ids {
pool.release(id);
}
assert_eq!(pool.total_count(), 5);
}
}