Diffstat (limited to 'src/walk/walkers/core/array.rs')
| -rw-r--r-- | src/walk/walkers/core/array.rs | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/src/walk/walkers/core/array.rs b/src/walk/walkers/core/array.rs new file mode 100644 index 0000000..73777d0 --- /dev/null +++ b/src/walk/walkers/core/array.rs @@ -0,0 +1,95 @@ +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] { + 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> + 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: &'a mut Visitor<'a, 'ctx>, + ) -> ControlFlowFor<'a, Self::Effect, Self::Output, Self::Error> { + SyncEffect::wrap(async { + if let Some(object) = visitor.upcast_mut::<dyn Sequence<'ctx, W::Effect> + '_>() { + object.visit(&mut self).await; + } + + if let Some((index, error)) = self.item_err { + ControlFlow::Break(WalkerError { index, error }) + } else { + ControlFlow::Continue(()) + } + }) + } +} + +impl<'ctx, T, const N: usize, W: crate::Walker<'ctx> + From<T>> SequenceScope<'ctx, W::Effect> + for Walker<'ctx, T, N, W> +{ + #[inline] + fn next<'a>( + &'a mut self, + visitor: &'a mut Visitor<'a, 'ctx>, + ) -> ControlFlowFor<'a, W::Effect, Status> { + W::Effect::wrap(async { + if let Some(Some(value)) = self.array.get_mut(self.index).map(Option::take) { + self.index += 1; + + let walker = W::from(value); + + match walker.walk(visitor).await { + ControlFlow::Continue(_) => ControlFlow::Continue(Status::Continue), + ControlFlow::Break(err) => { + self.item_err = Some((self.index, err)); + ControlFlow::Continue(Status::Done) + } + } + } else { + ControlFlow::Continue(Status::Done) + } + }) + } +} |