Diffstat (limited to 'src/protocol/visitor/recoverable.rs')
-rw-r--r--src/protocol/visitor/recoverable.rs73
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())
+ }
+}