use std::collections::VecDeque;
use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::{self};
use std::sync::Mutex;
use bytes::BytesMut;
pub struct PooledBuf {
pool: Mutex<VecDeque<BytesMut>>,
size: usize,
initial_capacity: usize,
}
impl Debug for PooledBuf {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
f.debug_struct("PooledBuf")
.field("size", &self.size)
.field("initial_capacity", &self.initial_capacity)
.finish_non_exhaustive()
}
}
impl PooledBuf {
pub fn new(size: usize) -> Self {
Self {
pool: Mutex::new(VecDeque::with_capacity(size)),
size,
initial_capacity: 0,
}
}
pub fn with_initial_capacity(mut self, initial_capacity: usize) -> Self {
self.initial_capacity = initial_capacity;
self
}
pub fn get(&self) -> BytesMut {
let Ok(mut pool) = self.pool.try_lock() else {
return BytesMut::with_capacity(self.initial_capacity);
};
if let Some(buf) = pool.pop_front() {
buf
} else {
BytesMut::with_capacity(self.initial_capacity)
}
}
pub fn put(&self, mut buf: BytesMut) {
let Ok(mut pool) = self.pool.try_lock() else {
return;
};
if pool.len() < self.size {
buf.clear();
pool.push_back(buf);
}
}
}
#[cfg(test)]
mod tests {
use bytes::BufMut;
use super::*;
#[test]
fn test_pooled_buf() {
let pool = PooledBuf::new(2);
let mut buf1 = pool.get();
buf1.put_slice(b"hello, world!");
let mut buf2 = pool.get();
buf2.reserve(1024);
pool.put(buf1);
pool.put(buf2);
let buf3 = pool.get();
assert_eq!(buf3.len(), 0);
assert_eq!(buf3.capacity(), 13);
let buf4 = pool.get();
assert_eq!(buf4.len(), 0);
assert_eq!(buf4.capacity(), 1024);
}
}