safer_ring/advanced/
buffer_group.rs1use crate::error::{Result, SaferRingError};
4use std::collections::VecDeque;
5
6#[derive(Debug)]
11pub struct BufferGroup {
12 pub group_id: u16,
14 pub buffer_count: u32,
16 pub buffer_size: u32,
18 #[cfg(target_os = "linux")]
20 #[allow(dead_code)] buffers: Vec<Box<[u8]>>,
22 available_buffers: VecDeque<u16>,
24}
25
26impl BufferGroup {
27 pub fn new(group_id: u16, buffer_count: u32, buffer_size: u32) -> Result<Self> {
48 if buffer_count == 0 {
49 return Err(SaferRingError::Io(std::io::Error::new(
50 std::io::ErrorKind::InvalidInput,
51 "Buffer count must be greater than 0",
52 )));
53 }
54
55 if buffer_size == 0 {
56 return Err(SaferRingError::Io(std::io::Error::new(
57 std::io::ErrorKind::InvalidInput,
58 "Buffer size must be greater than 0",
59 )));
60 }
61
62 #[cfg(target_os = "linux")]
64 let buffers = {
65 let mut buffers = Vec::with_capacity(buffer_count as usize);
66 for _ in 0..buffer_count {
67 buffers.push(vec![0u8; buffer_size as usize].into_boxed_slice());
69 }
70 buffers
71 };
72
73 let available_buffers = (0..buffer_count as u16).collect();
75
76 Ok(Self {
77 group_id,
78 buffer_count,
79 buffer_size,
80 #[cfg(target_os = "linux")]
81 buffers,
82 available_buffers,
83 })
84 }
85
86 #[inline]
90 pub fn get_buffer(&mut self) -> Option<u16> {
91 self.available_buffers.pop_front()
92 }
93
94 #[inline]
104 pub fn return_buffer(&mut self, buffer_id: u16) {
105 debug_assert!(
106 buffer_id < self.buffer_count as u16,
107 "Invalid buffer ID: {} >= {}",
108 buffer_id,
109 self.buffer_count
110 );
111
112 if buffer_id < self.buffer_count as u16 {
114 self.available_buffers.push_back(buffer_id);
115 }
116 }
117
118 #[inline]
120 pub fn available_count(&self) -> usize {
121 self.available_buffers.len()
122 }
123
124 #[inline]
126 pub fn has_available(&self) -> bool {
127 !self.available_buffers.is_empty()
128 }
129
130 #[inline]
134 pub fn utilization(&self) -> f64 {
135 let in_use = self.buffer_count as usize - self.available_buffers.len();
136 in_use as f64 / self.buffer_count as f64
137 }
138}
139
140#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn test_buffer_group_creation() {
146 let group = BufferGroup::new(1, 10, 4096).unwrap();
147
148 assert_eq!(group.group_id, 1);
149 assert_eq!(group.buffer_count, 10);
150 assert_eq!(group.buffer_size, 4096);
151 assert_eq!(group.available_count(), 10);
152 assert!(group.has_available());
153 assert_eq!(group.utilization(), 0.0);
154 }
155
156 #[test]
157 fn test_buffer_allocation() {
158 let mut group = BufferGroup::new(1, 5, 1024).unwrap();
159
160 let mut buffer_ids = Vec::new();
162 for _ in 0..5 {
163 let id = group.get_buffer().unwrap();
164 buffer_ids.push(id);
165 }
166
167 assert_eq!(group.available_count(), 0);
168 assert!(!group.has_available());
169 assert_eq!(group.utilization(), 1.0);
170 assert!(group.get_buffer().is_none());
171
172 for id in buffer_ids {
174 group.return_buffer(id);
175 }
176
177 assert_eq!(group.available_count(), 5);
178 assert!(group.has_available());
179 assert_eq!(group.utilization(), 0.0);
180 }
181
182 #[test]
183 fn test_invalid_parameters() {
184 assert!(BufferGroup::new(1, 0, 4096).is_err());
185 assert!(BufferGroup::new(1, 10, 0).is_err());
186 }
187}