pub mod walkers; use core::fmt::Debug; use effectful::{ effective::{Canonical, Effective}, environment::Environment, DynBind, SendSync, }; use crate::{protocol::DynVisitor, Flow}; /// A type that can be walked. pub trait Walk<'src, M, E: Environment>: Sized { /// The walker for the type. type Walker: Walker<'src, E>; #[must_use] fn into_walker<'u>(self) -> Canonical<'u, Self::Walker, E> where Self: 'u; } /// Walker for a type. /// /// The `'ctx` lifetime is some lifetime that is longer than `Self`. /// Data from the value may borrow using `'ctx`. /// /// The way to use a walker is as follows. /// - Call [From::from()] with a value to be walked to make a walker. /// - Call [Self::walk()] to walk the value. Data will be sent to the provided /// visitor. pub trait Walker<'src, E: Environment>: DynBind { type Error: DynBind + Debug; /// An arbitrary type the walker is left with after walking. /// /// Its recommended that this is `Self` if the walker is repeatable. type Output: DynBind; /// Walk the value. /// /// The walker should send data to the `visitor` as it walks the value. fn walk<'r>( self, visitor: DynVisitor<'r, 'src, E>, ) -> Canonical<'r, Result, E> where Self: 'r; } pub trait WalkerObjSafe<'src, E: Environment>: DynBind { fn walk<'r>(&'r mut self, visitor: DynVisitor<'r, 'src, E>) -> Canonical<'r, Flow, E>; } pub type DynWalkerObjSafe<'r, 'src, E> = &'r mut dyn WalkerObjSafe<'src, E>; #[derive(SendSync)] enum DynWalkerState<'src, W: Walker<'src, E>, E: Environment> { Walking, Pending(W), Done(W::Output), Err(W::Error), } pub enum DynWalkerError<'src, W: Walker<'src, E>, E: Environment> { NeverWalked(W), /// This can only happen if a panic happens furing the walk and is then caught before calling /// finish.. WalkNeverFinished, Walker(W::Error), WasWalked(W::Output), } #[derive(SendSync)] pub struct DynWalkerAdapter<'src, W: Walker<'src, E>, E: Environment> { state: DynWalkerState<'src, W, E>, } impl<'src, W: Walker<'src, E>, E: Environment> DynWalkerAdapter<'src, W, E> { #[inline(always)] pub fn new(walker: W) -> Self { Self { state: DynWalkerState::Pending(walker), } } #[inline(always)] pub fn finish(self) -> Result> { match self.state { DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished), DynWalkerState::Pending(walker) => Err(DynWalkerError::NeverWalked(walker)), DynWalkerState::Done(value) => Ok(value), DynWalkerState::Err(err) => Err(DynWalkerError::Walker(err)), } } #[inline(always)] pub fn into_inner(self) -> Result> { match self.state { DynWalkerState::Walking => Err(DynWalkerError::WalkNeverFinished), DynWalkerState::Pending(walker) => Ok(walker), DynWalkerState::Done(value) => Err(DynWalkerError::WasWalked(value)), DynWalkerState::Err(err) => Err(DynWalkerError::Walker(err)), } } } impl<'src, W: Walker<'src, E>, E: Environment> WalkerObjSafe<'src, E> for DynWalkerAdapter<'src, W, E> where Self: DynBind, { #[inline(always)] fn walk<'r>(&'r mut self, visitor: DynVisitor<'r, 'src, E>) -> Canonical<'r, Flow, E> { if let DynWalkerState::Pending(walker) = core::mem::replace(&mut self.state, DynWalkerState::Walking) { E::value((self, visitor)) .update_map(walker, |walker, (this, visitor)| { // Walk the walker. walker .walk(visitor.cast()) .map(this, |this, value| match value { Ok(value) => { this.state = DynWalkerState::Done(value); Flow::Done } Err(err) => { this.state = DynWalkerState::Err(err); // Signal that control flow should stop as soon as possible as we // are in an error state. Flow::Err } }) .cast() }) .map((), |_, (_, value)| value) .cast() } else { // Can't do anything if the walker has already been walked. E::value(Flow::Done).cast() } } }