use crate::utils::Utils;
use derive_more::IsVariant;
use std::{
convert::Infallible,
ops::{ControlFlow, FromResidual, Residual, Try},
};
#[derive(Debug, IsVariant)]
pub enum Output<T, E> {
Ok(T),
EndOk,
EndErr(E),
}
impl<T, E> Output<T, E> {
pub fn into_option(self) -> Option<Result<T, E>> {
match self {
Self::Ok(ok) => ok.ok().some(),
Self::EndOk => None,
Self::EndErr(err) => err.err().some(),
}
}
pub fn into_control_flow(self) -> ControlFlow<Output<Infallible, E>, T> {
match self {
Self::Ok(ok) => ok.into_continue(),
Self::EndOk => Output::EndOk.into_break(),
Self::EndErr(err) => err.end_err().into_break(),
}
}
pub fn into_end(self) -> Option<Result<(), E>> {
match self {
Self::Ok(_ok) => None,
Self::EndOk => ().ok().some(),
Self::EndErr(err) => err.err().some(),
}
}
}
impl<T: Default, E> Output<T, E> {
pub fn into_result(self) -> Result<T, E> {
match self {
Self::Ok(ok) => ok.ok(),
Self::EndOk => T::default().ok(),
Self::EndErr(err) => err.err(),
}
}
}
impl<T, E> From<T> for Output<T, E> {
fn from(ok: T) -> Self {
Self::Ok(ok)
}
}
impl<T, E> From<Option<T>> for Output<T, E> {
fn from(option: Option<T>) -> Self {
if let Some(ok) = option {
Self::Ok(ok)
} else {
Self::EndOk
}
}
}
impl<T, E> From<Option<Result<T, E>>> for Output<T, E> {
fn from(opt_res: Option<Result<T, E>>) -> Self {
match opt_res {
Some(Ok(ok)) => Self::Ok(ok),
Some(Err(err)) => Self::EndErr(err),
None => Self::EndOk,
}
}
}
impl<T, E> From<Result<T, E>> for Output<T, E> {
fn from(result: Result<T, E>) -> Self {
match result {
Ok(ok) => Self::Ok(ok),
Err(err) => Self::EndErr(err),
}
}
}
impl<T, E> Residual<T> for Output<Infallible, E> {
type TryType = Output<T, E>;
}
impl<T, E> Try for Output<T, E> {
type Output = T;
type Residual = Output<Infallible, E>;
fn from_output(output: Self::Output) -> Self {
output.into()
}
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
self.into_control_flow()
}
}
impl<T, E2, E: From<E2>> FromResidual<Output<Infallible, E2>> for Output<T, E> {
fn from_residual(residual: Output<Infallible, E2>) -> Self {
match residual {
Output::EndOk => Self::EndOk,
Output::EndErr(err) => err.convert::<E>().end_err(),
}
}
}
impl<T, E2, E: From<E2>> FromResidual<Result<Infallible, E2>> for Output<T, E> {
fn from_residual(residual: Result<Infallible, E2>) -> Self {
match residual {
Err(err) => err.convert::<E>().end_err(),
}
}
}
impl<T, E> FromResidual<Option<Infallible>> for Output<T, E> {
fn from_residual(_residual: Option<Infallible>) -> Self {
Self::EndOk
}
}