alloc-from-pool 1.0.5

Single-threaded object pool implementation
Documentation
use std::cell::UnsafeCell;
use std::ops::Deref;

use crate::{alloc_in::alloc_in, allocations_ptr::allocations_ptr};

pub struct PoolValue<T: 'static> {
    pub(crate) ptr: *mut T,
    pub(crate) slots: *const UnsafeCell<Vec<Box<T>>>,
    #[cfg(test)]
    pub(crate) allocations: *mut usize,
}

impl<T> PoolValue<T> {
    pub fn take_value(&mut self) -> T {
        let value = *unsafe { Box::from_raw(self.ptr) };
        self.ptr = std::ptr::null_mut();
        value
    }
}

impl<T> Deref for PoolValue<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        unsafe { self.ptr.as_ref().unwrap_unchecked() }
    }
}

impl<T> Clone for PoolValue<T>
where
    T: Clone,
{
    fn clone(&self) -> Self {
        alloc_in(self.slots, allocations_ptr!(self), self.deref().clone())
    }
}

impl<T> PartialEq for PoolValue<T>
where
    T: PartialEq,
{
    fn eq(&self, other: &Self) -> bool {
        self.deref() == other.deref()
    }
}

impl<T> PartialEq<T> for PoolValue<T>
where
    T: PartialEq,
{
    fn eq(&self, other: &T) -> bool {
        self.deref() == other
    }
}

impl<T> PartialEq<&T> for PoolValue<T>
where
    T: PartialEq + std::fmt::Debug,
{
    fn eq(&self, other: &&T) -> bool {
        self.deref() == *other
    }
}

impl<T> Drop for PoolValue<T> {
    fn drop(&mut self) {
        if !self.ptr.is_null() {
            let ptr = self.ptr;
            self.ptr = std::ptr::null_mut();
            unsafe {
                UnsafeCell::raw_get(self.slots)
                    .as_mut()
                    .unwrap_unchecked()
                    .push(Box::from_raw(ptr))
            }
        }
    }
}

impl<T> std::fmt::Debug for PoolValue<T>
where
    T: std::fmt::Debug,
{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{:?}", self.deref())
    }
}