use std::fmt;
use yansi::{Paint, Color};
use crate::{route, request, response};
use crate::data::{self, Data, FromData};
use crate::http::Status;
use self::Outcome::*;
#[must_use]
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Outcome<S, E, F> {
Success(S),
Error(E),
Forward(F),
}
impl<S, E, F> Outcome<S, E, F> {
#[inline]
#[track_caller]
pub fn unwrap(self) -> S {
match self {
Success(val) => val,
_ => panic!("unwrapped a non-successful outcome")
}
}
#[inline]
#[track_caller]
pub fn expect(self, message: &str) -> S {
match self {
Success(val) => val,
_ => panic!("unwrapped a non-successful outcome: {}", message)
}
}
#[inline]
pub fn is_success(&self) -> bool {
matches!(self, Success(_))
}
#[inline]
pub fn is_error(&self) -> bool {
matches!(self, Error(_))
}
#[inline]
pub fn is_forward(&self) -> bool {
matches!(self, Forward(_))
}
#[inline]
pub fn succeeded(self) -> Option<S> {
match self {
Success(val) => Some(val),
_ => None
}
}
#[inline]
pub fn failed(self) -> Option<E> {
match self {
Error(val) => Some(val),
_ => None
}
}
#[inline]
pub fn forwarded(self) -> Option<F> {
match self {
Forward(val) => Some(val),
_ => None
}
}
#[inline]
pub fn success_or<T>(self, value: T) -> Result<S, T> {
match self {
Success(val) => Ok(val),
_ => Err(value)
}
}
#[inline]
pub fn success_or_else<T, V: FnOnce() -> T>(self, f: V) -> Result<S, T> {
match self {
Success(val) => Ok(val),
_ => Err(f())
}
}
#[inline]
pub fn as_ref(&self) -> Outcome<&S, &E, &F> {
match *self {
Success(ref val) => Success(val),
Error(ref val) => Error(val),
Forward(ref val) => Forward(val),
}
}
#[inline]
pub fn as_mut(&mut self) -> Outcome<&mut S, &mut E, &mut F> {
match *self {
Success(ref mut val) => Success(val),
Error(ref mut val) => Error(val),
Forward(ref mut val) => Forward(val),
}
}
#[inline]
pub fn map<T, M: FnOnce(S) -> T>(self, f: M) -> Outcome<T, E, F> {
match self {
Success(val) => Success(f(val)),
Error(val) => Error(val),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn map_error<T, M: FnOnce(E) -> T>(self, f: M) -> Outcome<S, T, F> {
match self {
Success(val) => Success(val),
Error(val) => Error(f(val)),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn map_forward<T, M: FnOnce(F) -> T>(self, f: M) -> Outcome<S, E, T> {
match self {
Success(val) => Success(val),
Error(val) => Error(val),
Forward(val) => Forward(f(val)),
}
}
#[inline]
pub fn and_then<T, M: FnOnce(S) -> Outcome<T, E, F>>(self, f: M) -> Outcome<T, E, F> {
match self {
Success(val) => f(val),
Error(val) => Error(val),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn error_then<T, M: FnOnce(E) -> Outcome<S, T, F>>(self, f: M) -> Outcome<S, T, F> {
match self {
Success(val) => Success(val),
Error(val) => f(val),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn forward_then<T, M: FnOnce(F) -> Outcome<S, E, T>>(self, f: M) -> Outcome<S, E, T> {
match self {
Success(val) => Success(val),
Error(val) => Error(val),
Forward(val) => f(val),
}
}
#[inline]
pub fn ok_map_forward<M>(self, f: M) -> Result<S, E>
where M: FnOnce(F) -> Result<S, E>
{
match self {
Outcome::Success(s) => Ok(s),
Outcome::Error(e) => Err(e),
Outcome::Forward(v) => f(v),
}
}
#[inline]
pub fn ok_map_error<M>(self, f: M) -> Result<S, F>
where M: FnOnce(E) -> Result<S, F>
{
match self {
Outcome::Success(s) => Ok(s),
Outcome::Error(e) => f(e),
Outcome::Forward(v) => Err(v),
}
}
}
impl<'a, S: Send + 'a, E: Send + 'a, F: Send + 'a> Outcome<S, E, F> {
#[inline]
pub fn pin(self) -> futures::future::BoxFuture<'a, Self> {
Box::pin(async move { self })
}
}
crate::export! {
macro_rules! try_outcome {
($expr:expr $(,)?) => (match $expr {
$crate::outcome::Outcome::Success(val) => val,
$crate::outcome::Outcome::Error(e) => {
return $crate::outcome::Outcome::Error(::std::convert::From::from(e))
},
$crate::outcome::Outcome::Forward(f) => {
return $crate::outcome::Outcome::Forward(::std::convert::From::from(f))
},
});
}
}
impl<S, E, F> Outcome<S, E, F> {
#[inline]
fn dbg_str(&self) -> &'static str {
match self {
Success(..) => "Success",
Error(..) => "Error",
Forward(..) => "Forward",
}
}
#[inline]
fn color(&self) -> Color {
match self {
Success(..) => Color::Green,
Error(..) => Color::Red,
Forward(..) => Color::Yellow,
}
}
}
pub(crate) struct Display<'a, 'r>(&'a route::Outcome<'r>);
impl<'r> route::Outcome<'r> {
pub(crate) fn log_display(&self) -> Display<'_, 'r> {
impl fmt::Display for Display<'_, '_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", "Outcome: ".primary().bold())?;
let color = self.0.color();
match self.0 {
Success(r) => write!(f, "{}({})", "Success".paint(color), r.status().primary()),
Error(s) => write!(f, "{}({})", "Error".paint(color), s.primary()),
Forward((_, s)) => write!(f, "{}({})", "Forward".paint(color), s.primary()),
}
}
}
Display(self)
}
}
impl<S, E, F> fmt::Debug for Outcome<S, E, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Outcome::{}", self.dbg_str())
}
}
impl<S, E, F> fmt::Display for Outcome<S, E, F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.dbg_str().paint(self.color()))
}
}
pub trait IntoOutcome<Outcome> {
type Error: Sized;
type Forward: Sized;
fn or_error(self, error: Self::Error) -> Outcome;
fn or_forward(self, forward: Self::Forward) -> Outcome;
}
impl<S, E, F> IntoOutcome<Outcome<S, E, F>> for Option<S> {
type Error = E;
type Forward = F;
#[inline]
fn or_error(self, error: E) -> Outcome<S, E, F> {
match self {
Some(val) => Success(val),
None => Error(error)
}
}
#[inline]
fn or_forward(self, forward: F) -> Outcome<S, E, F> {
match self {
Some(val) => Success(val),
None => Forward(forward)
}
}
}
impl<'r, T: FromData<'r>> IntoOutcome<data::Outcome<'r, T>> for Result<T, T::Error> {
type Error = Status;
type Forward = (Data<'r>, Status);
#[inline]
fn or_error(self, error: Status) -> data::Outcome<'r, T> {
match self {
Ok(val) => Success(val),
Err(err) => Error((error, err))
}
}
#[inline]
fn or_forward(self, (data, forward): (Data<'r>, Status)) -> data::Outcome<'r, T> {
match self {
Ok(val) => Success(val),
Err(_) => Forward((data, forward))
}
}
}
impl<S, E> IntoOutcome<request::Outcome<S, E>> for Result<S, E> {
type Error = Status;
type Forward = Status;
#[inline]
fn or_error(self, error: Status) -> request::Outcome<S, E> {
match self {
Ok(val) => Success(val),
Err(err) => Error((error, err))
}
}
#[inline]
fn or_forward(self, status: Status) -> request::Outcome<S, E> {
match self {
Ok(val) => Success(val),
Err(_) => Forward(status)
}
}
}
impl<'r, 'o: 'r> IntoOutcome<route::Outcome<'r>> for response::Result<'o> {
type Error = ();
type Forward = (Data<'r>, Status);
#[inline]
fn or_error(self, _: ()) -> route::Outcome<'r> {
match self {
Ok(val) => Success(val),
Err(status) => Error(status),
}
}
#[inline]
fn or_forward(self, (data, forward): (Data<'r>, Status)) -> route::Outcome<'r> {
match self {
Ok(val) => Success(val),
Err(_) => Forward((data, forward))
}
}
}