use std::alloc::{alloc, Layout};
use std::sync::Arc;
use crossbeam_queue::ArrayQueue;
const CACHE_LINE: usize = 64;
const BUFFER_SIZE: usize = 2048;
pub struct Buffer {
pub ptr: *mut u8,
pub capacity: usize,
pub head: usize,
pub size: usize,
pub pool: Arc<BufferPool>
}
impl Drop for Buffer {
fn drop(&mut self) {
let _ = self.pool.available.push(self.ptr);
}
}
impl Buffer {
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe {
let start_ptr = self.ptr.add(self.head + self.size);
let available_space = self.capacity - (self.head + self.size);
std::slice::from_raw_parts_mut(start_ptr, available_space)
}
}
pub fn advance(&mut self, n: usize) {
self.size += n;
}
pub fn data(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(self.ptr.add(self.head), self.size)
}
}
pub fn data_mut(&mut self) -> &mut [u8] {
unsafe {
std::slice::from_raw_parts_mut(self.ptr.add(self.head), self.size)
}
}
pub fn prepend(&mut self, header: &[u8]) {
let len = header.len();
if len <= self.head {
self.head -= len;
self.size += len;
unsafe {
let start = self.ptr.add(self.head);
std::ptr::copy_nonoverlapping(header.as_ptr(), start, len);
}
}
}
}
pub struct BufferPool {
pub storage: *mut u8,
pub capacity: usize,
pub available: ArrayQueue<*mut u8>
}
impl BufferPool {
pub fn new(num_buffers: usize) -> Arc<Self> {
let total_size = num_buffers * BUFFER_SIZE;
let layout = Layout::from_size_align(total_size, CACHE_LINE).expect("Falha ao definir layout da pool na memória.");
let storage = unsafe { alloc(layout) };
let available = ArrayQueue::new(num_buffers);
for i in 0..num_buffers {
unsafe {
let buffer_ptr = storage.add(i * BUFFER_SIZE);
let _ = available.push(buffer_ptr);
}
}
Arc::new(Self {
storage,
capacity: num_buffers,
available
})
}
pub fn acquire(self: &Arc<Self>) -> Option<Buffer> {
self.available.pop().map(|ptr| Buffer {
ptr,
capacity: BUFFER_SIZE,
head: 128,
size: 0,
pool: Arc::clone(self)
})
}
}