fickle 0.3.0

Tools for handling fickle (flaky) tests in rust.
Documentation
use std::any::Any;
use std::fmt::{Debug, Display, Formatter};

#[derive(Debug, Clone, Copy)]
pub enum Outcome<T, E, P> {
    Success(T),
    Failure(Failure<E, P>),
}

impl<T, E, P> Outcome<T, E, P> {
    pub fn is_success(&self) -> bool {
        matches!(self, Self::Success(_))
    }
}

impl<T, E, P> Display for Outcome<T, E, P>
where
    E: Display,
    P: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Outcome::Success(_) => "Passed!".to_string(),
                Outcome::Failure(failure) => format!("{}", failure),
            }
        )
    }
}

impl<T, E> From<Result<Result<T, E>, Box<dyn Any + Send>>> for Outcome<T, E, String> {
    fn from(value: Result<Result<T, E>, Box<dyn Any + Send>>) -> Self {
        match value {
            Ok(Ok(success)) => Outcome::Success(success),
            Ok(Err(err)) => Outcome::Failure(Failure::Err(err)),
            Err(pnic) => Outcome::Failure(Failure::Panic(panic_msg(pnic))),
        }
    }
}

impl<T, E> From<Result<T, Box<dyn Any + Send>>> for Outcome<T, E, String> {
    fn from(value: Result<T, Box<dyn Any + Send>>) -> Self {
        match value {
            Ok(success) => Outcome::Success(success),
            Err(pnic) => Outcome::Failure(Failure::Panic(panic_msg(pnic))),
        }
    }
}

fn panic_msg(panic: Box<dyn Any + Send>) -> String {
    (&*panic)
        .downcast_ref::<String>()
        .map_or_else(
            || (&*panic).downcast_ref::<&str>().map(|s| s.to_string()),
            |s| Some(s.to_owned()),
        )
        .unwrap_or_else(|| "Fickle was unable to determine the panic message".into())
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Failure<E, P> {
    Err(E),
    Panic(P),
}

impl<E, P> Display for Failure<E, P>
where
    E: Display,
    P: Debug,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Failure::Err(err) => format!("Failed with error: {}", err),
                Failure::Panic(panic) => format!("Failed with panic: {:?}", panic),
            }
        )
    }
}