assert-rs 0.1.1

An assertion library that uses types and data to fail tests instead of panicking.
Documentation
use super::{Assertion, Debug, Display};

/// A group of assertions, where the first one to fail will short-circuit.
///
/// This can be created using its [`FromIterator`] implementation or the [`AssertAll`] extension trait.
pub struct CollectedAssertion<A: Assertion>(pub Option<A>);

impl<A: Assertion> Display for CollectedAssertion<A> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        match self.0 {
            Some(ref a) => Display::fmt(a, f),
            None => Ok(()),
        }
    }
}

impl<A: Assertion> Debug for CollectedAssertion<A> {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        Display::fmt(self, f)
    }
}

impl<A: Assertion> FromIterator<A> for CollectedAssertion<A> {
    fn from_iter<T: IntoIterator<Item = A>>(iter: T) -> Self {
        Self(iter.into_iter().find(|a| !a.test()))
    }
}

#[cfg(feature = "std")]
impl<A: Assertion> std::process::Termination for CollectedAssertion<A> {
    fn report(self) -> std::process::ExitCode {
        if self.test() {
            std::process::ExitCode::SUCCESS
        } else {
            println!("{self}");
            std::process::ExitCode::FAILURE
        }
    }
}

impl<A: Assertion> Assertion for CollectedAssertion<A> {
    fn test(&self) -> bool {
        self.0.as_ref().is_none_or(Assertion::test)
    }
}

/// Extension trait, blanked implemented for [`Iterator`]s of [`Assertion`]s.
///
/// Adds the [`assert_all`](AssertAll::assert_all) method,
/// which calls the [`collect`](Iterator::collect) method (with fewer generics and turbofish).
pub trait AssertAll {
    type Output: Assertion;

    /// Collect this iterator of [`Assertion`]s into a [`CollectedAssertion`].
    fn assert_all(self) -> CollectedAssertion<Self::Output>
    where
        Self: Sized;
}

impl<I, A> AssertAll for I
where
    I: IntoIterator<Item = A>,
    A: Assertion,
{
    type Output = A;

    fn assert_all(self) -> CollectedAssertion<Self::Output>
    where
        Self: Sized,
    {
        self.into_iter().collect()
    }
}