Diffstat (limited to 'src/walk.rs')
| -rw-r--r-- | src/walk.rs | 80 |
1 files changed, 79 insertions, 1 deletions
diff --git a/src/walk.rs b/src/walk.rs index f0c5c65..a119965 100644 --- a/src/walk.rs +++ b/src/walk.rs @@ -1,5 +1,7 @@ pub mod walkers; +use core::ops::ControlFlow; + use crate::{ effect::{Effect, Future}, protocol::Visitor, @@ -8,7 +10,12 @@ use crate::{ /// A type that can be walked. pub trait Walk<'ctx>: WalkerTypes<'ctx> + Sized { /// The walker for the type. - type Walker<E: Effect<'ctx>>: Walker<'ctx, Error = Self::Error, Output = Self::Output, Effect = E>; + type Walker<E: Effect<'ctx>>: Walker< + 'ctx, + Error = Self::Error, + Output = Self::Output, + Effect = E, + >; fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>; } @@ -44,3 +51,74 @@ pub trait Walker<'ctx>: WalkerTypes<'ctx> + Send { where Self: 'a; } + +pub trait DynWalker<'ctx>: Send { + type Effect: Effect<'ctx>; + + fn walk<'a>( + &'a mut self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a; +} + +enum DynWalkerState<'ctx, W: WalkerTypes<'ctx>> { + Walking, + Pending(W), + Done(Result<W::Output, W::Error>), +} + +pub enum DynWalkerError<'ctx, W: WalkerTypes<'ctx>> { + NeverWalked(W), + + /// This can only happen if a panic happens furing the walk and is then caught before calling + /// finish.. + WalkNeverFinished, + + Walker(W::Error), +} + +pub struct DynWalkerAdapter<'ctx, W: WalkerTypes<'ctx>> { + state: DynWalkerState<'ctx, W>, +} + +impl<'ctx, W: WalkerTypes<'ctx>> DynWalkerAdapter<'ctx, W> { + pub fn new(walker: W) -> Self { + Self { + state: DynWalkerState::Pending(walker), + } + } + + pub fn finish(self) -> Result<W::Output, DynWalkerError<'ctx, W>> { + match self.state { + DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished), + DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)), + DynWalkerState::Done(result) => result.map_err(DynWalkerError::Walker), + } + } +} + +impl<'ctx, W: Walker<'ctx>> DynWalker<'ctx> for DynWalkerAdapter<'ctx, W> { + type Effect = W::Effect; + + fn walk<'a>( + &'a mut self, + visitor: Visitor<'a, 'ctx>, + ) -> Future<'a, 'ctx, ControlFlow<(), ()>, Self::Effect> + where + Self: 'a, + { + Self::Effect::wrap(async { + if let DynWalkerState::Pending(walker) = + core::mem::replace(&mut self.state, DynWalkerState::Walking) + { + // Walk the walker. + self.state = DynWalkerState::Done(walker.walk(visitor).await); + } else { + // Can't do anything if the walker has already been walked. + } + ControlFlow::Continue(()) + }) + } +} |