use std::fmt;
use std::ops::Try;
use yansi::{Paint, Color};
use self::Outcome::*;
#[must_use]
#[derive(Clone, Copy, PartialEq, PartialOrd, Eq, Ord, Hash)]
pub enum Outcome<S, E, F> {
Success(S),
Failure(E),
Forward(F),
}
pub trait IntoOutcome<S, E, F> {
type Failure: Sized;
type Forward: Sized;
fn into_outcome(self, failure: Self::Failure) -> Outcome<S, E, F>;
fn or_forward(self, forward: Self::Forward) -> Outcome<S, E, F>;
}
impl<S, E, F> IntoOutcome<S, E, F> for Option<S> {
type Failure = E;
type Forward = F;
#[inline]
fn into_outcome(self, failure: E) -> Outcome<S, E, F> {
match self {
Some(val) => Success(val),
None => Failure(failure)
}
}
#[inline]
fn or_forward(self, forward: F) -> Outcome<S, E, F> {
match self {
Some(val) => Success(val),
None => Forward(forward)
}
}
}
impl<S, E, F> Outcome<S, E, F> {
#[inline]
pub fn unwrap(self) -> S {
match self {
Success(val) => val,
_ => panic!("Expected a successful outcome!")
}
}
#[inline]
pub fn expect(self, message: &str) -> S {
match self {
Success(val) => val,
_ => panic!("Outcome::expect() failed: {}", message)
}
}
#[inline]
pub fn is_success(&self) -> bool {
match *self {
Success(_) => true,
_ => false
}
}
#[inline]
pub fn is_failure(&self) -> bool {
match *self {
Failure(_) => true,
_ => false
}
}
#[inline]
pub fn is_forward(&self) -> bool {
match *self {
Forward(_) => true,
_ => false
}
}
#[inline]
pub fn succeeded(self) -> Option<S> {
match self {
Success(val) => Some(val),
_ => None
}
}
#[inline]
pub fn failed(self) -> Option<E> {
match self {
Failure(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),
Failure(ref val) => Failure(val),
Forward(ref 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)),
Failure(val) => Failure(val),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn map_failure<T, M: FnOnce(E) -> T>(self, f: M) -> Outcome<S, T, F> {
match self {
Success(val) => Success(val),
Failure(val) => Failure(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),
Failure(val) => Failure(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),
Failure(val) => Failure(val),
Forward(val) => Forward(val),
}
}
#[inline]
pub fn failure_then<T, M: FnOnce(E) -> Outcome<S, T, F>>(self, f: M) -> Outcome<S, T, F> {
match self {
Success(val) => Success(val),
Failure(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),
Failure(val) => Failure(val),
Forward(val) => f(val),
}
}
#[inline]
pub fn as_mut(&mut self) -> Outcome<&mut S, &mut E, &mut F> {
match *self {
Success(ref mut val) => Success(val),
Failure(ref mut val) => Failure(val),
Forward(ref mut val) => Forward(val),
}
}
#[inline]
fn formatting(&self) -> (Color, &'static str) {
match *self {
Success(..) => (Color::Green, "Success"),
Failure(..) => (Color::Red, "Failure"),
Forward(..) => (Color::Yellow, "Forward"),
}
}
}
impl<S, E, F> Try for Outcome<S, E, F> {
type Ok = S;
type Error = Result<F, E>;
fn into_result(self) -> Result<Self::Ok, Self::Error> {
match self {
Success(val) => Ok(val),
Forward(val) => Err(Ok(val)),
Failure(val) => Err(Err(val)),
}
}
fn from_error(val: Self::Error) -> Self {
match val {
Ok(val) => Forward(val),
Err(val) => Failure(val),
}
}
fn from_ok(val: Self::Ok) -> Self {
Success(val)
}
}
impl<S, E, F> fmt::Debug for Outcome<S, E, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Outcome::{}", self.formatting().1)
}
}
impl<S, E, F> fmt::Display for Outcome<S, E, F> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (color, string) = self.formatting();
write!(f, "{}", Paint::default(string).fg(color))
}
}