memkit 0.1.0-beta.1

Deterministic, intent-driven memory allocation for systems requiring predictable performance
Documentation
//! Pool-allocated box type.

use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;

/// A Box-like wrapper for pool-allocated memory.
///
/// Automatically frees memory back to the pool when dropped.
pub struct MkPoolBox<T> {
    ptr: NonNull<T>,
    global: std::sync::Arc<crate::core::global::GlobalState>,
}

impl<T> MkPoolBox<T> {
    /// Create a new MkPoolBox.
    ///
    /// # Safety
    ///
    /// The pointer must have been allocated from a pool.
    pub(crate) unsafe fn from_raw(ptr: *mut T, global: std::sync::Arc<crate::core::global::GlobalState>) -> Option<Self> {
        NonNull::new(ptr).map(|ptr| Self { ptr, global })
    }

    /// Get the raw pointer.
    pub fn as_ptr(&self) -> *const T {
        self.ptr.as_ptr()
    }

    /// Get the raw mutable pointer.
    pub fn as_mut_ptr(&mut self) -> *mut T {
        self.ptr.as_ptr()
    }

    /// Leak the MkPoolBox, returning the raw pointer.
    pub fn into_raw(self) -> *mut T {
        let ptr = self.ptr.as_ptr();
        std::mem::forget(self);
        ptr
    }
}

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

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

impl<T> DerefMut for MkPoolBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { self.ptr.as_mut() }
    }
}

impl<T> Drop for MkPoolBox<T> {
    fn drop(&mut self) {
        unsafe {
            // Drop the value first
            std::ptr::drop_in_place(self.ptr.as_ptr());
            // Return memory to global heap (SlabAllocator is thread-local, 
            // so we use the global heap_free for cross-thread safety or 
            // the deferred queue if we want more safety. 
            // However, MkPoolBox is currently allocated via TLS slab.
            // If it drops on the SAME thread, it could go back to slab.
            // For now, to be safe across threads, we use heap_free since 
            // the SlabAllocator doesn't easily support cross-thread returns 
            // without a global lock.
            let layout = std::alloc::Layout::new::<T>();
            self.global.heap_free(self.ptr.as_ptr() as *mut u8, layout);
        }
    }
}

unsafe impl<T: Send> Send for MkPoolBox<T> {}
unsafe impl<T: Sync> Sync for MkPoolBox<T> {}