blob: 1a78c8d27b8a5d3558d692d31596e12ce8948c60 [file] [log] [blame]
// Copyright (c) 2018, 2022 The predicates-rs Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
//! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types.
use std::fmt;
use crate::reflection;
use crate::utils;
use crate::Predicate;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum EqOps {
Equal,
NotEqual,
}
impl fmt::Display for EqOps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match *self {
EqOps::Equal => "==",
EqOps::NotEqual => "!=",
};
write!(f, "{}", op)
}
}
/// Predicate that returns `true` if `variable` matches the pre-defined `Eq`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{eq, ne}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EqPredicate<T> {
constant: T,
op: EqOps,
}
impl<P, T> Predicate<P> for EqPredicate<T>
where
T: std::borrow::Borrow<P> + fmt::Debug,
P: fmt::Debug + PartialEq + ?Sized,
{
fn eval(&self, variable: &P) -> bool {
match self.op {
EqOps::Equal => variable.eq(self.constant.borrow()),
EqOps::NotEqual => variable.ne(self.constant.borrow()),
}
}
fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
utils::default_find_case(self, expected, variable).map(|case| {
case.add_product(reflection::Product::new(
"var",
utils::DebugAdapter::new(variable).to_string(),
))
})
}
}
impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug {}
impl<T> fmt::Display for EqPredicate<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let palette = crate::Palette::new(f.alternate());
write!(
f,
"{} {} {}",
palette.var("var"),
palette.description(self.op),
palette.expected(utils::DebugAdapter::new(&self.constant)),
)
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::eq(5);
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&10));
///
/// let predicate_fn = predicate::eq("Hello");
/// assert_eq!(true, predicate_fn.eval("Hello"));
/// assert_eq!(false, predicate_fn.eval("Goodbye"));
///
/// let predicate_fn = predicate::eq(String::from("Hello"));
/// assert_eq!(true, predicate_fn.eval("Hello"));
/// assert_eq!(false, predicate_fn.eval("Goodbye"));
/// ```
pub fn eq<T>(constant: T) -> EqPredicate<T>
where
T: fmt::Debug + PartialEq,
{
EqPredicate {
constant,
op: EqOps::Equal,
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// _not_ equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::ne(5);
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&10));
/// ```
pub fn ne<T>(constant: T) -> EqPredicate<T>
where
T: PartialEq + fmt::Debug,
{
EqPredicate {
constant,
op: EqOps::NotEqual,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum OrdOps {
LessThan,
LessThanOrEqual,
GreaterThanOrEqual,
GreaterThan,
}
impl fmt::Display for OrdOps {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let op = match *self {
OrdOps::LessThan => "<",
OrdOps::LessThanOrEqual => "<=",
OrdOps::GreaterThanOrEqual => ">=",
OrdOps::GreaterThan => ">",
};
write!(f, "{}", op)
}
}
/// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{gt, ge, lt, le}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrdPredicate<T> {
constant: T,
op: OrdOps,
}
impl<P, T> Predicate<P> for OrdPredicate<T>
where
T: std::borrow::Borrow<P> + fmt::Debug,
P: fmt::Debug + PartialOrd + ?Sized,
{
fn eval(&self, variable: &P) -> bool {
match self.op {
OrdOps::LessThan => variable.lt(self.constant.borrow()),
OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()),
OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()),
OrdOps::GreaterThan => variable.gt(self.constant.borrow()),
}
}
fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
utils::default_find_case(self, expected, variable).map(|case| {
case.add_product(reflection::Product::new(
"var",
utils::DebugAdapter::new(variable).to_string(),
))
})
}
}
impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug {}
impl<T> fmt::Display for OrdPredicate<T>
where
T: fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let palette = crate::Palette::new(f.alternate());
write!(
f,
"{} {} {}",
palette.var("var"),
palette.description(self.op),
palette.expected(utils::DebugAdapter::new(&self.constant)),
)
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// less than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::lt(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&6));
///
/// let predicate_fn = predicate::lt("b");
/// assert_eq!(true, predicate_fn.eval("a"));
/// assert_eq!(false, predicate_fn.eval("c"));
///
/// let predicate_fn = predicate::lt(String::from("b"));
/// assert_eq!(true, predicate_fn.eval("a"));
/// assert_eq!(false, predicate_fn.eval("c"));
/// ```
pub fn lt<T>(constant: T) -> OrdPredicate<T>
where
T: fmt::Debug + PartialOrd,
{
OrdPredicate {
constant,
op: OrdOps::LessThan,
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// less than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::le(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&6));
/// ```
pub fn le<T>(constant: T) -> OrdPredicate<T>
where
T: PartialOrd + fmt::Debug,
{
OrdPredicate {
constant,
op: OrdOps::LessThanOrEqual,
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate = predicate::ge(5);
/// assert_eq!(false, predicate.eval(&4));
/// assert_eq!(true, predicate.eval(&5));
/// assert_eq!(true, predicate.eval(&6));
/// ```
pub fn ge<T>(constant: T) -> OrdPredicate<T>
where
T: PartialOrd + fmt::Debug,
{
OrdPredicate {
constant,
op: OrdOps::GreaterThanOrEqual,
}
}
/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::gt(5);
/// assert_eq!(false, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&6));
/// ```
pub fn gt<T>(constant: T) -> OrdPredicate<T>
where
T: PartialOrd + fmt::Debug,
{
OrdPredicate {
constant,
op: OrdOps::GreaterThan,
}
}