bool-logic 0.3.3

A library for manipulating and evaluating boolean expressions
Documentation
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Expr<T> {
    Any(Any<T>),
    All(All<T>),
    Not(Not<T>),
    Var(Var<T>),
    Const(bool),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Any<T>(pub Vec<Expr<T>>);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct All<T>(pub Vec<Expr<T>>);

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Not<T>(pub Box<Expr<T>>);

#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct Var<T>(pub T);

pub fn expr<T>(x: impl Into<Expr<T>>) -> Expr<T> {
    x.into()
}

pub fn any<T>(x: impl Into<Any<T>>) -> Any<T> {
    x.into()
}

pub fn all<T>(x: impl Into<All<T>>) -> All<T> {
    x.into()
}

pub fn not<T>(x: impl Into<Expr<T>>) -> Not<T> {
    x.into().into()
}

pub fn var<T>(x: impl Into<Var<T>>) -> Var<T> {
    x.into()
}

#[must_use]
pub fn const_<T>(x: bool) -> Expr<T> {
    x.into()
}

impl<T> Expr<T> {
    pub fn is_any(&self) -> bool {
        matches!(self, Self::Any(_))
    }

    pub fn is_all(&self) -> bool {
        matches!(self, Self::All(_))
    }

    pub fn is_not(&self) -> bool {
        matches!(self, Self::Not(_))
    }

    pub fn is_var(&self) -> bool {
        matches!(self, Self::Var(_))
    }

    pub fn is_const(&self) -> bool {
        matches!(self, Self::Const(_))
    }

    pub fn is_const_true(&self) -> bool {
        matches!(self, Self::Const(true))
    }

    pub fn is_const_false(&self) -> bool {
        matches!(self, Self::Const(false))
    }
}

impl<T> Expr<T> {
    pub fn as_mut_any(&mut self) -> Option<&mut Any<T>> {
        match self {
            Expr::Any(any) => Some(any),
            _ => None,
        }
    }

    pub fn as_mut_all(&mut self) -> Option<&mut All<T>> {
        match self {
            Expr::All(all) => Some(all),
            _ => None,
        }
    }

    pub fn as_mut_not(&mut self) -> Option<&mut Not<T>> {
        match self {
            Expr::Not(not) => Some(not),
            _ => None,
        }
    }

    pub fn as_mut_var(&mut self) -> Option<&mut Var<T>> {
        match self {
            Expr::Var(var) => Some(var),
            _ => None,
        }
    }

    pub fn as_mut_const(&mut self) -> Option<&mut bool> {
        match self {
            Expr::Const(b) => Some(b),
            _ => None,
        }
    }
}

impl<T> Expr<T> {
    pub fn as_any(&self) -> Option<&Any<T>> {
        match self {
            Expr::Any(any) => Some(any),
            _ => None,
        }
    }

    pub fn as_all(&self) -> Option<&All<T>> {
        match self {
            Expr::All(all) => Some(all),
            _ => None,
        }
    }

    pub fn as_not(&self) -> Option<&Not<T>> {
        match self {
            Expr::Not(not) => Some(not),
            _ => None,
        }
    }

    pub fn as_var(&self) -> Option<&Var<T>> {
        match self {
            Expr::Var(var) => Some(var),
            _ => None,
        }
    }

    pub fn as_const(&self) -> Option<&bool> {
        match self {
            Expr::Const(b) => Some(b),
            _ => None,
        }
    }
}

impl<T> Expr<T> {
    pub fn is_empty_not_any(&self) -> bool {
        if let Expr::Not(Not(not)) = self {
            if let Expr::Any(Any(list)) = &**not {
                return list.is_empty();
            }
        }
        false
    }

    pub fn is_empty_not_all(&self) -> bool {
        if let Expr::Not(Not(not)) = self {
            if let Expr::All(All(list)) = &**not {
                return list.is_empty();
            }
        }
        false
    }

    pub fn is_expr_not_var(&self) -> bool {
        if let Expr::Not(Not(not)) = self {
            return not.is_var();
        }
        false
    }

    pub fn as_mut_not_any(&mut self) -> Option<&mut Any<T>> {
        if let Expr::Not(Not(not)) = self {
            if let Expr::Any(any) = &mut **not {
                return Some(any);
            }
        }
        None
    }

    pub fn as_mut_not_all(&mut self) -> Option<&mut All<T>> {
        if let Expr::Not(Not(not)) = self {
            if let Expr::All(any) = &mut **not {
                return Some(any);
            }
        }
        None
    }

    pub fn as_mut_expr_list(&mut self) -> Option<&mut Vec<Expr<T>>> {
        match self {
            Expr::Any(Any(list)) | Expr::All(All(list)) => Some(list),
            _ => None,
        }
    }
}

impl<T> From<Any<T>> for Expr<T> {
    fn from(any: Any<T>) -> Self {
        Expr::Any(any)
    }
}

impl<T> From<All<T>> for Expr<T> {
    fn from(all: All<T>) -> Self {
        Expr::All(all)
    }
}

impl<T> From<Not<T>> for Expr<T> {
    fn from(not: Not<T>) -> Self {
        Expr::Not(not)
    }
}

impl<T> From<Var<T>> for Expr<T> {
    fn from(var: Var<T>) -> Self {
        Expr::Var(var)
    }
}

impl<T> From<bool> for Expr<T> {
    fn from(b: bool) -> Self {
        Expr::Const(b)
    }
}

impl<T> From<Vec<Expr<T>>> for Any<T> {
    fn from(exprs: Vec<Expr<T>>) -> Self {
        Any(exprs)
    }
}

impl<T> From<Vec<Expr<T>>> for All<T> {
    fn from(exprs: Vec<Expr<T>>) -> Self {
        All(exprs)
    }
}

impl<T> From<Box<Expr<T>>> for Not<T> {
    fn from(expr: Box<Expr<T>>) -> Self {
        Not(expr)
    }
}

impl<T> From<Expr<T>> for Not<T> {
    fn from(expr: Expr<T>) -> Self {
        Not(Box::new(expr))
    }
}

impl<T> From<Any<T>> for Not<T> {
    fn from(any: Any<T>) -> Self {
        Not(Box::new(any.into()))
    }
}

impl<T> From<All<T>> for Not<T> {
    fn from(all: All<T>) -> Self {
        Not(Box::new(all.into()))
    }
}

impl<T> From<Var<T>> for Not<T> {
    fn from(var: Var<T>) -> Self {
        Not(Box::new(var.into()))
    }
}

impl<T> From<T> for Not<T> {
    fn from(var: T) -> Self {
        Self::from(Var(var))
    }
}

impl<T> From<T> for Var<T> {
    fn from(var: T) -> Self {
        Var(var)
    }
}

macro_rules! impl_from_tuple {
    ($ty:ident, ()) => {
        impl_from_tuple!(@expand $ty, ());
    };
    ($ty:ident, ($x:tt, $($xs:tt,)*)) => {
        impl_from_tuple!($ty, ($($xs,)*));
        impl_from_tuple!(@expand $ty, ($x, $($xs,)*));
    };
    (@expand $ty:ident, ($($tt:tt,)*)) => {
        #[doc(hidden)] // too ugly
        #[allow(non_camel_case_types)]
        impl<T, $($tt),*> From<($($tt,)*)>  for $ty<T>
        where
            $($tt: Into<Expr<T>>,)*
        {
            fn from(($($tt,)*): ($($tt,)*)) -> Self {
                Self::from(vec![$(Into::into($tt)),*])
            }
        }
    };
}

impl_from_tuple!(
    Any,
    (
        x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, //
        x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, //
        x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35,
    )
);

impl_from_tuple!(
    All,
    (
        x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, //
        x12, x13, x14, x15, x16, x17, x18, x19, x20, x21, x22, x23, //
        x24, x25, x26, x27, x28, x29, x30, x31, x32, x33, x34, x35,
    )
);

impl<T> fmt::Display for Expr<T>
where
    T: fmt::Display,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Expr::Any(Any(any)) => fmt_list(f, "any", any),
            Expr::All(All(all)) => fmt_list(f, "all", all),
            Expr::Not(Not(not)) => write!(f, "not({not})"),
            Expr::Var(Var(x)) => write!(f, "{x}"),
            Expr::Const(b) => write!(f, "{b}"),
        }
    }
}

fn fmt_list<T>(f: &mut fmt::Formatter<'_>, name: &str, list: &[Expr<T>]) -> fmt::Result
where
    T: fmt::Display,
{
    write!(f, "{name}(")?;
    for (i, e) in list.iter().enumerate() {
        if i != 0 {
            write!(f, ", ")?;
        }
        write!(f, "{e}")?;
    }
    write!(f, ")")
}