use crate::{
any::{TypeName, WithContextLt}, bijective_higher_ranked_type, effect::{Effect, Future}, hkt::AnySizedSend, protocol::{walker::hint::HintMeta, Visitor}, Flow
};
use super::Status;
pub trait Recoverable<'ctx, E: Effect> {
fn visit<'a>(
&'a mut self,
scope: DynRecoverableScope<'a, 'ctx, E>,
) -> Future<'a, Flow, E>;
}
bijective_higher_ranked_type! {
pub type DynRecoverable['ctx][E]: WithContextLt['ctx][]
for<'a>
(dyn Recoverable<'ctx, E> + Send + 'a)
where {
E: Effect
}
}
bijective_higher_ranked_type! {
pub type [][E]: TypeName[][]
for<'ctx>
(DynRecoverable<'ctx, E>)
where {
E: Effect
}
}
pub trait RecoverableScope<'ctx, E: Effect> {
fn new_walk<'a>(&'a mut self, visitor: Visitor<'a, 'ctx>) -> Future<'a, Flow, E>;
}
pub type DynRecoverableScope<'a, 'ctx, E> = &'a mut (dyn RecoverableScope<'ctx, E> + Send + 'a);
bijective_higher_ranked_type! {
pub type RecoverableKnownHkt[][]: AnySizedSend[][] for<'lt> (())
}
impl<'ctx, E: Effect> HintMeta<'ctx> for DynRecoverable<'ctx, E> {
type Known = RecoverableKnownHkt;
type Hint = ();
}
pub fn visit_recoverable<'a, 'ctx, E: Effect>(
visitor: Visitor<'a, 'ctx>,
scope: DynRecoverableScope<'a, 'ctx, E>,
) -> Future<'a, 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())
}
}