Last active
July 9, 2022 04:08
-
-
Save barrowsys/ea0cd9e230475c906e41b6c90c8392c6 to your computer and use it in GitHub Desktop.
my ~~cursed~~ neat control flow type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* -------------------- | |
* THIS FILE IS LICENSED UNDER THE FOLLOWING TERMS | |
* | |
* this code may not be used for any purpose. be gay, do crime | |
* | |
* THE FOLLOWING MESSAGE IS NOT A LICENSE | |
* | |
* <barrow@tilde.team> wrote this file. | |
* by reading this text, you are reading "TRANS RIGHTS". | |
* this file and the content within it is the gay agenda. | |
* if we meet some day, and you think this stuff is worth it, | |
* you can buy me a beer, tea, or something stronger. | |
* -Ezra Barrow | |
* -------------------- | |
*/ | |
#![allow( | |
clippy::use_self // theres a lot of From impls here that are harder to read when using Self | |
)] | |
use std::{ | |
borrow::Cow, | |
convert::Infallible, | |
ops::{ControlFlow, FromResidual}, | |
}; | |
type Error = anyhow::Error; | |
type StaticStr = Cow<'static, str>; | |
pub type CrResultOk = ControlFlow<(), StaticStr>; | |
pub type CrResultErr = ControlFlow<anyhow::Error, anyhow::Error>; | |
pub type CrResult = Result<CrResultOk, CrResultErr>; | |
pub type CrFlowBreak = Result<(), anyhow::Error>; | |
pub type CrFlowContinue = Result<StaticStr, anyhow::Error>; | |
pub type CrFlow = ControlFlow<CrFlowBreak, CrFlowContinue>; | |
#[derive(Debug)] | |
pub enum CommandResult { | |
Info(StaticStr), | |
Warning(Error), | |
Fatal(Error), | |
Exit, | |
} | |
impl CommandResult { | |
pub const OK: Self = Self::Info(Cow::Borrowed("")); | |
pub fn into_flow(self) -> CrFlow { | |
self.into() | |
} | |
pub fn into_result(self) -> CrResult { | |
self.into() | |
} | |
pub fn without_err_flow(self) -> Result<CrResultOk, anyhow::Error> { | |
self.into_result().map_err(|cf| match cf { | |
ControlFlow::Continue(e) | ControlFlow::Break(e) => e, | |
}) | |
} | |
} | |
impl From<CrResult> for CommandResult { | |
fn from(f: CrResult) -> Self { | |
f.map(Self::from).map_err(Self::from).into_ok_or_err() | |
} | |
} | |
impl From<CrResultOk> for CommandResult { | |
fn from(f: CrResultOk) -> Self { | |
match f { | |
ControlFlow::Continue(s) => CommandResult::Info(s), | |
ControlFlow::Break(()) => CommandResult::Exit, | |
} | |
} | |
} | |
impl From<CrResultErr> for CommandResult { | |
fn from(f: CrResultErr) -> Self { | |
match f { | |
ControlFlow::Continue(e) => CommandResult::Warning(e), | |
ControlFlow::Break(e) => CommandResult::Fatal(e), | |
} | |
} | |
} | |
impl From<CommandResult> for CrResult { | |
fn from(f: CommandResult) -> CrResult { | |
match f { | |
CommandResult::Info(msg) => Ok(ControlFlow::Continue(msg)), | |
CommandResult::Warning(err) => Err(ControlFlow::Continue(err)), | |
CommandResult::Fatal(error) => Err(ControlFlow::Break(error)), | |
CommandResult::Exit => Ok(ControlFlow::Break(())), | |
} | |
} | |
} | |
impl From<CrFlow> for CommandResult { | |
fn from(f: CrFlow) -> Self { | |
match f { | |
ControlFlow::Continue(Ok(s)) => CommandResult::Info(s), | |
ControlFlow::Break(Ok(())) => CommandResult::Exit, | |
ControlFlow::Continue(Err(e)) => CommandResult::Warning(e), | |
ControlFlow::Break(Err(e)) => CommandResult::Fatal(e), | |
} | |
} | |
} | |
impl From<CrFlowContinue> for CommandResult { | |
fn from(f: CrFlowContinue) -> Self { | |
f.map(CommandResult::Info) | |
.map_err(CommandResult::Warning) | |
.into_ok_or_err() | |
} | |
} | |
impl From<CrFlowBreak> for CommandResult { | |
fn from(f: CrFlowBreak) -> Self { | |
f.map(|_| CommandResult::Exit) | |
.map_err(CommandResult::Fatal) | |
.into_ok_or_err() | |
} | |
} | |
impl From<CommandResult> for CrFlow { | |
fn from(f: CommandResult) -> Self { | |
match f { | |
CommandResult::Info(msg) => ControlFlow::Continue(Ok(msg)), | |
CommandResult::Warning(err) => ControlFlow::Continue(Err(err)), | |
CommandResult::Fatal(error) => ControlFlow::Break(Err(error)), | |
CommandResult::Exit => ControlFlow::Break(Ok(())), | |
} | |
} | |
} | |
impl FromResidual<Result<Infallible, CrResultErr>> for CommandResult { | |
fn from_residual(residual: Result<Infallible, CrResultErr>) -> Self { | |
unsafe { residual.unwrap_err_unchecked().into() } | |
} | |
} | |
pub trait ErrorFlow { | |
type T; | |
fn warn(self) -> Result<Self::T, ControlFlow<anyhow::Error, anyhow::Error>>; | |
fn fatal(self) -> Result<Self::T, ControlFlow<anyhow::Error, anyhow::Error>>; | |
} | |
impl<T> ErrorFlow for Result<T, anyhow::Error> { | |
type T = T; | |
fn warn(self) -> Result<T, ControlFlow<anyhow::Error, anyhow::Error>> { | |
self.map_err(ControlFlow::Continue) | |
} | |
fn fatal(self) -> Result<T, ControlFlow<anyhow::Error, anyhow::Error>> { | |
self.map_err(ControlFlow::Break) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment