pub mod walkers;
use core::ops::ControlFlow;
use crate::{
effect::{Effect, Future},
protocol::Visitor,
};
/// 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,
>;
fn into_walker<E: Effect<'ctx>>(self) -> Self::Walker<E>;
}
pub trait WalkerTypes<'ctx> {
type Error: Send;
/// An arbitrary type the walker is left with after walking.
///
/// Its recommended that this is `Self` if the walker is repeatable.
type Output: Send;
}
/// 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<'ctx>: WalkerTypes<'ctx> + Send {
type Effect: Effect<'ctx>;
/// Walk the value.
///
/// The walker should send data to the `visitor` as it walks the value.
fn walk<'a>(
self,
visitor: Visitor<'a, 'ctx>,
) -> Future<'a, 'ctx, Result<Self::Output, Self::Error>, Self::Effect>
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(())
})
}
}