Diffstat (limited to 'src/protocol/visitor/recoverable.rs')
| -rw-r--r-- | src/protocol/visitor/recoverable.rs | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/src/protocol/visitor/recoverable.rs b/src/protocol/visitor/recoverable.rs new file mode 100644 index 0000000..f2d12f7 --- /dev/null +++ b/src/protocol/visitor/recoverable.rs @@ -0,0 +1,73 @@ +use crate::{ + effect::{Effect, Future}, + higher_ranked_type, + hkt::AnySend, + nameable, + protocol::{walker::hint::HintMeta, Visitor}, + Flow, +}; + +use super::Status; + +pub trait Recoverable<'ctx, E: Effect<'ctx>> { + fn visit<'a>( + &'a mut self, + scope: DynRecoverableScope<'a, 'ctx, E>, + ) -> Future<'a, 'ctx, Flow, E>; +} + +pub type DynRecoverable<'a, 'ctx, E> = &'a mut (dyn Recoverable<'ctx, E> + Send + 'a); + +nameable! { + pub struct Name['a, 'ctx, E]; + + impl [E] for DynRecoverable<'a, 'ctx, E> where { + E: Effect<'ctx>, + 'ctx: 'a + } + + impl [E] where DynRecoverable<'a, 'ctx, E> { + E: Effect<'ctx>, + 'ctx: 'a + } +} + +pub trait RecoverableScope<'ctx, E: Effect<'ctx>> { + fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, 'ctx, Flow, E>; +} + +pub type DynRecoverableScope<'a, 'ctx, E> = &'a mut (dyn RecoverableScope<'ctx, E> + Send + 'a); + +higher_ranked_type! { + pub type RecoverableKnownHkt['ctx]: (AnySend) = for<'lt> () +} + +impl<'a, 'ctx: 'a, E: Effect<'ctx>> HintMeta<'ctx> for DynRecoverable<'a, 'ctx, E> { + type Known = RecoverableKnownHkt<'ctx>; + + type Hint = (); +} + +pub fn visit_recoverable<'a, 'ctx, E: Effect<'ctx>>( + visitor: Visitor<'a, 'ctx>, + scope: DynRecoverableScope<'a, 'ctx, E>, +) -> Future<'a, 'ctx, Status, E> { + if let Some(object) = visitor.upcast_mut::<DynRecoverable<'_, 'ctx, E>>() { + // Allow the visitor to give a hint if it wants. + E::map(object.visit(scope), |flow| match flow { + Flow::Continue => { + // The visitor wants the walker to continue to it's normal + // walking. + Status::r#continue() + } + Flow::Break | Flow::Done => { + // The visitor is done (either because of an error or because + // it already used a hint). + Status::r#break() + } + }) + } else { + // If the visitor doesn't support request hint then we continue. + E::ready(Status::skipped()) + } +} |