use std::fmt;
use std::ops::{Deref, DerefMut};
use crate::BufferPool;
pub struct PooledBuffer {
buffer: Option<Vec<u8>>,
pool: BufferPool,
}
impl PooledBuffer {
pub(crate) fn new(buffer: Vec<u8>, pool: BufferPool) -> Self {
Self { buffer: Some(buffer), pool }
}
#[inline]
pub fn len(&self) -> usize {
self.buffer.as_ref().unwrap().len()
}
#[inline]
pub fn capacity(&self) -> usize {
self.buffer.as_ref().unwrap().capacity()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.buffer.as_ref().unwrap().is_empty()
}
pub fn into_inner(mut self) -> Vec<u8> {
self.buffer.take().expect("PooledBuffer already consumed")
}
#[inline]
pub fn into_vec(self) -> Vec<u8> {
self.into_inner()
}
}
impl Deref for PooledBuffer {
type Target = Vec<u8>;
#[inline]
fn deref(&self) -> &Self::Target {
self.buffer.as_ref().expect("PooledBuffer already consumed")
}
}
impl DerefMut for PooledBuffer {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
self.buffer.as_mut().expect("PooledBuffer already consumed")
}
}
impl Drop for PooledBuffer {
fn drop(&mut self) {
if let Some(buffer) = self.buffer.take() {
self.pool.put(buffer);
}
}
}
impl fmt::Debug for PooledBuffer {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PooledBuffer")
.field("len", &self.len())
.field("capacity", &self.capacity())
.finish()
}
}
impl AsRef<[u8]> for PooledBuffer {
#[inline]
fn as_ref(&self) -> &[u8] {
self.buffer.as_ref().unwrap().as_ref()
}
}
impl AsMut<[u8]> for PooledBuffer {
#[inline]
fn as_mut(&mut self) -> &mut [u8] {
self.buffer.as_mut().unwrap().as_mut()
}
}
#[cfg(all(target_os = "linux", feature = "tokio-uring"))]
mod tokio_uring_support {
use super::PooledBuffer;
use tokio_uring::buf::{IoBuf, IoBufMut};
unsafe impl IoBuf for PooledBuffer {
fn stable_ptr(&self) -> *const u8 {
self.buffer.as_ref().unwrap().as_ptr()
}
fn bytes_init(&self) -> usize {
self.buffer.as_ref().unwrap().len()
}
fn bytes_total(&self) -> usize {
self.buffer.as_ref().unwrap().capacity()
}
}
unsafe impl IoBufMut for PooledBuffer {
fn stable_mut_ptr(&mut self) -> *mut u8 {
self.buffer.as_mut().unwrap().as_mut_ptr()
}
unsafe fn set_init(&mut self, pos: usize) {
unsafe {
self.buffer.as_mut().unwrap().set_len(pos);
}
}
}
}
#[cfg(test)]
mod tests {
use crate::BufferPool;
#[test]
fn test_pooled_buffer_deref() {
let pool = BufferPool::new();
let mut buffer = pool.get(1024);
assert_eq!(buffer.len(), 1024);
buffer[0] = 42;
assert_eq!(buffer[0], 42);
}
#[test]
fn test_pooled_buffer_auto_return() {
let pool = BufferPool::new();
let cap = {
let buffer = pool.get(1024);
buffer.capacity()
};
let buffer2 = pool.get(1024);
assert_eq!(buffer2.capacity(), cap, "Buffer was not reused");
}
#[test]
fn test_pooled_buffer_explicit_drop() {
let pool = BufferPool::new();
let cap = {
let buffer = pool.get(1024);
let cap = buffer.capacity();
drop(buffer); cap
};
let buffer2 = pool.get(1024);
assert_eq!(buffer2.capacity(), cap, "Buffer was not reused");
}
#[test]
fn test_pooled_buffer_as_ref() {
let pool = BufferPool::new();
let mut buffer = pool.get(10);
buffer[0] = 42;
let slice: &[u8] = buffer.as_ref();
assert_eq!(slice[0], 42);
}
#[test]
fn test_pooled_buffer_as_mut() {
let pool = BufferPool::new();
let mut buffer = pool.get(10);
let slice: &mut [u8] = buffer.as_mut();
slice[0] = 42;
assert_eq!(buffer[0], 42);
}
#[test]
fn test_pooled_buffer_debug() {
let pool = BufferPool::new();
let buffer = pool.get(1024);
let debug_str = format!("{buffer:?}");
assert!(debug_str.contains("PooledBuffer"));
assert!(debug_str.contains("len"));
assert!(debug_str.contains("capacity"));
}
#[test]
fn test_into_inner() {
let pool = BufferPool::new();
let mut buffer = pool.get(10);
buffer[0] = 42;
let vec = buffer.into_inner();
assert_eq!(vec.len(), 10);
assert_eq!(vec[0], 42);
let new_buffer = pool.get(10);
assert_ne!(new_buffer.as_ptr(), vec.as_ptr());
}
#[test]
fn test_into_vec() {
let pool = BufferPool::new();
let mut buffer = pool.get(5);
buffer[0] = 123;
let vec = buffer.into_vec();
assert_eq!(vec.len(), 5);
assert_eq!(vec[0], 123);
}
#[test]
fn test_into_inner_consumes_buffer() {
let pool = BufferPool::new();
let buffer = pool.get(1024);
let vec = buffer.into_inner();
assert_eq!(vec.len(), 1024);
}
#[cfg(all(target_os = "linux", feature = "tokio-uring"))]
#[test]
fn test_tokio_uring_traits() {
use tokio_uring::buf::{IoBuf, IoBufMut};
let pool = BufferPool::new();
let mut buffer = pool.get(1024);
assert_eq!(buffer.bytes_total(), 1024);
let ptr = buffer.stable_mut_ptr();
assert!(!ptr.is_null());
}
#[cfg(all(target_os = "linux", feature = "tokio-uring"))]
#[test]
fn test_tokio_uring_bounded_traits() {
let pool = BufferPool::new();
let mut buffer = pool.get(10);
buffer[0] = 42;
let slice: &[u8] = &buffer;
assert_eq!(slice[0], 42);
let mut_slice: &mut [u8] = &mut buffer;
mut_slice[1] = 43;
assert_eq!(buffer[1], 43);
}
}