use super::{BoolExpr, BooleanTest, Field, FieldRef, ValueExpr};
#[inline]
pub const fn true_() -> BoolExpr {
BoolExpr::Constant(true)
}
#[inline]
pub const fn false_() -> BoolExpr {
BoolExpr::Constant(false)
}
pub fn and(exprs: impl IntoIterator<Item = BoolExpr>) -> BoolExpr {
BoolExpr::and(exprs)
}
pub fn or(exprs: impl IntoIterator<Item = BoolExpr>) -> BoolExpr {
BoolExpr::or(exprs)
}
pub fn exists(stmt: impl Into<crate::Stmt>) -> BoolExpr {
BoolExpr::Exists(Box::new(stmt.into()))
}
#[inline]
pub fn not(expr: BoolExpr) -> BoolExpr {
BoolExpr::negate(expr)
}
impl BoolExpr {
pub fn and(exprs: impl IntoIterator<Item = BoolExpr>) -> Self {
Self::And(flatten_and(exprs))
}
pub fn or(exprs: impl IntoIterator<Item = BoolExpr>) -> Self {
Self::Or(flatten_or(exprs))
}
#[inline]
pub fn negate(expr: BoolExpr) -> Self {
Self::Not(Box::new(expr))
}
pub(crate) fn and_pair(left: Self, right: Self) -> Self {
match (left, right) {
(BoolExpr::And(mut left), BoolExpr::And(right))
if !left.is_empty() && !right.is_empty() =>
{
left.extend(right);
Self::And(left)
}
(BoolExpr::And(mut left), right) if !left.is_empty() => {
left.push(right);
Self::And(left)
}
(left, BoolExpr::And(right)) if !right.is_empty() => {
let mut exprs = Vec::with_capacity(right.len() + 1);
exprs.push(left);
exprs.extend(right);
Self::And(exprs)
}
(left, right) => Self::And(vec![left, right]),
}
}
#[inline]
pub(crate) fn and_option(current: Option<Self>, next: Self) -> Self {
match current {
Some(existing) => Self::and_pair(existing, next),
None => next,
}
}
pub(crate) fn or_pair(left: Self, right: Self) -> Self {
match (left, right) {
(BoolExpr::Or(mut left), BoolExpr::Or(right))
if !left.is_empty() && !right.is_empty() =>
{
left.extend(right);
Self::Or(left)
}
(BoolExpr::Or(mut left), right) if !left.is_empty() => {
left.push(right);
Self::Or(left)
}
(left, BoolExpr::Or(right)) if !right.is_empty() => {
let mut exprs = Vec::with_capacity(right.len() + 1);
exprs.push(left);
exprs.extend(right);
Self::Or(exprs)
}
(left, right) => Self::Or(vec![left, right]),
}
}
#[inline]
pub(crate) fn or_option(current: Option<Self>, next: Self) -> Self {
match current {
Some(existing) => Self::or_pair(existing, next),
None => next,
}
}
}
fn flatten_and(exprs: impl IntoIterator<Item = BoolExpr>) -> Vec<BoolExpr> {
let exprs = exprs.into_iter();
let mut flattened = Vec::with_capacity(exprs.size_hint().0);
for expr in exprs {
match expr {
BoolExpr::And(inner) if !inner.is_empty() => flattened.extend(inner),
other => flattened.push(other),
}
}
flattened
}
fn flatten_or(exprs: impl IntoIterator<Item = BoolExpr>) -> Vec<BoolExpr> {
let exprs = exprs.into_iter();
let mut flattened = Vec::with_capacity(exprs.size_hint().0);
for expr in exprs {
match expr {
BoolExpr::Or(inner) if !inner.is_empty() => flattened.extend(inner),
other => flattened.push(other),
}
}
flattened
}
impl ValueExpr {
#[inline]
pub fn is_true(self) -> BoolExpr {
self.boolean_test(BooleanTest::True, false)
}
#[inline]
pub fn is_not_true(self) -> BoolExpr {
self.boolean_test(BooleanTest::True, true)
}
#[inline]
pub fn is_false(self) -> BoolExpr {
self.boolean_test(BooleanTest::False, false)
}
#[inline]
pub fn is_not_false(self) -> BoolExpr {
self.boolean_test(BooleanTest::False, true)
}
#[inline]
pub fn is_unknown(self) -> BoolExpr {
self.boolean_test(BooleanTest::Unknown, false)
}
#[inline]
pub fn is_not_unknown(self) -> BoolExpr {
self.boolean_test(BooleanTest::Unknown, true)
}
fn boolean_test(self, test: BooleanTest, negated: bool) -> BoolExpr {
BoolExpr::is_boolean(self, test, negated)
}
}
macro_rules! boolean_field_tests {
() => {
pub fn is_true(self) -> BoolExpr {
self.expr().is_true()
}
pub fn is_not_true(self) -> BoolExpr {
self.expr().is_not_true()
}
pub fn is_false(self) -> BoolExpr {
self.expr().is_false()
}
pub fn is_not_false(self) -> BoolExpr {
self.expr().is_not_false()
}
pub fn is_unknown(self) -> BoolExpr {
self.expr().is_unknown()
}
pub fn is_not_unknown(self) -> BoolExpr {
self.expr().is_not_unknown()
}
};
}
impl Field<bool> {
boolean_field_tests!();
}
impl FieldRef<bool> {
boolean_field_tests!();
}