use std::sync::{Arc, Mutex};
const MAX_POOLED_BUFFER_SIZE: usize = 4096;
const DEFAULT_BUFFER_CAPACITY: usize = 1024;
pub struct PooledBuffer {
buffer: Vec<u8>,
pool: Arc<Mutex<Vec<Vec<u8>>>>,
}
impl PooledBuffer {
#[allow(clippy::should_implement_trait)]
pub fn as_mut(&mut self) -> &mut Vec<u8> {
&mut self.buffer
}
#[allow(clippy::should_implement_trait)]
pub fn as_ref(&self) -> &[u8] {
&self.buffer
}
pub fn into_inner(mut self) -> Vec<u8> {
self.buffer.clear();
std::mem::take(&mut self.buffer)
}
}
impl Drop for PooledBuffer {
fn drop(&mut self) {
if self.buffer.capacity() <= MAX_POOLED_BUFFER_SIZE {
self.buffer.clear(); if let Ok(mut pool) = self.pool.lock() {
pool.push(std::mem::take(&mut self.buffer));
}
}
}
}
impl std::ops::Deref for PooledBuffer {
type Target = Vec<u8>;
fn deref(&self) -> &Self::Target {
&self.buffer
}
}
impl std::ops::DerefMut for PooledBuffer {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.buffer
}
}
pub struct BufferPool {
pool: Arc<Mutex<Vec<Vec<u8>>>>,
initial_capacity: usize,
}
impl BufferPool {
pub fn new(pool_size: usize) -> Self {
let mut pool = Vec::with_capacity(pool_size);
for _ in 0..pool_size {
pool.push(Vec::with_capacity(DEFAULT_BUFFER_CAPACITY));
}
Self {
pool: Arc::new(Mutex::new(pool)),
initial_capacity: DEFAULT_BUFFER_CAPACITY,
}
}
pub fn acquire(&self) -> PooledBuffer {
let buffer = if let Ok(mut pool) = self.pool.lock() {
pool.pop()
.unwrap_or_else(|| Vec::with_capacity(self.initial_capacity))
} else {
Vec::with_capacity(self.initial_capacity)
};
PooledBuffer {
buffer,
pool: self.pool.clone(),
}
}
pub fn available(&self) -> usize {
self.pool.lock().map(|p| p.len()).unwrap_or(0)
}
}
impl Default for BufferPool {
fn default() -> Self {
Self::new(50) }
}
impl Clone for BufferPool {
fn clone(&self) -> Self {
Self {
pool: self.pool.clone(),
initial_capacity: self.initial_capacity,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_buffer_pool_basic() {
let pool = BufferPool::new(10);
assert_eq!(pool.available(), 10);
let mut buf = pool.acquire();
assert_eq!(pool.available(), 9);
buf.push(42);
assert_eq!(buf[0], 42);
drop(buf);
assert_eq!(pool.available(), 10);
}
#[test]
fn test_buffer_pool_reuse() {
let pool = BufferPool::new(1);
{
let mut buf1 = pool.acquire();
buf1.extend_from_slice(b"test");
assert_eq!(buf1.len(), 4);
}
let buf2 = pool.acquire();
assert_eq!(buf2.len(), 0);
assert!(buf2.capacity() >= 4);
}
#[test]
fn test_buffer_pool_empty() {
let pool = BufferPool::new(1);
let _buf1 = pool.acquire();
let _buf2 = pool.acquire();
assert_eq!(pool.available(), 0);
}
#[test]
fn test_buffer_size_limit() {
let pool = BufferPool::new(1);
{
let mut buf = pool.acquire();
buf.reserve(MAX_POOLED_BUFFER_SIZE + 1);
buf.extend_from_slice(&vec![0u8; MAX_POOLED_BUFFER_SIZE + 1]);
}
assert_eq!(pool.available(), 0);
}
}