use core::{marker::PhantomData, mem::MaybeUninit, ops::ControlFlow};
use crate::{
any_trait,
protocol::{
visitor::{Sequence, SequenceScope, Status},
AnyTraitObj, AnyTraitSendObj as _, ControlFlowFor, Effect, SyncEffect,
},
AsVisitor, DefaultBuilder,
};
#[cfg(feature = "alloc")]
use crate::protocol::AsyncEffect;
#[cfg(all(feature = "alloc", not(feature = "std")))]
use alloc::boxed::Box;
impl<'ctx, T, const N: usize, E: Effect<'ctx>> crate::Build<'ctx, E> for [T; N]
where
T: crate::Build<'ctx, E>,
<T as crate::Build<'ctx, E>>::Builder: DefaultBuilder<'ctx, E>,
Builder<'ctx, T::Builder, N, E>: AsVisitor<'ctx, E>,
{
type Builder = Builder<'ctx, T::Builder, N, E>;
}
#[derive(Debug)]
pub enum ArrayError<E> {
Incomplete,
Item(usize, E),
}
pub struct Builder<'ctx, B: crate::Builder<'ctx, E>, const N: usize, E: Effect<'ctx>> {
array: MaybeUninit<[B::Value; N]>,
index: usize,
item_err: Option<(usize, B::Error)>,
_marker: PhantomData<fn() -> E>,
}
impl<'ctx, B: crate::DefaultBuilder<'ctx, E>, const N: usize, E: Effect<'ctx>> crate::Builder<'ctx, E>
for Builder<'ctx, B, N, E>
where
Self: AsVisitor<'ctx, E>,
{
type Error = ArrayError<B::Error>;
type Value = [B::Value; N];
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() })
}
}
type Seed = ();
fn from_seed(seed: Self::Seed) -> Self {
Self {
array: MaybeUninit::uninit(),
index: 0,
item_err: None,
_marker: PhantomData,
}
}
}
impl<'ctx, B: crate::DefaultBuilder<'ctx, SyncEffect>, const N: usize> AsVisitor<'ctx, SyncEffect>
for Builder<'ctx, B, N, SyncEffect>
{
fn as_visitor(&mut self) -> crate::protocol::Visitor<'_, 'ctx, SyncEffect> {
AnyTraitObj::from_obj(self)
}
}
// #[cfg(not(feature = "alloc"))]
any_trait! {
impl['a, 'ctx, B: crate::DefaultBuilder<'ctx, E>, const N: usize, E: Effect<'ctx>] Builder<'ctx, B, N, E> = [
dyn Sequence<'ctx> + 'a,
]
}
// #[cfg(feature = "alloc")]
// any_trait! {
// impl['a, 'ctx, B: crate::DefaultBuilder<'ctx>, const N: usize] Builder<'ctx, B, N> = [
// dyn Sequence<'ctx> + 'a,
// dyn Sequence<'ctx, AsyncEffect> + 'a,
// ]
// }
impl<'ctx, B: crate::DefaultBuilder<'ctx, E>, const N: usize, E: Effect<'ctx>> Sequence<'ctx>
for Builder<'ctx, B, N, E>
{
#[inline]
fn visit<'a>(&'a mut self, scope: &'a mut dyn SequenceScope<'ctx>) -> ControlFlowFor<'a, 'ctx> where 'ctx: '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().into_obj()) {
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]) }
// }