buf_pool.rs

  1use crossbeam::queue::SegQueue;
  2use std::ops::{Deref, DerefMut};
  3use std::path::PathBuf;
  4use std::sync::Arc;
  5
  6/// Trait for types that can be pooled and reused.
  7///
  8/// Types implementing this trait can be:
  9/// 1. Created empty via `Default`
 10/// 2. Reset to empty state via `clear()` (preserving capacity)
 11/// 3. Sent across threads (required by `SegQueue`)
 12pub trait Poolable: Default + Send {
 13    /// Reset the value to its empty state, preserving any allocated capacity.
 14    fn clear(&mut self);
 15}
 16
 17impl<T: Send> Poolable for Vec<T> {
 18    fn clear(&mut self) {
 19        Vec::clear(self);
 20    }
 21}
 22
 23impl Poolable for String {
 24    fn clear(&mut self) {
 25        String::clear(self);
 26    }
 27}
 28
 29impl Poolable for PathBuf {
 30    fn clear(&mut self) {
 31        PathBuf::clear(self);
 32    }
 33}
 34
 35/// A thread-safe, lock-free pool of reusable buffers.
 36#[derive(Clone)]
 37pub struct BufPool<T: Poolable> {
 38    queue: Arc<SegQueue<T>>,
 39}
 40
 41impl<T: Poolable> BufPool<T> {
 42    /// Creates a pool pre-populated with `capacity` empty buffers.
 43    pub fn with_capacity(capacity: usize) -> Self {
 44        let queue = Arc::new(SegQueue::new());
 45        for _ in 0..capacity {
 46            queue.push(T::default());
 47        }
 48        Self { queue }
 49    }
 50
 51    /// Checks out a buffer from the pool. If the pool is empty, allocates a new buffer.
 52    pub fn checkout(&self) -> BufGuard<T> {
 53        let buf = self.queue.pop().unwrap_or_else(T::default);
 54        BufGuard {
 55            buf,
 56            pool: self.queue.clone(),
 57        }
 58    }
 59}
 60
 61/// RAII guard that automatically returns the buffer to the pool when dropped.
 62#[derive(Debug)]
 63pub struct BufGuard<T: Poolable> {
 64    buf: T,
 65    pool: Arc<SegQueue<T>>,
 66}
 67
 68impl<T: Poolable> BufGuard<T> {
 69    /// Extracts the buffer, preventing automatic return to the pool.
 70    /// Useful if you need to move the buffer elsewhere.
 71    pub fn into_inner(mut self) -> T {
 72        let buf = std::mem::take(&mut self.buf);
 73        // SAFETY:
 74        // 1) We forget `self`, preventing it from
 75        // double-free'ing `pool`
 76        // 2) The 'pointer' is really a &mut, so
 77        // it is aligned, type-valid, and valid for reads.
 78        let pool = unsafe { std::ptr::read(&self.pool) };
 79        std::mem::forget(self);
 80        drop(pool);
 81        buf
 82    }
 83}
 84
 85impl<T: Poolable> Drop for BufGuard<T> {
 86    fn drop(&mut self) {
 87        let mut buf = std::mem::take(&mut self.buf);
 88        buf.clear();
 89        self.pool.push(buf);
 90    }
 91}
 92
 93impl<T: Poolable> Deref for BufGuard<T> {
 94    type Target = T;
 95
 96    fn deref(&self) -> &Self::Target {
 97        &self.buf
 98    }
 99}
100
101impl<T: Poolable> DerefMut for BufGuard<T> {
102    fn deref_mut(&mut self) -> &mut Self::Target {
103        &mut self.buf
104    }
105}