use std::{cell, mem};
use inline::{index, slot};
use crate::{
base::marker::ThreadBound,
depot::{self, arena::linked::fifo::ends, queue::ring::inline},
};
pub struct Pool<T, const N: usize, P: Copy = ()> {
_thread: ThreadBound,
pub(in crate::depot::queue::ring::inline) entries: [slot::Slot<T, N, P>; N],
pub(in crate::depot::queue::ring::inline) free: ends::Cell<Option<index::Index<N>>>,
pub(in crate::depot::queue::ring::inline) pending: ends::Cell<Option<index::Index<N>>>,
}
impl<T, const N: usize, P: Copy> Pool<T, N, P> {
pub fn new(values: [T; N]) -> Self {
let (head, tail) = match index::Index::bounds() {
Some((head, tail)) => (Some(head), Some(tail)),
None => (None, None),
};
let mut next = head.and_then(index::Index::next);
let entries = values.map(|value| {
let slot = slot::Slot {
value: cell::UnsafeCell::new(value),
payload: cell::UnsafeCell::new(mem::MaybeUninit::uninit()),
next: cell::Cell::new(next),
};
next = next.and_then(index::Index::next);
slot
});
Self {
_thread: ThreadBound::NEW,
entries,
free: unsafe { ends::Cell::from_parts(head, tail) },
pending: ends::Cell::empty(),
}
}
pub fn try_acquire(&self) -> Result<inline::Lease<'_, T, N, P>, inline::Full> {
self.pop::<false>().ok_or(inline::Full { capacity: N })
}
pub fn pop_front(&self) -> Option<(inline::Lease<'_, T, N, P>, P)> {
let lease = self.pop::<true>()?;
let payload = unsafe { (*lease.index.get(&self.entries).payload.get()).assume_init_read() };
Some((lease, payload))
}
fn pop<const PENDING: bool>(&self) -> Option<inline::Lease<'_, T, N, P>> {
let list = if PENDING { &self.pending } else { &self.free };
ends::Cell::pop_front(unsafe {
depot::raw::Proof::new((list, (), |head: index::Index<N>, ()| {
(
head.get(&self.entries).next.get(),
inline::Lease {
pool: self,
index: head,
},
)
}))
})
}
pub fn is_empty(&self) -> bool {
self.pending.is_empty()
}
}