use super::predicate::Predicate;
pub trait PredicateConstructor {
type Value;
fn lower_bound_predicate(&self, bound: Self::Value) -> Predicate;
fn upper_bound_predicate(&self, bound: Self::Value) -> Predicate;
fn equality_predicate(&self, bound: Self::Value) -> Predicate;
fn disequality_predicate(&self, bound: Self::Value) -> Predicate;
}
#[macro_export]
macro_rules! predicate {
($($var:ident).+$([$index:expr])? >= $bound:expr) => {{
#[allow(unused, reason = "could be imported at call-site")]
use $crate::predicates::PredicateConstructor;
$($var).+$([$index])?.lower_bound_predicate($bound)
}};
($($var:ident).+$([$index:expr])? <= $bound:expr) => {{
#[allow(unused, reason = "could be imported at call-site")]
use $crate::predicates::PredicateConstructor;
$($var).+$([$index])?.upper_bound_predicate($bound)
}};
($($var:ident).+$([$index:expr])? == $value:expr) => {{
#[allow(unused, reason = "could be imported at call-site")]
use $crate::predicates::PredicateConstructor;
$($var).+$([$index])?.equality_predicate($value)
}};
($($var:ident).+$([$index:expr])? != $value:expr) => {{
#[allow(unused, reason = "could be imported at call-site")]
use $crate::predicates::PredicateConstructor;
$($var).+$([$index])?.disequality_predicate($value)
}};
}
#[cfg(test)]
mod tests {
use crate::variables::DomainId;
#[test]
fn macro_local_identifiers_are_matched() {
let x = DomainId::new(0);
assert_eq!(x, predicate![x >= 2].get_domain());
assert_eq!(x, predicate![x <= 3].get_domain());
assert_eq!(x, predicate![x == 5].get_domain());
assert_eq!(x, predicate![x != 5].get_domain());
assert_eq!(2, predicate![x >= 2].get_right_hand_side());
assert_eq!(3, predicate![x <= 3].get_right_hand_side());
assert_eq!(5, predicate![x == 5].get_right_hand_side());
assert_eq!(5, predicate![x != 5].get_right_hand_side());
assert!(predicate!(x >= 2).is_lower_bound_predicate());
assert!(!predicate!(x >= 2).is_upper_bound_predicate());
assert!(!predicate!(x >= 2).is_equality_predicate());
assert!(!predicate!(x >= 2).is_not_equal_predicate());
assert!(predicate!(x <= 3).is_upper_bound_predicate());
assert!(!predicate!(x <= 3).is_lower_bound_predicate());
assert!(!predicate!(x <= 3).is_equality_predicate());
assert!(!predicate!(x <= 3).is_not_equal_predicate());
assert!(predicate!(x == 5).is_equality_predicate());
assert!(!predicate!(x == 5).is_lower_bound_predicate());
assert!(!predicate!(x == 5).is_upper_bound_predicate());
assert!(!predicate!(x == 5).is_not_equal_predicate());
assert!(predicate!(x != 5).is_not_equal_predicate());
assert!(!predicate!(x != 5).is_lower_bound_predicate());
assert!(!predicate!(x != 5).is_upper_bound_predicate());
assert!(!predicate!(x != 5).is_equality_predicate());
}
#[test]
fn macro_nested_identifiers_are_matched() {
struct Wrapper {
x: DomainId,
}
let wrapper = Wrapper {
x: DomainId::new(0),
};
assert_eq!(wrapper.x, predicate![wrapper.x >= 2].get_domain());
assert_eq!(wrapper.x, predicate![wrapper.x <= 3].get_domain());
assert_eq!(wrapper.x, predicate![wrapper.x == 5].get_domain());
assert_eq!(wrapper.x, predicate![wrapper.x != 5].get_domain());
assert_eq!(2, predicate![wrapper.x >= 2].get_right_hand_side());
assert_eq!(3, predicate![wrapper.x <= 3].get_right_hand_side());
assert_eq!(5, predicate![wrapper.x == 5].get_right_hand_side());
assert_eq!(5, predicate![wrapper.x != 5].get_right_hand_side());
}
#[test]
fn macro_index_expressions_are_matched() {
let wrapper = [DomainId::new(0)];
assert_eq!(wrapper[0], predicate![wrapper[0] >= 2].get_domain());
assert_eq!(wrapper[0], predicate![wrapper[0] <= 3].get_domain());
assert_eq!(wrapper[0], predicate![wrapper[0] == 5].get_domain());
assert_eq!(wrapper[0], predicate![wrapper[0] != 5].get_domain());
assert_eq!(2, predicate![wrapper[0] >= 2].get_right_hand_side());
assert_eq!(3, predicate![wrapper[0] <= 3].get_right_hand_side());
assert_eq!(5, predicate![wrapper[0] == 5].get_right_hand_side());
assert_eq!(5, predicate![wrapper[0] != 5].get_right_hand_side());
}
}