use std::alloc::{alloc, Layout};
use std::sync::{Mutex, OnceLock};
pub struct CellHeap<T> {
pool: Mutex<Vec<*mut T>>,
layout: Layout,
}
impl<T: 'static> CellHeap<T> {
fn global() -> &'static Self {
static INIT: OnceLock<Mutex<Vec<u8>>> = OnceLock::new(); static mut HEAP_PTR: *const () = std::ptr::null();
unsafe {
if HEAP_PTR.is_null() {
let layout = Layout::new::<T>();
let heap = Box::new(CellHeap {
pool: Mutex::new(Vec::<*mut T>::new()),
layout,
});
HEAP_PTR = Box::into_raw(heap) as *const ();
INIT.get_or_init(|| Mutex::new(vec![])); }
&*(HEAP_PTR as *const CellHeap<T>)
}
}
fn alloc(&self) -> *mut T {
self.pool.lock().unwrap().pop().unwrap_or_else(|| unsafe {
alloc(self.layout) as *mut T
})
}
unsafe fn free(&self, ptr: *mut T) {
self.pool.lock().unwrap().push(ptr);
}
}
pub struct Cell<T: 'static> {
ptr: *mut T,
heap: &'static CellHeap<T>,
}
impl<T: 'static> Cell<T> {
pub fn new(value: T) -> Self {
let heap = CellHeap::<T>::global();
let ptr = heap.alloc();
unsafe { ptr.write(value) }
Self { ptr, heap }
}
}
impl<T: 'static> Drop for Cell<T> {
fn drop(&mut self) {
unsafe {
self.ptr.drop_in_place();
self.heap.free(self.ptr);
}
}
}
impl<T: 'static> std::ops::Deref for Cell<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
unsafe { &*self.ptr }
}
}
impl<T: 'static> std::ops::DerefMut for Cell<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { &mut *self.ptr }
}
}