//! Contains the data to create an assertion.
//!
//! See the [wiki] or the [`Should`](struct.Should.html) struct's methods for more information.
//!
//! [wiki]: https://gitlab.com/Boiethios/fluid-rs/wikis/assertions

mod left_element;
mod should_impl;

pub use left_element::LeftElement;
pub use should_impl::ShouldImpl;

use super::display::PrintDebug;
use super::information::Information;
use std::fmt::Debug;
use std::ops::Not;

/// Adds the `should` extension that permits to initiate an assertion.
pub trait ShouldExtension<L: Debug> {
    /// Initiates an assertion. Note that this method should not be used alone, but:
    ///
    /// - either with the `fact` or `theory` attribute,
    /// - or with the `fact_!` macro.
    fn should(self) -> Should<L>;
}

/// Main data structure used to create assertions.
/// See its methods for more information about the existing assertions.
#[derive(Debug)]
#[must_use]
pub struct Should<L>(pub(crate) ShouldImpl<L>)
where
    L: Debug;

impl<L> Default for Should<L>
where
    L: Debug,
{
    fn default() -> Self {
        Should(Default::default())
    }
}

impl<L> Not for Should<L>
where
    L: Debug,
{
    type Output = Self;

    fn not(self) -> Self {
        let ShouldImpl {
            left,
            truthness,
            info,
        } = self.0;

        Should(ShouldImpl {
            truthness: truthness.not(),
            left,
            info,
        })
    }
}

impl<L: Debug> ShouldExtension<L> for L {
    fn should(self) -> Should<L> {
        let left_dbg = self.dbg().to_string();

        Should(ShouldImpl {
            left: Some(self),
            truthness: true,
            info: Information::new(None, left_dbg),
        })
    }
}
