use std::{alloc, marker, mem, num::NonZero, ptr};
pub use block::Block;
pub use extent::Extent;
pub(crate) use layout::Bounds;
pub use layout::Layout;
pub use rows::Rows;
pub use shape::Shape;
use crate::{
alloc::{Exhausted, Overflow, Vacant, array},
base::marker::ThreadBound,
};
mod layout;
pub(crate) use layout::Root;
pub use resident::Resident;
#[derive(Debug)]
pub struct Initialized;
mod block;
mod extent;
mod resident;
mod rows;
mod shape;
pub trait VecExt<T> {
unsafe fn vacancy(&mut self) -> Vacant<'_, T>;
unsafe fn swap_remove(&mut self, index: usize) -> (T, Option<&T>);
}
impl<T> VecExt<T> for Vec<T> {
unsafe fn vacancy(&mut self) -> Vacant<'_, T> {
Vacant {
values: self,
_bound: ThreadBound::NEW,
}
}
unsafe fn swap_remove(&mut self, index: usize) -> (T, Option<&T>) {
let last = self.len() - 1;
let pointer = self.as_mut_ptr();
let value = unsafe { pointer.add(last).read() };
unsafe { self.set_len(last) };
if index == last {
return (value, None);
}
let slot = unsafe { &mut *pointer.add(index) };
(mem::replace(slot, value), Some(slot))
}
}
pub trait AssumeInit: Sized {
type Value;
type Output;
unsafe fn assume_init(self) -> Self::Output;
unsafe fn try_map<I: Iterator, F>(
self,
source: I,
make: impl for<'slot> FnMut(
array::Slot<'slot, Self::Value>,
I::Item,
) -> Result<array::Written<'slot>, F>,
) -> Result<Self::Output, F>;
}
pub unsafe fn relocate<T, E: Extent, S, const N: usize>(
source: &mut array::Block<mem::MaybeUninit<T>, E, S>,
mut spare: array::Block<mem::MaybeUninit<T>, E>,
runs: [(usize, usize, usize); N],
) {
for (start, target, len) in runs {
if len != 0 && mem::size_of::<T>() != 0 {
unsafe {
ptr::copy_nonoverlapping(
source.as_mut_ptr().add(start),
spare.as_mut_ptr().add(target),
len,
);
}
}
}
source.swap_storage(&mut spare);
}
#[derive(Clone, Copy)]
#[repr(transparent)]
pub struct Empty<E: Extent>(E);
impl<E: Extent> Empty<E> {
pub const unsafe fn assume(extent: E) -> Self {
Self(extent)
}
pub(in crate::alloc) const fn into_inner(self) -> E {
self.0
}
}
pub unsafe trait TailExtent: Extent {
#[doc(hidden)]
type Index: TailIndex;
#[doc(hidden)]
fn indices(self) -> impl Iterator<Item = Self::Index>;
}
unsafe impl TailExtent for usize {
type Index = usize;
fn indices(self) -> impl Iterator<Item = Self::Index> {
0..self
}
}
unsafe impl TailExtent for NonZero<u32> {
type Index = u32;
fn indices(self) -> impl Iterator<Item = Self::Index> {
0..self.get()
}
}
pub unsafe trait TailIndex: Copy {
#[doc(hidden)]
fn get(self) -> usize;
}
unsafe impl TailIndex for usize {
fn get(self) -> usize {
self
}
}
unsafe impl TailIndex for u32 {
fn get(self) -> usize {
const { assert!(usize::BITS >= u32::BITS) };
self as usize
}
}
impl<T, E: Extent, S> AssumeInit for array::Block<mem::MaybeUninit<T>, E, S> {
type Value = T;
type Output = array::Block<T, E, S>;
unsafe fn assume_init(self) -> Self::Output {
unsafe { self.assume_init() }
}
unsafe fn try_map<I: Iterator, F>(
mut self,
source: I,
mut make: impl for<'slot> FnMut(
array::Slot<'slot, T>,
I::Item,
) -> Result<array::Written<'slot>, F>,
) -> Result<array::Block<T, E, S>, F> {
let pointer = ptr::NonNull::from(&mut *self).cast::<T>();
let mut filled = 0;
for item in source {
let place = unsafe { pointer.add(filled) };
if let Err(error) = make(
array::Slot {
pointer: place,
filled: &mut filled,
value: marker::PhantomData,
},
item,
) {
unsafe {
ptr::drop_in_place(ptr::slice_from_raw_parts_mut(pointer.as_ptr(), filled));
}
return Err(error);
}
}
Ok(unsafe { self.assume_init() })
}
}
pub(in crate::alloc) fn into_vec<T>(block: array::Block<T, usize, ()>) -> Vec<T> {
let mut block = mem::ManuallyDrop::new(block);
let len = *block.extent();
let pointer = block.as_mut_ptr();
unsafe { Vec::from_raw_parts(pointer, len, len) }
}
#[repr(C)]
pub struct Tail<S, T> {
prior: S,
offset: usize,
value: marker::PhantomData<fn() -> T>,
}
pub trait Recipe: Sized {
type Fields;
fn try_build(self) -> Result<Bundle<Self::Fields>, Overflow>;
unsafe fn build(self) -> Bundle<Self::Fields>;
fn tail<T>(self, len: usize) -> impl Recipe<Fields = Tail<Self::Fields, T>> {
layout::Tail {
prior: self,
len,
value: marker::PhantomData,
}
}
}
pub trait LayoutExt: Sized {
fn try_allocate<T>(self) -> Result<ptr::NonNull<T>, Exhausted>;
unsafe fn deallocate<T>(self, pointer: ptr::NonNull<T>);
}
impl LayoutExt for alloc::Layout {
fn try_allocate<T>(self) -> Result<ptr::NonNull<T>, Exhausted> {
if self.size() == 0 {
return Ok(self.dangling_ptr().cast());
}
unsafe { try_new(self, false) }
}
unsafe fn deallocate<T>(self, pointer: ptr::NonNull<T>) {
if self.size() != 0 {
unsafe { dealloc(self, pointer) };
}
}
}
pub(crate) unsafe fn try_new<T>(
layout: alloc::Layout,
zeroed: bool,
) -> Result<ptr::NonNull<T>, Exhausted> {
let pointer = unsafe {
if zeroed {
alloc::alloc_zeroed(layout)
} else {
alloc::alloc(layout)
}
};
ptr::NonNull::new(pointer.cast()).ok_or(Exhausted)
}
pub(crate) unsafe fn dealloc<T>(layout: alloc::Layout, pointer: ptr::NonNull<T>) {
unsafe { alloc::dealloc(pointer.cast().as_ptr(), layout) };
}
pub(crate) unsafe fn resize(
layout: alloc::Layout,
pointer: ptr::NonNull<u8>,
target: alloc::Layout,
) -> Result<ptr::NonNull<u8>, Exhausted> {
let pointer = unsafe { alloc::realloc(pointer.as_ptr(), layout, target.size()) };
ptr::NonNull::new(pointer).ok_or(Exhausted)
}
pub(in crate::alloc) fn init<T>(
entries: &mut [mem::MaybeUninit<T>],
mut make: impl FnMut(usize) -> T,
) {
for (index, entry) in entries.iter_mut().enumerate() {
entry.write(make(index));
}
}
pub(in crate::alloc) fn pair<T, U>(
entries: &mut [mem::MaybeUninit<T>],
other: &mut [mem::MaybeUninit<U>],
make: impl Fn(usize) -> (mem::MaybeUninit<T>, U),
) {
for (index, (first, second)) in entries.iter_mut().zip(other).enumerate() {
let (left, right) = make(index);
*first = left;
second.write(right);
}
}
#[repr(C)]
pub struct Bundle<S> {
layout: alloc::Layout,
fields: S,
}
impl Bundle<()> {
pub const fn try_layout<S: Shape + ?Sized>(
len: usize,
tail_len: usize,
) -> Result<alloc::Layout, Overflow> {
let bounds = Self::bounds::<S>(len, tail_len);
if !bounds.fits() {
return Err(Overflow);
}
Ok(unsafe { bounds.layout() }.pad_to_align())
}
pub(crate) const fn bounds<S: Shape + ?Sized>(len: usize, tail_len: usize) -> Bounds {
Bounds::new(alloc::Layout::new::<()>())
.extend::<S::Root>(len)
.extend::<S::Tail>(tail_len)
.extend::<S::Extra>(len)
.extend::<S::Last>(len)
}
pub(crate) fn try_root<T>(len: usize) -> Result<Bundle<Layout<T>>, Overflow> {
Ok(Bundle {
layout: Layout::<T>::try_layout(len)?,
fields: Layout(marker::PhantomData),
})
}
pub(crate) const unsafe fn root<T>(len: usize) -> Bundle<Layout<T>> {
Bundle {
layout: unsafe { Layout::<T>::layout(len) },
fields: Layout(marker::PhantomData),
}
}
}
impl<S> Bundle<S> {
pub(crate) const fn layout(&self) -> alloc::Layout {
self.layout.pad_to_align()
}
pub fn try_allocate(&self) -> Result<Fields<'_, S>, Exhausted> {
Ok(Fields {
fields: &self.fields,
pointer: LayoutExt::try_allocate(self.layout())?,
})
}
pub unsafe fn deallocate(&self, pointer: ptr::NonNull<u8>) {
unsafe { LayoutExt::deallocate(self.layout(), pointer) }
}
}
impl<S> Bundle<S> {
pub(crate) fn try_tail<T>(self, len: usize) -> Result<Bundle<Tail<S, T>>, Overflow> {
let (layout, offset) = Layout::<T>::try_extend(self.layout, len)?;
Ok(Bundle {
layout,
fields: Tail {
prior: self.fields,
offset,
value: marker::PhantomData,
},
})
}
pub(crate) unsafe fn tail<T>(self, len: usize) -> Bundle<Tail<S, T>> {
let (layout, offset) = unsafe { Layout::<T>::extend(self.layout, len) };
Bundle {
layout,
fields: Tail {
prior: self.fields,
offset,
value: marker::PhantomData,
},
}
}
}
pub struct Fields<'a, S> {
fields: &'a S,
pointer: ptr::NonNull<u8>,
}
impl<T> Fields<'_, Layout<T>> {
pub(crate) const fn root(self) -> ptr::NonNull<T> {
self.pointer.cast()
}
}
impl<'a, S, T> Fields<'a, Tail<S, T>> {
pub fn tail(self) -> ptr::NonNull<T> {
unsafe { self.pointer.add(self.fields.offset) }.cast()
}
pub const fn prior(self) -> Fields<'a, S> {
Fields {
fields: &self.fields.prior,
pointer: self.pointer,
}
}
}
impl<S> Clone for Fields<'_, S> {
fn clone(&self) -> Self {
*self
}
}
impl<S> Copy for Fields<'_, S> {}