use crate::processor::Processor;
pub enum EarlyReturn<Return, Expr = ()> {
Expr(Expr),
Return(Return),
}
impl<R, E> EarlyReturn<R, E> {
pub fn expr(e: E) -> Self {
EarlyReturn::Expr(e)
}
pub fn ret(r: R) -> Self {
EarlyReturn::Return(r)
}
pub fn swap(self) -> EarlyReturn<E, R> {
match self {
EarlyReturn::Expr(e) => EarlyReturn::Return(e),
EarlyReturn::Return(r) => EarlyReturn::Expr(r),
}
}
pub fn or_return<Expr2>(self, res: EarlyReturn<R, Expr2>) -> EarlyReturn<R, Expr2> {
match self {
EarlyReturn::Expr(_) => res,
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub fn or_expr<Return2>(self, res: EarlyReturn<Return2, E>) -> EarlyReturn<Return2, E> {
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(e),
EarlyReturn::Return(_) => res,
}
}
pub fn map<F: FnOnce(E) -> E2, E2>(self, f: F) -> EarlyReturn<R, E2> {
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(f(e)),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub async fn process_map<P: Processor<E>>(
self,
processor: &P,
) -> EarlyReturn<R, Result<P::Output, P::Error>>
where
E: Send,
{
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(processor.process(e).await),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub fn map_return<F: FnOnce(R) -> R2, R2>(self, f: F) -> EarlyReturn<R2, E> {
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(e),
EarlyReturn::Return(r) => EarlyReturn::Return(f(r)),
}
}
pub fn flat_map<F: FnOnce(E) -> EarlyReturn<R, E2>, E2>(self, f: F) -> EarlyReturn<R, E2> {
match self {
EarlyReturn::Expr(e) => f(e),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub async fn process_flat_map<P: Processor<E, Output = EarlyReturn<R, E2>>, E2>(
self,
processor: &P,
) -> EarlyReturn<R, Result<E2, P::Error>>
where
E: Send,
{
match self {
EarlyReturn::Expr(e) => match processor.process(e).await {
Ok(EarlyReturn::Expr(e2)) => EarlyReturn::Expr(Ok(e2)),
Ok(EarlyReturn::Return(r)) => EarlyReturn::Return(r),
Err(e) => EarlyReturn::Expr(Err(e)),
},
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub fn from_result<Ok>(res: Result<E, R>) -> EarlyReturn<Result<Ok, R>, E> {
match res {
Ok(t) => EarlyReturn::Expr(t),
Err(e) => EarlyReturn::Return(Err(e)),
}
}
}
impl<R, E> EarlyReturn<R, EarlyReturn<R, E>> {
pub fn flatten(self) -> EarlyReturn<R, E> {
match self {
EarlyReturn::Expr(EarlyReturn::Expr(e)) => EarlyReturn::Expr(e),
EarlyReturn::Expr(EarlyReturn::Return(r)) => EarlyReturn::Return(r),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
}
impl<R, E> EarlyReturn<R, &E> {
pub fn copied_expr(self) -> EarlyReturn<R, E>
where
E: Copy,
{
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(*e),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub fn cloned_expr(self) -> EarlyReturn<R, E>
where
E: Clone,
{
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(e.clone()),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub fn owned_expr<Owned>(self) -> EarlyReturn<R, Owned>
where
E: ToOwned<Owned = Owned>,
{
match self {
EarlyReturn::Expr(e) => EarlyReturn::Expr(e.to_owned()),
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
}
impl<Succ, Err, Expr> EarlyReturn<Result<Succ, Err>, Expr> {
pub fn try_map<F: FnOnce(Expr) -> Result<Expr2, Err2>, Expr2, Err2: Into<Err>>(
self,
f: F,
) -> EarlyReturn<Result<Succ, Err>, Expr2> {
match self {
EarlyReturn::Expr(e) => match f(e) {
Ok(e) => EarlyReturn::Expr(e),
Err(e) => EarlyReturn::Return(Err(e.into())),
},
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
pub async fn try_process_map<P: Processor<Expr, Output = Expr2, Error = Err>, Expr2>(
self,
processor: &P,
) -> EarlyReturn<Result<Succ, Err>, Expr2>
where
Expr: Send,
{
match self {
EarlyReturn::Expr(e) => match processor.process(e).await {
Ok(e) => EarlyReturn::Expr(e),
Err(e) => EarlyReturn::Return(Err(e)),
},
EarlyReturn::Return(r) => EarlyReturn::Return(r),
}
}
}
impl<T> EarlyReturn<T, T> {
pub fn safe_unwrap(self) -> T {
match self {
EarlyReturn::Expr(e) => e,
EarlyReturn::Return(r) => r,
}
}
}
#[macro_export]
macro_rules! early_return {
($e:expr) => {
match $e {
$crate::flow::EarlyReturn::Return(r) => return r,
$crate::flow::EarlyReturn::Expr(e) => e,
}
};
}
#[macro_export]
macro_rules! monad_early_return {
($e:expr) => {
match $e {
$crate::flow::EarlyReturn::Return(r) => return $crate::flow::EarlyReturn::Return(r),
$crate::flow::EarlyReturn::Expr(e) => e,
}
};
}