use core::{fmt, marker::PhantomData};
use crate::predicate::{Predicate, PredicateExpected};
pub const NOTHING: &str = "nothing";
pub const ANYTHING: &str = "anything";
pub const FALSE: &str = "false";
pub const TRUE: &str = "true";
pub struct False {
private: PhantomData<()>,
}
pub struct True {
private: PhantomData<()>,
}
impl<T: ?Sized> Predicate<T> for False {
fn check(_value: &T) -> bool {
false
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(NOTHING)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(FALSE)
}
}
impl<T: ?Sized> Predicate<T> for True {
fn check(_value: &T) -> bool {
true
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(ANYTHING)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter.write_str(TRUE)
}
}
pub const NOT: &str = "not";
pub struct Not<P: ?Sized> {
predicate: PhantomData<P>,
}
impl<T: ?Sized, P: Predicate<T> + ?Sized> Predicate<T> for Not<P> {
fn check(value: &T) -> bool {
!P::check(value)
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{NOT} ({expected})", expected = P::expected())
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(formatter, "{NOT}<{expected:?}>", expected = P::expected())
}
}
pub const AND: &str = "and";
pub struct And<P: ?Sized, Q: ?Sized> {
left: PhantomData<P>,
right: PhantomData<Q>,
}
impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for And<P, Q> {
fn check(value: &T) -> bool {
P::check(value) && Q::check(value)
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"({left}) {AND} ({right})",
left = P::expected(),
right = Q::expected(),
)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{AND}<{left:?}, {right:?}>",
left = P::expected(),
right = Q::expected(),
)
}
}
pub const OR: &str = "or";
pub struct Or<P: ?Sized, Q: ?Sized> {
left: PhantomData<P>,
right: PhantomData<Q>,
}
impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Or<P, Q> {
fn check(value: &T) -> bool {
P::check(value) || Q::check(value)
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"({left}) {OR} ({right})",
left = P::expected(),
right = Q::expected(),
)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{OR}<{left:?}, {right:?}>",
left = P::expected(),
right = Q::expected(),
)
}
}
pub const XOR: &str = "xor";
pub struct Xor<P: ?Sized, Q: ?Sized> {
left: PhantomData<P>,
right: PhantomData<Q>,
}
impl<T: ?Sized, P: Predicate<T> + ?Sized, Q: Predicate<T> + ?Sized> Predicate<T> for Xor<P, Q> {
fn check(value: &T) -> bool {
P::check(value) ^ Q::check(value)
}
fn expect(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"({left}) {XOR} ({right})",
left = P::expected(),
right = Q::expected(),
)
}
fn expect_code(formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(
formatter,
"{XOR}<{left:?}, {right:?}>",
left = P::expected(),
right = Q::expected(),
)
}
}
pub type Nand<P, Q> = Not<And<P, Q>>;
pub type Nor<P, Q> = Not<Or<P, Q>>;
pub type Xnor<P, Q> = Not<Xor<P, Q>>;
pub type Implies<P, Q> = Or<Not<P>, Q>;
#[macro_export]
macro_rules! not {
($predicate: ty) => {
$crate::logical::Not<$predicate>
};
}
#[macro_export]
macro_rules! and {
($left: ty, $right: ty) => {
$crate::logical::And<$left, $right>
};
($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
$crate::and!($first, $crate::and!($second, $($rest),+))
};
}
#[macro_export]
macro_rules! or {
($left: ty, $right: ty) => {
$crate::logical::Or<$left, $right>
};
($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
$crate::or!($first, $crate::or!($second, $($rest),+))
};
}
#[macro_export]
macro_rules! xor {
($left: ty, $right: ty) => {
$crate::logical::Xor<$left, $right>
};
($first: ty, $second: ty, $($rest: ty),+ $(,)?) => {
$crate::xor!($first, $crate::xor!($second, $($rest),+))
};
}