Diffstat (limited to 'src/walk/walkers/core/array.rs')
-rw-r--r--src/walk/walkers/core/array.rs95
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)
+ }
+ })
+ }
+}