use core::cell::UnsafeCell;
use core::mem::MaybeUninit;
use core::ops::{Deref, DerefMut};
use crate::critical::CriticalSlots;
use crate::free_slots::FreeSlots;
pub struct ObjectPool<T, const N: usize, B = CriticalSlots<N>> {
pub(crate) slots: UnsafeCell<MaybeUninit<[T; N]>>,
pub(crate) free: B,
}
unsafe impl<T, const N: usize, B: FreeSlots<N>> Sync for ObjectPool<T, N, B> {}
pub struct StaticObjectPool<T, const N: usize, B: FreeSlots<N> = CriticalSlots<N>> {
data: UnsafeCell<MaybeUninit<ObjectPool<T, N, B>>>,
}
unsafe impl<T, const N: usize, B: FreeSlots<N>> Sync for StaticObjectPool<T, N, B> {}
impl<T: Clone, const N: usize, B: FreeSlots<N>> StaticObjectPool<T, N, B> {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Self {
data: UnsafeCell::new(MaybeUninit::uninit()),
}
}
pub fn init_pool(&'static self, init: T) -> &'static ObjectPool<T, N, B> {
assert!(N > 0, "Pool capacity must be greater than 0");
unsafe {
let ptr: *mut ObjectPool<T, N, B> = self.data.get().cast::<ObjectPool<T, N, B>>();
ptr.write(ObjectPool {
slots: UnsafeCell::new(MaybeUninit::uninit()),
free: B::new(),
});
(*ptr).free.fill(N).expect("fill(N) must succeed when count == capacity");
for i in 0..N {
(*ptr).slot_mut_ptr(i).write(init.clone());
}
&*ptr
}
}
}
impl<T, const N: usize, B: FreeSlots<N>> ObjectPool<T, N, B> {
pub fn request(&'static self) -> Option<ObjectGuard<T, N, B>> {
self.free
.take()
.map(|index| ObjectGuard { pool: self, index })
}
pub(crate) fn release(&self, idx: usize) {
self.free.put(idx);
}
#[inline]
pub(crate) unsafe fn slot_mut_ptr(&self, idx: usize) -> *mut T {
unsafe {
let base: *mut T = (*self.slots.get()).as_mut_ptr().cast::<T>();
base.add(idx)
}
}
#[inline]
pub(crate) unsafe fn slot_ptr(&self, idx: usize) -> *const T {
unsafe {
let base: *const T = (*self.slots.get()).as_ptr().cast::<T>();
base.add(idx)
}
}
}
#[must_use = "discarding an ObjectGuard immediately frees the slot — likely a bug"]
pub struct ObjectGuard<T: 'static, const N: usize, B: FreeSlots<N> + 'static = CriticalSlots<N>> {
pub(crate) pool: &'static ObjectPool<T, N, B>,
pub(crate) index: usize,
}
impl<T, const N: usize, B: FreeSlots<N>> Deref for ObjectGuard<T, N, B> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.pool.slot_ptr(self.index) }
}
}
impl<T, const N: usize, B: FreeSlots<N>> DerefMut for ObjectGuard<T, N, B> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.pool.slot_mut_ptr(self.index) }
}
}
impl<T, const N: usize, B: FreeSlots<N>> Drop for ObjectGuard<T, N, B> {
fn drop(&mut self) {
self.pool.release(self.index);
}
}
unsafe impl<T: Send, const N: usize, B: FreeSlots<N>> Send for ObjectGuard<T, N, B> {}