use core::ops::ControlFlow; use crate::{Flow, Status}; mod recoverable; mod request_hint; mod sequence; mod tag; mod value; use effectful::{ bound::HasSendAndSync, effective::{Canonical, Effective, UpdatePartial}, environment::{Environment, InEnvironment}, DynBind, SendSync, }; pub use recoverable::*; pub use request_hint::*; pub use sequence::*; pub use tag::*; pub use value::*; #[derive(Copy, Clone, SendSync)] #[must_use] pub enum VisitResult { /// The protocol was not used. /// /// This either means the visitor doesn't support the protocol at all, or /// it didn't want to use the protocol right now. Skipped(S), /// How control flow should proceed. Control(Flow), } impl VisitResult { pub fn unit_skipped(self) -> VisitResult<()> { match self { VisitResult::Skipped(_) => VisitResult::Skipped(()), VisitResult::Control(flow) => VisitResult::Control(flow), } } pub fn to_status(self) -> Status { match self { VisitResult::Skipped(_) => Status::Ok, VisitResult::Control(flow) => flow.to_status(), } } pub fn to_flow(self) -> Option { match self { VisitResult::Skipped(_) => None, VisitResult::Control(flow) => Some(flow), } } pub fn dont_break_if_skipped(self) -> Option { match self { VisitResult::Skipped(_) => None, VisitResult::Control(Flow::Continue) => Some(Status::Ok), VisitResult::Control(Flow::Done) => Some(Status::Ok), VisitResult::Control(Flow::Err) => Some(Status::Err), } } pub fn break_if_done_or_err(self) -> Option { match self { VisitResult::Skipped(_) => None, VisitResult::Control(Flow::Continue) => None, VisitResult::Control(Flow::Done) => Some(Status::Ok), VisitResult::Control(Flow::Err) => Some(Status::Err), } } pub fn break_if_err(self) -> Option { match self { VisitResult::Skipped(_) => None, VisitResult::Control(Flow::Continue) => None, VisitResult::Control(Flow::Done) => None, VisitResult::Control(Flow::Err) => Some(Status::Err), } } pub fn map_skipped(self, f: F) -> VisitResult where F: FnOnce(S) -> R, { match self { VisitResult::Skipped(s) => VisitResult::Skipped(f(s)), VisitResult::Control(flow) => VisitResult::Control(flow), } } } pub type IfSkippedEffective<'ctx, 'lt, 'wrap, Cap, Update, Eff> = UpdatePartial< 'wrap, 'lt, (), ( Cap, HasSendAndSync< for<'a> fn( Cap, &'a mut Update, ) -> Canonical<'a, VisitResult<()>, ::Env, &'ctx ()>, >, ), (), Update, (), VisitResult<()>, (Update, VisitResult<()>), Eff, >; type IfSkippedF<'ctx, Cap, Update, Eff> = for<'a> fn( Cap, &'a mut Update, ) -> Canonical<'a, VisitResult<()>, ::Env, &'ctx ()>; pub trait EffectiveVisitExt<'lt>: Effective<'lt> { fn if_skipped<'ctx, 'wrap, Cap, Update>( self, cap: Cap, f: IfSkippedF<'ctx, Cap, Update, Self>, ) -> IfSkippedEffective<'ctx, 'lt, 'wrap, Cap, Update, Self> where Cap: DynBind, Update: DynBind, Self: Effective<'lt, Output = (Update, VisitResult<()>)>, 'ctx: 'lt, 'lt: 'wrap, { self.update_partial( (), |_, (update, result)| match result { VisitResult::Skipped(()) => (update, ControlFlow::Continue(())), VisitResult::Control(_) => (update, ControlFlow::Break(result)), }, (cap, HasSendAndSync(f)), |(cap, HasSendAndSync(f)), update, ()| f(cap, update).cast().into_raw(), (), |_, update, out| (update, out), ) } fn if_not_finished<'ctx, 'wrap, Cap, Update>( self, cap: Cap, f: IfSkippedF<'ctx, Cap, Update, Self>, ) -> IfSkippedEffective<'ctx, 'lt, 'wrap, Cap, Update, Self> where Cap: DynBind, Update: DynBind, Self: Effective<'lt, Output = (Update, VisitResult<()>)>, 'ctx: 'lt, 'lt: 'wrap, { self.update_partial( (), |_, (update, result)| match result { VisitResult::Skipped(()) | VisitResult::Control(Flow::Continue) => { (update, ControlFlow::Continue(())) } VisitResult::Control(_) => (update, ControlFlow::Break(result)), }, (cap, HasSendAndSync(f)), |(cap, HasSendAndSync(f)), update, ()| f(cap, update).cast().into_raw(), (), |_, update, out| (update, out), ) } } impl<'lt, T: Effective<'lt>> EffectiveVisitExt<'lt> for T {} impl PartialEq for VisitResult { fn eq(&self, other: &Self) -> bool { match (self, other) { (Self::Skipped(_), Self::Skipped(_)) => true, (Self::Control(l0), Self::Control(r0)) => l0 == r0, _ => false, } } } impl core::fmt::Debug for VisitResult { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self { Self::Skipped(_) => f.debug_tuple("Skipped").finish(), Self::Control(arg0) => f.debug_tuple("Control").field(arg0).finish(), } } } impl From for VisitResult { fn from(value: Flow) -> Self { Self::Control(value) } }