use std::{alloc::Layout, marker, mem};
use crate::alloc::{self, tail};
#[repr(transparent)]
pub struct Plan<H, T, N: alloc::raw::TailExtent = usize> {
value: N,
types: marker::PhantomData<fn() -> (H, T)>,
}
#[repr(C)]
pub(in crate::alloc::tail) struct Prefix<H, T, N: alloc::raw::TailExtent = usize> {
pub(in crate::alloc::tail) header: H,
pub(in crate::alloc::tail) len: Plan<H, T, N>,
}
impl<H, T, N: alloc::raw::TailExtent> Plan<H, T, N> {
pub(in crate::alloc) const fn tail_offset() -> usize {
unsafe { alloc::raw::Layout::<T>::offset(mem::size_of::<Prefix<H, T, N>>()) }
}
pub fn try_new(extent: N) -> Result<Self, alloc::Overflow> {
if !Self::fits(extent.len()) {
return Err(alloc::Overflow);
}
Ok(Self {
value: extent,
types: marker::PhantomData,
})
}
pub fn try_allocate(self) -> Result<tail::Uninit<H, T, N>, alloc::Exhausted> {
let memory = alloc::raw::LayoutExt::try_allocate(self.layout())?;
Ok(tail::Uninit {
memory,
layout: self,
})
}
const fn fits(len: usize) -> bool {
alloc::raw::Layout::<T>::fits_after(Layout::new::<Prefix<H, T, N>>(), len)
}
pub fn layout(&self) -> Layout {
unsafe { Self::layout_for(self.len()) }
}
const unsafe fn layout_for(len: usize) -> Layout {
unsafe { alloc::raw::Layout::<T>::extend(Layout::new::<Prefix<H, T, N>>(), len) }
.0
.pad_to_align()
}
pub(in crate::alloc::tail) fn len(self) -> usize {
self.value.len()
}
pub(in crate::alloc::tail) const fn extent(self) -> N {
self.value
}
}
impl<H, T> Plan<H, T> {
pub const fn size(self) -> usize {
unsafe { Self::layout_for(self.value) }.size()
}
#[must_use]
pub const fn fixed<const LEN: usize>() -> Self {
const {
assert!(Self::fits(LEN), "layout");
};
Self {
value: LEN,
types: marker::PhantomData,
}
}
}
impl<H, T, N: alloc::raw::TailExtent> Clone for Plan<H, T, N> {
fn clone(&self) -> Self {
*self
}
}
impl<H, T, N: alloc::raw::TailExtent> Copy for Plan<H, T, N> {}