use std::{mem, ptr, slice};
use crate::alloc;
#[derive(Debug)]
#[repr(C)]
pub struct Block<
E: alloc::raw::Shape,
S,
X = (),
R = mem::MaybeUninit<<E as alloc::raw::Shape>::Root>,
> {
root: ptr::NonNull<R>,
pub(super) tail: ptr::NonNull<E::Tail>,
pub(super) extent: E,
pub state: S,
extra: X,
}
pub(super) struct Uninit<E: alloc::raw::Shape> {
memory: ptr::NonNull<u8>,
extent: E,
}
impl<E: alloc::raw::Shape> Uninit<E> {
pub(super) fn try_new(extent: E) -> Result<Self, alloc::Exhausted> {
let plan = extent.layout();
Ok(Self {
memory: alloc::raw::LayoutExt::try_allocate(plan)?,
extent,
})
}
pub(super) fn planes_mut(&mut self) -> Arrays<'_, E::Root, E::Tail, E::Extra, E::Last> {
let len = self.extent.len();
unsafe {
(
slice::from_raw_parts_mut(self.memory.cast().as_ptr(), len),
slice::from_raw_parts_mut(
self.memory.add(self.extent.offset()).cast().as_ptr(),
self.extent.tail_len(),
),
slice::from_raw_parts_mut(
self.memory.add(self.extent.extra()).cast().as_ptr(),
len,
),
slice::from_raw_parts_mut(self.memory.add(self.extent.last()).cast().as_ptr(), len),
)
}
}
pub(super) unsafe fn finish<S, X, R>(self, state: S, extra: X) -> Block<E, S, X, R> {
let tail = unsafe { self.memory.add(self.extent.offset()) }.cast();
Block {
root: self.memory.cast(),
tail,
extent: self.extent,
state,
extra,
}
}
}
impl<E: alloc::raw::Shape<Tail: Copy>, S> Block<E, S> {
pub(crate) fn try_new(extent: E, state: S, value: E::Tail) -> Result<Self, alloc::Exhausted> {
let mut memory = Uninit::try_new(extent)?;
memory.planes_mut().1.fill(mem::MaybeUninit::new(value));
Ok(unsafe { memory.finish(state, ()) })
}
}
impl<E: alloc::raw::Rows, S> Block<E, S> {
pub(crate) fn try_fill(
extent: E,
state: S,
init: impl Fn(usize) -> (mem::MaybeUninit<E::Root>, E::Tail),
) -> Result<Self, alloc::Exhausted> {
const { assert!(!mem::needs_drop::<E::Tail>()) };
let mut memory = Uninit::try_new(extent)?;
let (roots, tails, _, _) = memory.planes_mut();
alloc::raw::pair(roots, tails, init);
Ok(unsafe { memory.finish(state, ()) })
}
}
impl<E: alloc::raw::Rows, S> Block<E, S, (), E::Root> {
pub(crate) fn try_init(
extent: E,
state: S,
init: impl Fn(usize) -> (E::Root, E::Tail),
) -> Result<Self, alloc::Exhausted> {
const { assert!(!mem::needs_drop::<E::Root>() && !mem::needs_drop::<E::Tail>()) };
let mut memory = Uninit::try_new(extent)?;
let (roots, tails, _, _) = memory.planes_mut();
alloc::raw::pair(roots, tails, |index| {
let (value, entry) = init(index);
(mem::MaybeUninit::new(value), entry)
});
Ok(unsafe { memory.finish(state, ()) })
}
}
impl<E: alloc::raw::Shape, S> Block<E, S, (), E::Root> {
pub fn try_from_fn(
extent: E,
state: S,
root: impl Fn(usize) -> E::Root,
tail: impl Fn(usize) -> E::Tail,
) -> Result<Self, alloc::Exhausted> {
const { assert!(!mem::needs_drop::<E::Tail>()) };
let mut memory = Uninit::try_new(extent)?;
let (entries, heads, _, _) = memory.planes_mut();
alloc::raw::init(entries, &root);
alloc::raw::init(heads, tail);
Ok(unsafe { memory.finish(state, ()) })
}
}
impl<E: alloc::raw::Shape<Last = ()>, S> Block<E, S, alloc::raw::Initialized, E::Root> {
pub fn try_planes(
extent: E,
state: S,
root: impl Fn(usize) -> (E::Root, E::Extra),
tail: impl Fn(usize) -> E::Tail,
) -> Result<Self, alloc::Exhausted> {
const {
assert!(!mem::needs_drop::<E::Tail>());
assert!(!mem::needs_drop::<E::Extra>());
};
let mut memory = Uninit::try_new(extent)?;
let (entries, heads, extra, _) = memory.planes_mut();
alloc::raw::pair(entries, extra, |index| {
let (value, aux) = root(index);
(mem::MaybeUninit::new(value), aux)
});
alloc::raw::init(heads, tail);
Ok(unsafe { memory.finish(state, alloc::raw::Initialized) })
}
pub fn values(&self) -> &[E::Extra] {
let extra = unsafe { self.as_ptr().byte_add(self.extent.extra()).cast() };
unsafe { slice::from_raw_parts(extra, self.extent.len()) }
}
}
impl<E: alloc::raw::Shape, S> Block<E, S> {
pub(crate) fn enumerate(
self,
init: impl Fn(usize) -> E::Extra,
) -> Block<E, S, ptr::NonNull<E::Extra>> {
const { assert!(!mem::needs_drop::<E::Extra>()) };
let extra = unsafe { self.root.cast::<u8>().add(self.extent.extra()) }
.cast::<mem::MaybeUninit<E::Extra>>();
let entries = unsafe { slice::from_raw_parts_mut(extra.as_ptr(), self.extent.len()) };
alloc::raw::init(entries, init);
let this = mem::ManuallyDrop::new(self);
Block {
root: this.root,
tail: this.tail,
extent: unsafe { ptr::read(&this.extent) },
state: unsafe { ptr::read(&this.state) },
extra: extra.cast(),
}
}
}
impl<E: alloc::raw::Rows<Tail = mem::MaybeUninit<T>>, S, T>
Block<E, S, (ptr::NonNull<E::Extra>, ptr::NonNull<E::Last>)>
{
pub fn try_parts(
extent: E,
state: S,
init: impl Fn(usize) -> (E::Extra, E::Last),
) -> Result<Self, alloc::Exhausted> {
const {
assert!(!mem::needs_drop::<E::Extra>());
assert!(!mem::needs_drop::<E::Last>());
};
let mut memory = Uninit::try_new(extent)?;
let (_, _, extra, last) = memory.planes_mut();
alloc::raw::pair(extra, last, |index| {
let (entry, value) = init(index);
(mem::MaybeUninit::new(entry), value)
});
let extra = (
ptr::NonNull::from(extra).cast(),
ptr::NonNull::from(last).cast(),
);
Ok(unsafe { memory.finish(state, extra) })
}
}
impl<E: alloc::raw::Shape, S, X, R> Drop for Block<E, S, X, R> {
fn drop(&mut self) {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
self.root.as_ptr(),
self.extent.len(),
));
alloc::raw::LayoutExt::deallocate(self.extent.layout(), self.root);
}
}
}
impl<E: alloc::raw::Shape, S, X, R> Block<E, S, X, R> {
pub(crate) const fn as_ptr(&self) -> *mut R {
self.root.as_ptr()
}
pub const fn extent(&self) -> &E {
&self.extent
}
pub fn tail(&self) -> &[E::Tail] {
unsafe { slice::from_raw_parts(self.tail.as_ptr(), self.extent.tail_len()) }
}
pub fn parts_mut(&mut self) -> (&mut S, &mut [R], &mut [E::Tail]) {
unsafe {
(
&mut self.state,
slice::from_raw_parts_mut(self.root.as_ptr(), self.extent.len()),
slice::from_raw_parts_mut(self.tail.as_ptr(), self.extent.tail_len()),
)
}
}
}
impl<E: alloc::raw::Shape, S, X, R> AsRef<[R]> for Block<E, S, X, R> {
fn as_ref(&self) -> &[R] {
unsafe { slice::from_raw_parts(self.root.as_ptr(), self.extent.len()) }
}
}
impl<E: alloc::raw::Shape, S, X, R> AsMut<[R]> for Block<E, S, X, R> {
fn as_mut(&mut self) -> &mut [R] {
self.parts_mut().1
}
}
impl<E: alloc::raw::Shape, S> Block<E, S, ptr::NonNull<E::Extra>, mem::MaybeUninit<E::Root>> {
pub(crate) fn values(&self) -> &[E::Extra] {
unsafe { slice::from_raw_parts(self.extra.as_ptr(), self.extent.len()) }
}
pub(crate) fn values_mut(&mut self) -> &mut [E::Extra] {
unsafe { slice::from_raw_parts_mut(self.extra.as_ptr(), self.extent.len()) }
}
}
impl<E: alloc::raw::Rows, S>
Block<E, S, (ptr::NonNull<E::Extra>, ptr::NonNull<E::Last>), mem::MaybeUninit<E::Root>>
{
pub fn extra(&self) -> (&[E::Extra], &[E::Last]) {
unsafe {
(
slice::from_raw_parts(self.extra.0.as_ptr(), self.extent.len()),
slice::from_raw_parts(self.extra.1.as_ptr(), self.extent.len()),
)
}
}
pub fn extra_mut(&mut self) -> (&mut [E::Extra], &mut [E::Last]) {
unsafe {
(
slice::from_raw_parts_mut(self.extra.0.as_ptr(), self.extent.len()),
slice::from_raw_parts_mut(self.extra.1.as_ptr(), self.extent.len()),
)
}
}
}
type Arrays<'a, A, B, C, D> = (
&'a mut [mem::MaybeUninit<A>],
&'a mut [mem::MaybeUninit<B>],
&'a mut [mem::MaybeUninit<C>],
&'a mut [mem::MaybeUninit<D>],
);