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<S = ()> {
/// 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<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 fn map_skipped<R, F>(self, f: F) -> VisitResult<R>
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<()>, <Eff as InEnvironment>::Env, &'ctx ()>,
>,
),
(),
Update,
(),
VisitResult<()>,
(Update, VisitResult<()>),
Eff,
>;
type IfSkippedF<'ctx, Cap, Update, Eff> =
for<'a> fn(
Cap,
&'a mut Update,
) -> Canonical<'a, VisitResult<()>, <Eff as InEnvironment>::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<Self::Env>,
Update: DynBind<Self::Env>,
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<Self::Env>,
Update: DynBind<Self::Env>,
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<S> PartialEq for VisitResult<S> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Skipped(_), Self::Skipped(_)) => true,
(Self::Control(l0), Self::Control(r0)) => l0 == r0,
_ => false,
}
}
}
impl<S> core::fmt::Debug for VisitResult<S> {
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<S> From<Flow> for VisitResult<S> {
fn from(value: Flow) -> Self {
Self::Control(value)
}
}