use core::{mem::MaybeUninit, ops::ControlFlow};
use crate::{
any_trait,
protocol::{
visitor::{Sequence, SequenceScope, Status},
ControlFlowFor, Effect,
},
};
#[cfg(feature = "alloc")]
use crate::protocol::AsyncEffect;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
impl<'ctx, T, const N: usize> crate::Build<'ctx> for [T; N]
where
T: crate::Build<'ctx>,
{
type Builder = Builder<'ctx, T::Builder, N>;
}
#[derive(Debug)]
pub enum ArrayError<E> {
Incomplete,
Item(usize, E),
}
pub struct Builder<'ctx, B: crate::Builder<'ctx>, const N: usize> {
array: MaybeUninit<[B::Value; N]>,
index: usize,
item_err: Option<(usize, B::Error)>,
}
impl<'ctx, B: crate::Builder<'ctx>, const N: usize> Default for Builder<'ctx, B, N> {
fn default() -> Self {
Self {
array: MaybeUninit::uninit(),
index: 0,
item_err: None,
}
}
}
impl<'ctx, B: crate::Builder<'ctx>, const N: usize> crate::Builder<'ctx> for Builder<'ctx, B, N> {
type Error = ArrayError<B::Error>;
type Value = [B::Value; N];
fn as_visitor(&mut self) -> &mut crate::protocol::Visitor<'_, 'ctx> {
self
}
fn build(self) -> Result<Self::Value, Self::Error> {
if let Some((index, err)) = self.item_err {
return Err(ArrayError::Item(index, err));
}
if self.index < N {
Err(ArrayError::Incomplete)
} else {
Ok(unsafe { self.array.assume_init() })
}
}
}
#[cfg(not(feature = "alloc"))]
any_trait! {
impl['a, 'ctx, B: crate::Builder<'ctx>, const N: usize] Builder<'ctx, B, N> = [
dyn Sequence<'ctx> + 'a,
];
}
#[cfg(feature = "alloc")]
any_trait! {
impl['a, 'ctx, B: crate::Builder<'ctx>, const N: usize] Builder<'ctx, B, N> = [
dyn Sequence<'ctx> + 'a,
dyn Sequence<'ctx, AsyncEffect> + 'a,
];
}
impl<'ctx, B: crate::Builder<'ctx>, const N: usize> Sequence<'ctx>
for Builder<'ctx, B, N>
{
#[inline]
fn visit<'a>(&'a mut self, scope: &'a mut dyn SequenceScope<'ctx>) -> ControlFlowFor<'a> {
loop {
// Check if the array is full.
if self.index >= N {
return ControlFlow::Continue(());
}
// Try to build the next value.
let mut builder = B::default();
match scope.next(builder.as_visitor()) {
ControlFlow::Continue(Status::Done) => {
// The sequence is done so the builder wasn't given a value.
// We just throw away the empty builder.
return ControlFlow::Continue(());
}
ControlFlow::Continue(Status::Continue) => match builder.build() {
Ok(value) => {
// Put the value in the array, and move to the next one.
// unsafe {
// maybe_uninit_array(&mut self.array)
// .get_unchecked_mut(self.index)
// .write(value)
// };
unsafe {
let ptr = (self.array.as_mut_ptr() as *mut B::Value).offset(self.index as _);
core::ptr::write(ptr, value);
}
// std::ptr::write(&mut self.array
self.index += 1;
}
Err(err) => {
// Record the item error and return a stop signal.
self.item_err = Some((self.index, err));
return ControlFlow::Break(());
}
},
ControlFlow::Break(()) => {
return ControlFlow::Break(());
}
}
}
}
}
//
// fn maybe_uninit_array<T, const N: usize>(
// array: &mut MaybeUninit<[T; N]>,
// ) -> &mut [MaybeUninit<T>; N] {
// unsafe { &mut *(array as *mut _ as *mut [MaybeUninit<T>; N]) }
// }