use std::{cell, marker, mem, ptr};
use crate::{
alloc::tail,
depot::{
arena::pool::{self, recycle},
capacity,
},
};
pub struct Header<T: recycle::Recycle, C> {
pub(in crate::depot::arena::pool) free: cell::Cell<*mut pool::Entry<T, Header<T, C>>>,
pub(in crate::depot::arena::pool) context: mem::ManuallyDrop<C>,
}
pub trait Context<'owner, T>: Sized + 'owner
where
T: recycle::Recycle + 'owner,
{
fn released(&self, result: T::Release);
}
#[repr(transparent)]
pub struct Store<T: recycle::Recycle, C> {
block: Storage<T, C>,
}
impl<T: recycle::Recycle, C> Store<T, C> {
pub fn try_init(
capacity: capacity::Count,
context: C,
seed: T::Seed,
) -> Result<Self, crate::alloc::Error> {
Ok(Self {
block: pool::Entry::init(
tail::Plan::try_new(capacity)?.try_allocate()?,
Header {
free: cell::Cell::new(ptr::null_mut()),
context: mem::ManuallyDrop::new(context),
},
|_| T::from_seed(seed),
),
})
}
pub fn vacancy<'owner>(
&'owner self,
) -> Option<pool::Vacant<'owner, T, Header<T, C>, Notify<'owner>>>
where
T: 'owner,
C: Context<'owner, T>,
{
let header = tail::View::new(&self.block).header();
pool::Vacant::new(header)
}
}
impl<T: recycle::Recycle, C> Drop for Store<T, C> {
fn drop(&mut self) {
unsafe { mem::ManuallyDrop::drop(&mut self.block.header_mut().context) };
}
}
pub struct Notify<'a>(marker::PhantomData<fn(&'a ()) -> &'a ()>);
#[derive(Debug)]
pub struct Frozen;
unsafe impl<'owner, T, C> crate::depot::raw::PoolPolicy<T, Header<T, C>> for Notify<'owner>
where
T: recycle::Recycle + 'owner,
C: Context<'owner, T>,
{
fn retire(mut entry: pool::Terminal<'_, T, Header<T, C>>) {
let result = T::recycle(entry.get_mut());
entry.recycle().context.released(result);
}
}
unsafe impl<'owner, T, C> crate::depot::raw::PoolMutable<T, Header<T, C>> for Notify<'owner>
where
T: recycle::Recycle + 'owner,
C: Context<'owner, T>,
{
}
impl<T: recycle::Recycle, C> Header<T, C> {
pub(in crate::depot) fn free_list(&self) -> &cell::Cell<*mut pool::Entry<T, Self>> {
&self.free
}
}
type Storage<T, C> = tail::Block<Header<T, C>, pool::Entry<T, Header<T, C>>, capacity::Count>;