use crate::protocol::Effect;
use core::{mem::MaybeUninit, ops::ControlFlow};
use crate::{
any_trait,
protocol::{
visitor::{RequestHint, Sequence, SequenceScope, Status},
walker::{Hint, HintMeta},
ControlFlowFor, SyncEffect, Visitor,
},
};
impl<'ctx, T: crate::Walk<'ctx>, const N: usize> crate::Walk<'ctx> for [T; N]
where
<T as crate::Walk<'ctx>>::Walker: crate::Walker<'ctx, Effect = SyncEffect>,
{
type Walker = Walker<'ctx, T, N, T::Walker>;
}
#[derive(Debug)]
pub struct WalkerError<E> {
pub index: usize,
pub error: E,
}
pub struct Walker<'ctx, T, const N: usize, W: crate::Walker<'ctx>> {
array: [Option<T>; N],
index: usize,
item_err: Option<(usize, W::Error)>,
}
impl<'ctx, T, const N: usize, W: crate::Walker<'ctx> + From<T>> From<[T; N]>
for Walker<'ctx, T, N, W>
{
fn from(value: [T; N]) -> Self {
Self {
array: value.map(Some),
index: 0,
item_err: None,
}
}
}
impl<'ctx, T, const N: usize, W: crate::Walker<'ctx, Effect = SyncEffect> + From<T>>
crate::Walker<'ctx> for Walker<'ctx, T, N, W>
{
type Effect = SyncEffect;
type Error = WalkerError<W::Error>;
type Output = ();
#[inline]
fn walk<'a>(
mut self,
visitor: Visitor<'a, 'ctx, Self::Effect>,
) -> ControlFlowFor<'a, 'ctx, Self::Effect, Self::Output, Self::Error>
where
Self: 'a,
{
if let Some(object) = visitor.upcast_mut::<dyn Sequence<'ctx, W::Effect> + '_>() {
object.visit(&mut self);
}
if let Some((index, error)) = self.item_err {
ControlFlow::Break(WalkerError { index, error })
} else {
ControlFlow::Continue(())
}
}
}
impl<'a, 'ctx: 'a, T, const N: usize, W: crate::Walker<'ctx, Effect = SyncEffect> + From<T>>
SequenceScope<'a, 'ctx> for Walker<'ctx, T, N, W>
{
#[inline]
fn next(
&'a mut self,
visitor: Visitor<'a, 'ctx, SyncEffect>,
) -> ControlFlowFor<'a, 'ctx, W::Effect, Status> {
if self.index >= N {
return ControlFlow::Continue(Status::Done);
}
let value = unsafe {
self.array
.get_unchecked_mut(self.index)
.take()
.unwrap_unchecked()
};
self.index += 1;
let walker = W::from(value);
match walker.walk(visitor) {
ControlFlow::Continue(_) => ControlFlow::Continue(Status::Continue),
ControlFlow::Break(err) => {
self.item_err = Some((self.index, err));
ControlFlow::Continue(Status::Done)
}
}
}
}