use crate::error::{Result, SaferRingError};
use std::collections::VecDeque;
#[derive(Debug)]
pub struct BufferGroup {
pub group_id: u16,
pub buffer_count: u32,
pub buffer_size: u32,
#[cfg(target_os = "linux")]
#[allow(dead_code)] buffers: Vec<Box<[u8]>>,
available_buffers: VecDeque<u16>,
}
impl BufferGroup {
pub fn new(group_id: u16, buffer_count: u32, buffer_size: u32) -> Result<Self> {
if buffer_count == 0 {
return Err(SaferRingError::Io(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Buffer count must be greater than 0",
)));
}
if buffer_size == 0 {
return Err(SaferRingError::Io(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Buffer size must be greater than 0",
)));
}
#[cfg(target_os = "linux")]
let buffers = {
let mut buffers = Vec::with_capacity(buffer_count as usize);
for _ in 0..buffer_count {
buffers.push(vec![0u8; buffer_size as usize].into_boxed_slice());
}
buffers
};
let available_buffers = (0..buffer_count as u16).collect();
Ok(Self {
group_id,
buffer_count,
buffer_size,
#[cfg(target_os = "linux")]
buffers,
available_buffers,
})
}
#[inline]
pub fn get_buffer(&mut self) -> Option<u16> {
self.available_buffers.pop_front()
}
#[inline]
pub fn return_buffer(&mut self, buffer_id: u16) {
debug_assert!(
buffer_id < self.buffer_count as u16,
"Invalid buffer ID: {} >= {}",
buffer_id,
self.buffer_count
);
if buffer_id < self.buffer_count as u16 {
self.available_buffers.push_back(buffer_id);
}
}
#[inline]
pub fn available_count(&self) -> usize {
self.available_buffers.len()
}
#[inline]
pub fn has_available(&self) -> bool {
!self.available_buffers.is_empty()
}
#[inline]
pub fn utilization(&self) -> f64 {
let in_use = self.buffer_count as usize - self.available_buffers.len();
in_use as f64 / self.buffer_count as f64
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_group_creation() {
let group = BufferGroup::new(1, 10, 4096).unwrap();
assert_eq!(group.group_id, 1);
assert_eq!(group.buffer_count, 10);
assert_eq!(group.buffer_size, 4096);
assert_eq!(group.available_count(), 10);
assert!(group.has_available());
assert_eq!(group.utilization(), 0.0);
}
#[test]
fn test_buffer_allocation() {
let mut group = BufferGroup::new(1, 5, 1024).unwrap();
let mut buffer_ids = Vec::new();
for _ in 0..5 {
let id = group.get_buffer().unwrap();
buffer_ids.push(id);
}
assert_eq!(group.available_count(), 0);
assert!(!group.has_available());
assert_eq!(group.utilization(), 1.0);
assert!(group.get_buffer().is_none());
for id in buffer_ids {
group.return_buffer(id);
}
assert_eq!(group.available_count(), 5);
assert!(group.has_available());
assert_eq!(group.utilization(), 0.0);
}
#[test]
fn test_invalid_parameters() {
assert!(BufferGroup::new(1, 0, 4096).is_err());
assert!(BufferGroup::new(1, 10, 0).is_err());
}
}