use std::{array, cell, mem, slice};
use crate::{
alloc,
depot::{
arena::slab::{
entries,
key::{self, cycle},
},
capacity,
},
};
pub struct Heap;
pub struct Inline<const N: usize>;
pub struct Eager;
pub struct Lazy;
pub trait Storage: entries::Sealed {
type Plane<T, const MAX: u32, M: entries::Mode, I: Init>: Plane<T, MAX, M>;
}
impl Storage for Heap {
type Plane<T, const MAX: u32, M: entries::Mode, I: Init> = <I as Init>::Heap<T, MAX, M>;
}
impl<const N: usize> Storage for Inline<N> {
type Plane<T, const MAX: u32, M: entries::Mode, I: Init> = <I as Init>::Inline<N, T, MAX, M>;
}
impl entries::Sealed for Heap {}
impl<const N: usize> entries::Sealed for Inline<N> {}
pub trait Init: entries::Sealed {
const LAZY: bool;
type Heap<T, const MAX: u32, M: entries::Mode>: HeapPlane<T, MAX, M>;
type Inline<const N: usize, T, const MAX: u32, M: entries::Mode>: InlinePlane<T, MAX, M>;
}
impl Init for Eager {
const LAZY: bool = false;
type Heap<T, const MAX: u32, M: entries::Mode> = HeapEager<T, MAX, M>;
type Inline<const N: usize, T, const MAX: u32, M: entries::Mode> = InlineEager<N, T, MAX, M>;
}
impl Init for Lazy {
const LAZY: bool = true;
type Heap<T, const MAX: u32, M: entries::Mode> = HeapLazy<T, MAX, M>;
type Inline<const N: usize, T, const MAX: u32, M: entries::Mode> = InlineLazy<N, T, MAX, M>;
}
impl entries::Sealed for Eager {}
impl entries::Sealed for Lazy {}
type Slot<T, const MAX: u32, M> = crate::depot::raw::SlabSlot<
T,
key::Generation<MAX>,
<M as entries::Mode>::Busy,
<<M as entries::Mode>::Cycle as cycle::Policy>::Retired,
>;
type Shape<T, const MAX: u32, M> = crate::depot::raw::SlabCapacity<
T,
key::Generation<MAX>,
<M as entries::Mode>::Busy,
<<M as entries::Mode>::Cycle as cycle::Policy>::Retired,
>;
type Prepared<T, const MAX: u32, M> = crate::alloc::raw::Block<
Shape<T, MAX, M>,
cell::Cell<u32>,
(),
mem::MaybeUninit<Slot<T, MAX, M>>,
>;
type Ready<T, const MAX: u32, M> =
crate::alloc::raw::Block<Shape<T, MAX, M>, cell::Cell<u32>, (), Slot<T, MAX, M>>;
pub struct HeapEager<T, const MAX: u32, M: entries::Mode> {
block: Ready<T, MAX, M>,
}
impl<T, const MAX: u32, M: entries::Mode> HeapPlane<T, MAX, M> for HeapEager<T, MAX, M> {
fn try_alloc(
cap: capacity::Count,
init: impl Fn(u32) -> Slot<T, MAX, M>,
) -> Result<Self, alloc::Error> {
let extent = crate::depot::raw::SlabCapacity::new(cap)?;
Ok(Self {
block: crate::alloc::raw::Block::try_init(extent, cell::Cell::new(0), |index| {
(
init(index as u32),
cell::Cell::new(mem::MaybeUninit::uninit()),
)
})?,
})
}
}
impl<T, const MAX: u32, M: entries::Mode> Plane<T, MAX, M> for HeapEager<T, MAX, M> {
fn retired(&self) -> Option<&cell::Cell<u32>> {
Some(&self.block.state)
}
fn count(&self) -> capacity::Count {
self.block.extent().count
}
fn tail(&self) -> &[cell::Cell<mem::MaybeUninit<u32>>] {
self.block.tail()
}
fn as_ref(&self) -> &[Slot<T, MAX, M>] {
self.block.as_ref()
}
}
pub struct HeapLazy<T, const MAX: u32, M: entries::Mode> {
block: Prepared<T, MAX, M>,
built: cell::Cell<u32>,
}
impl<T, const MAX: u32, M: entries::Mode> HeapPlane<T, MAX, M> for HeapLazy<T, MAX, M> {
fn try_alloc(
cap: capacity::Count,
_: impl Fn(u32) -> Slot<T, MAX, M>,
) -> Result<Self, alloc::Error> {
let extent = crate::depot::raw::SlabCapacity::new(cap)?;
Ok(Self {
block: crate::alloc::raw::Block::try_fill(extent, cell::Cell::new(0), |_| {
(
mem::MaybeUninit::uninit(),
cell::Cell::new(mem::MaybeUninit::uninit()),
)
})?,
built: cell::Cell::new(0),
})
}
}
impl<T, const MAX: u32, M: entries::Mode> Plane<T, MAX, M> for HeapLazy<T, MAX, M> {
fn retired(&self) -> Option<&cell::Cell<u32>> {
Some(&self.block.state)
}
fn count(&self) -> capacity::Count {
self.block.extent().count
}
fn tail(&self) -> &[cell::Cell<mem::MaybeUninit<u32>>] {
self.block.tail()
}
fn as_ref(&self) -> &[Slot<T, MAX, M>] {
unsafe { slice::from_raw_parts(self.block.as_ptr().cast(), self.built() as usize) }
}
fn built(&self) -> u32 {
self.built.get()
}
fn push(&self, slot: Slot<T, MAX, M>) -> Option<&Slot<T, MAX, M>> {
let index = self.built();
if index as usize >= self.capacity() {
return None;
}
let slot = unsafe { (&mut *self.block.as_ptr().add(index as usize)).write(slot) };
self.built.set(index + 1);
Some(slot)
}
}
pub struct InlineEager<const N: usize, T, const MAX: u32, M: entries::Mode> {
slots: [Slot<T, MAX, M>; N],
cells: [cell::Cell<mem::MaybeUninit<u32>>; N],
}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> InlinePlane<T, MAX, M>
for InlineEager<N, T, MAX, M>
{
fn inline(init: impl Fn(u32) -> Slot<T, MAX, M>) -> Self {
const { assert!(N <= u32::MAX as usize, "inline slot count") };
Self {
slots: array::from_fn(|index| init(index as u32)),
cells: [const { cell::Cell::new(mem::MaybeUninit::uninit()) }; N],
}
}
}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> Plane<T, MAX, M>
for InlineEager<N, T, MAX, M>
{
fn count(&self) -> capacity::Count {
capacity::Count::new(N as u32)
}
fn tail(&self) -> &[cell::Cell<mem::MaybeUninit<u32>>] {
&self.cells
}
fn as_ref(&self) -> &[Slot<T, MAX, M>] {
&self.slots
}
}
pub struct InlineLazy<const N: usize, T, const MAX: u32, M: entries::Mode> {
slots: [cell::UnsafeCell<mem::MaybeUninit<Slot<T, MAX, M>>>; N],
cells: [cell::Cell<mem::MaybeUninit<u32>>; N],
built: cell::Cell<u32>,
}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> InlinePlane<T, MAX, M>
for InlineLazy<N, T, MAX, M>
{
fn inline(_: impl Fn(u32) -> Slot<T, MAX, M>) -> Self {
const { assert!(N <= u32::MAX as usize, "inline slot count") };
Self {
slots: [const { cell::UnsafeCell::new(mem::MaybeUninit::uninit()) }; N],
cells: [const { cell::Cell::new(mem::MaybeUninit::uninit()) }; N],
built: cell::Cell::new(0),
}
}
}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> Plane<T, MAX, M>
for InlineLazy<N, T, MAX, M>
{
fn count(&self) -> capacity::Count {
capacity::Count::new(N as u32)
}
fn tail(&self) -> &[cell::Cell<mem::MaybeUninit<u32>>] {
&self.cells
}
fn as_ref(&self) -> &[Slot<T, MAX, M>] {
unsafe { slice::from_raw_parts(self.slots.as_ptr().cast(), self.built() as usize) }
}
fn built(&self) -> u32 {
self.built.get()
}
fn push(&self, slot: Slot<T, MAX, M>) -> Option<&Slot<T, MAX, M>> {
let index = self.built();
if index as usize >= N {
return None;
}
let slot = unsafe { (*self.slots.get_unchecked(index as usize).get()).write(slot) };
self.built.set(index + 1);
Some(slot)
}
}
pub trait Plane<T, const MAX: u32, M: entries::Mode>: Sized + entries::Sealed {
fn count(&self) -> capacity::Count;
fn retired(&self) -> Option<&cell::Cell<u32>> {
None
}
fn tail(&self) -> &[cell::Cell<mem::MaybeUninit<u32>>];
fn as_ref(&self) -> &[Slot<T, MAX, M>];
fn built(&self) -> u32 {
self.count().raw()
}
fn push(&self, _: Slot<T, MAX, M>) -> Option<&Slot<T, MAX, M>> {
None
}
fn capacity(&self) -> usize {
self.count().get()
}
fn get(&self, index: u32) -> Option<&Slot<T, MAX, M>> {
self.as_ref().get(index as usize)
}
}
pub trait HeapPlane<T, const MAX: u32, M: entries::Mode>: Plane<T, MAX, M> {
fn try_alloc(
cap: capacity::Count,
init: impl Fn(u32) -> Slot<T, MAX, M>,
) -> Result<Self, alloc::Error>;
}
pub trait InlinePlane<T, const MAX: u32, M: entries::Mode>: Plane<T, MAX, M> {
fn inline(init: impl Fn(u32) -> Slot<T, MAX, M>) -> Self;
}
impl<T, const MAX: u32, M: entries::Mode> entries::Sealed for HeapEager<T, MAX, M> {}
impl<T, const MAX: u32, M: entries::Mode> entries::Sealed for HeapLazy<T, MAX, M> {}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> entries::Sealed
for InlineEager<N, T, MAX, M>
{
}
impl<const N: usize, T, const MAX: u32, M: entries::Mode> entries::Sealed
for InlineLazy<N, T, MAX, M>
{
}