use std::{iter, marker, mem, ops, ptr, slice};
use crate::depot::{array, array::prefix, capacity};
pub struct Prefix<'a, 'id, T, const N: usize> {
entries: &'a mut [mem::MaybeUninit<T>; N],
len: array::Len<N>,
brand: marker::PhantomData<*mut capacity::Domain<'id>>,
}
#[must_use = "a prefix slot must be filled or abandoned"]
pub struct Slot<'a, 'b, 'id, T, const N: usize> {
prefix: &'a mut Prefix<'b, 'id, T, N>,
slot: array::Vacancy<N>,
}
impl<'a, T, const N: usize> Prefix<'a, '_, T, N> {
pub fn with<U, R>(
entries: &'a mut [mem::MaybeUninit<U>; N],
run: impl for<'id> FnOnce(&mut Prefix<'a, 'id, T, N>) -> R,
) -> R {
const {
assert!(N <= u8::MAX as usize + 1);
assert!(size_of::<T>() == size_of::<U>(), "size");
assert!(align_of::<T>() == align_of::<U>(), "align");
};
let mut prefix = Prefix {
entries: crate::mem::raw::cast_uninit(entries),
len: array::Len::ZERO,
brand: marker::PhantomData,
};
run(&mut prefix)
}
}
impl<'a, 'id, T, const N: usize> Prefix<'a, 'id, T, N> {
pub fn vacancy(&mut self) -> Option<Slot<'_, 'a, 'id, T, N>> {
let slot = self.len.vacancy()?;
Some(Slot { prefix: self, slot })
}
pub fn as_slice(&self) -> &[T] {
unsafe { self.len.prefix(self.entries).assume_init_ref() }
}
pub const fn extent(&self) -> array::Len<N> {
self.len
}
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { self.len.prefix_mut(self.entries).assume_init_mut() }
}
pub fn get(&self, key: capacity::Key<'id, u8>) -> &T {
unsafe {
self.entries
.get_unchecked(*key.as_inner() as usize)
.assume_init_ref()
}
}
pub fn get_mut(&mut self, key: capacity::Key<'id, u8>) -> &mut T {
unsafe {
self.entries
.get_unchecked_mut(*key.as_inner() as usize)
.assume_init_mut()
}
}
}
impl<'id, T, const N: usize> Slot<'_, '_, 'id, T, N> {
pub fn insert(self, value: T) -> capacity::Key<'id, u8> {
let index = self.slot.index() as u8;
self.slot.get_mut(self.prefix.entries).write(value);
self.prefix.len = self.slot.commit();
capacity::Key::new(unsafe { crate::depot::raw::Proof::new(index) })
}
}
impl<T, const N: usize> Drop for Prefix<'_, '_, T, N> {
fn drop(&mut self) {
crate::depot::raw::Drain::destroy::<false>(self);
}
}
unsafe impl<T, const N: usize> crate::depot::raw::Drain<T> for Prefix<'_, '_, T, N> {
type Slots = [mem::MaybeUninit<T>; N];
fn detach(&mut self) -> (&mut Self::Slots, ops::Range<usize>) {
let len = mem::replace(&mut self.len, array::Len::ZERO);
(self.entries, 0..len.get())
}
}
#[must_use = "dropping a guard releases its initialized prefix"]
pub struct Guard<'a, T, const N: usize, const REVERSE: bool = false, P = ()> {
entries: &'a mut [mem::MaybeUninit<T>; N],
len: usize,
phase: marker::PhantomData<P>,
}
#[derive(Debug)]
pub struct Vacant;
#[derive(Debug)]
pub struct Full;
#[derive(Debug)]
#[repr(transparent)]
#[must_use = "dropping the iterator releases its unread values"]
pub struct IntoIter<'a, T, const REVERSE: bool = false> {
entries: &'a mut [mem::MaybeUninit<T>],
}
impl<'a, T, const N: usize, const REVERSE: bool> Guard<'a, T, N, REVERSE> {
pub fn new(entries: &'a mut mem::MaybeUninit<[T; N]>) -> Self {
let entries = unsafe { &mut *entries.as_mut_ptr().cast() };
Self {
entries,
len: 0,
phase: marker::PhantomData,
}
}
pub fn try_map<'source, U, V, E>(
entries: &'a mut [mem::MaybeUninit<U>; N],
source: &'source Prefix<'_, '_, V, N>,
mut map: impl FnMut(&'source V) -> Result<Option<T>, E>,
) -> Result<Self, (Self, E)> {
let mut guard = Self {
entries: crate::mem::raw::cast_uninit(entries),
len: 0,
phase: marker::PhantomData,
};
for value in source.as_slice() {
let value = match map(value) {
Ok(value) => value,
Err(error) => return Err((guard, error)),
};
if let Some(value) = value {
guard = guard.phase::<Vacant>().insert(value);
}
}
Ok(guard)
}
pub fn next(
self,
) -> ops::ControlFlow<Guard<'a, T, N, REVERSE, Full>, Guard<'a, T, N, REVERSE, Vacant>> {
if self.len < N {
return ops::ControlFlow::Continue(self.phase());
}
ops::ControlFlow::Break(self.phase())
}
}
impl<T, const N: usize, const REVERSE: bool> Guard<'_, T, N, REVERSE, Full> {
pub fn into_array(self) -> [T; N] {
let this = mem::ManuallyDrop::new(self);
unsafe { this.entries.as_ptr().cast::<[T; N]>().read() }
}
pub fn map_with<U, V>(self, values: [U; N], mut map: impl FnMut(T, U) -> V) -> [V; N] {
let this = mem::ManuallyDrop::new(self);
let mut index = 0;
values.map(|other| {
let value = unsafe { this.entries.get_unchecked(index).assume_init_read() };
index += 1;
map(value, other)
})
}
}
impl<'a, T, const N: usize, const REVERSE: bool> Guard<'a, T, N, REVERSE, Vacant> {
pub fn get<'b, U>(&self, values: &'b [U; N]) -> &'b U {
unsafe { values.get_unchecked(self.len) }
}
pub fn get_mut<'b, U>(&self, values: &'b mut [U; N]) -> &'b mut U {
unsafe { values.get_unchecked_mut(self.len) }
}
pub fn zip<'b, 'c, U>(
&'b self,
values: &'c [U; N],
) -> iter::Zip<slice::Iter<'b, T>, slice::Iter<'c, U>> {
let len = self.len;
let values = unsafe { values.get_unchecked(..len) };
self.as_slice().iter().zip(values)
}
pub fn insert(mut self, value: T) -> Guard<'a, T, N, REVERSE> {
unsafe { self.entries.get_unchecked_mut(self.len).write(value) };
self.len += 1;
self.phase()
}
}
impl<T, const N: usize, const REVERSE: bool, P> Drop for Guard<'_, T, N, REVERSE, P> {
fn drop(&mut self) {
crate::depot::raw::Drain::destroy::<REVERSE>(self);
}
}
const _: () = {
assert!(size_of::<Prefix<'static, 'static, u8, 256>>() == 2 * size_of::<usize>());
assert!(size_of::<Guard<'static, u8, 1>>() == 2 * size_of::<usize>());
assert!(size_of::<Guard<'static, u8, 1, false, Vacant>>() == 2 * size_of::<usize>());
assert!(size_of::<Guard<'static, u8, 1, false, Full>>() == 2 * size_of::<usize>());
assert!(size_of::<IntoIter<'static, u8>>() == 2 * size_of::<usize>());
};
impl<'a, T, const N: usize, const REVERSE: bool, P> Guard<'a, T, N, REVERSE, P> {
pub fn as_slice(&self) -> &[T] {
unsafe { slice::from_raw_parts(self.entries.as_ptr().cast(), self.len) }
}
fn into_parts(self) -> (&'a mut [mem::MaybeUninit<T>; N], usize) {
let this = mem::ManuallyDrop::new(self);
let entries = unsafe { ptr::read(&this.entries) };
(entries, this.len)
}
fn phase<Q>(self) -> Guard<'a, T, N, REVERSE, Q> {
let (entries, len) = self.into_parts();
Guard {
entries,
len,
phase: marker::PhantomData,
}
}
}
impl<'a, T, const N: usize, const REVERSE: bool, P> IntoIterator for Guard<'a, T, N, REVERSE, P> {
type Item = T;
type IntoIter = IntoIter<'a, T, REVERSE>;
fn into_iter(self) -> Self::IntoIter {
let (entries, len) = self.into_parts();
let entries = unsafe { entries.get_unchecked_mut(..len) };
IntoIter { entries }
}
}
impl<'a, T> IntoIter<'a, T> {
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe { self.entries.assume_init_mut() }
}
pub(super) fn drain<const N: usize>(source: &'a mut prefix::Prefix<T, N>) -> Self {
let len = mem::replace(&mut source.len, array::Len::ZERO);
Self {
entries: len.prefix_mut(&mut source.entries),
}
}
}
impl<T, const REVERSE: bool> Iterator for IntoIter<'_, T, REVERSE> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
Some(unsafe { self.entries.split_off_first_mut()?.assume_init_read() })
}
fn size_hint(&self) -> (usize, Option<usize>) {
let len = self.entries.len();
(len, Some(len))
}
}
impl<T, const REVERSE: bool> ExactSizeIterator for IntoIter<'_, T, REVERSE> {}
impl<T, const REVERSE: bool> iter::FusedIterator for IntoIter<'_, T, REVERSE> {}
impl<T, const REVERSE: bool> Drop for IntoIter<'_, T, REVERSE> {
fn drop(&mut self) {
crate::depot::raw::Drain::destroy::<REVERSE>(self);
}
}
unsafe impl<T, const REVERSE: bool> crate::depot::raw::Drain<T> for IntoIter<'_, T, REVERSE> {
type Slots = [mem::MaybeUninit<T>];
fn detach(&mut self) -> (&mut Self::Slots, ops::Range<usize>) {
let entries = mem::take(&mut self.entries);
let len = entries.len();
(entries, 0..len)
}
}
unsafe impl<T, const N: usize, const REVERSE: bool, P> crate::depot::raw::Drain<T>
for Guard<'_, T, N, REVERSE, P>
{
type Slots = [mem::MaybeUninit<T>; N];
fn detach(&mut self) -> (&mut Self::Slots, ops::Range<usize>) {
let len = self.len;
self.len = 0;
(self.entries, 0..len)
}
}