Diffstat (limited to 'src/protocol/visitor.rs')
| -rw-r--r-- | src/protocol/visitor.rs | 124 |
1 files changed, 123 insertions, 1 deletions
diff --git a/src/protocol/visitor.rs b/src/protocol/visitor.rs index fbcfdd2..6dc58fb 100644 --- a/src/protocol/visitor.rs +++ b/src/protocol/visitor.rs @@ -1,4 +1,10 @@ -use crate::Flow; +use core::ops::ControlFlow; + +use crate::{ + effect::{Effective, EffectiveExt as _, ErasedEffective, Ss}, + never::Never, + Flow, Status, +}; mod recoverable; mod request_hint; @@ -25,6 +31,122 @@ pub enum VisitResult<S> { Control(Flow), } +impl<S> VisitResult<S> { + 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<Flow> { + match self { + VisitResult::Skipped(_) => None, + VisitResult::Control(flow) => Some(flow), + } + } + + pub fn dont_break_if_skipped(self) -> Option<Status> { + 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<Status> { + 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<Status> { + match self { + VisitResult::Skipped(_) => None, + VisitResult::Control(Flow::Continue) => None, + VisitResult::Control(Flow::Done) => None, + VisitResult::Control(Flow::Err) => Some(Status::Err), + } + } +} + +pub trait EffectiveVisitExt<'lt>: Effective<'lt> { + fn if_skipped<'ctx: 'lt, 'wrap, Ctx: Ss, F: Ss>( + self, + f: F, + ) -> ErasedEffective<'wrap, (Ctx, VisitResult<()>), Self::Effect> + where + Self: Effective<'lt, Output = (Ctx, VisitResult<()>)>, + F: for<'temp> FnOnce( + &'temp mut Ctx, + ) + -> ErasedEffective<'temp, VisitResult<()>, Self::Effect, &'ctx ()>, + 'lt: 'wrap, + { + self.r#do( + |(ctx, v)| { + ( + ctx, + match v { + VisitResult::Skipped(()) => ControlFlow::Continue(()), + v => ControlFlow::Break(v), + }, + ) + }, + |ctx, ()| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |ctx, _, v| (ctx, v), + ) + } + + fn if_not_finished<'ctx: 'lt, 'wrap, Ctx: Ss, F: Ss>( + self, + f: F, + ) -> ErasedEffective<'wrap, (Ctx, VisitResult<()>), Self::Effect> + where + Self: Effective<'lt, Output = (Ctx, VisitResult<()>)>, + F: for<'temp> FnOnce( + &'temp mut Ctx, + ) + -> ErasedEffective<'temp, VisitResult<()>, Self::Effect, &'ctx ()>, + 'lt: 'wrap, + { + self.r#do( + |(ctx, v)| { + ( + ctx, + match v { + VisitResult::Skipped(()) | VisitResult::Control(Flow::Continue) => { + ControlFlow::Continue(()) + } + v => ControlFlow::Break(v), + }, + ) + }, + |ctx, ()| f(ctx).cast(), + |_, v| ControlFlow::<_, Never>::Break(v), + |_, _| unreachable!(), + |_, _, _: Never| unreachable!(), + |ctx, _, v| (ctx, v), + ) + } +} + +impl<'lt, T: Effective<'lt>> EffectiveVisitExt<'lt> for T {} + impl<S> PartialEq for VisitResult<S> { fn eq(&self, other: &Self) -> bool { match (self, other) { |