predicates/
ord.rs

1// Copyright (c) 2018, 2022 The predicates-rs Project Developers.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/license/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types.
10
11use std::fmt;
12
13use crate::reflection;
14use crate::utils;
15use crate::Predicate;
16
17#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18enum EqOps {
19    Equal,
20    NotEqual,
21}
22
23impl fmt::Display for EqOps {
24    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25        let op = match *self {
26            EqOps::Equal => "==",
27            EqOps::NotEqual => "!=",
28        };
29        write!(f, "{op}")
30    }
31}
32
33/// Predicate that returns `true` if `variable` matches the pre-defined `Eq`
34/// value, otherwise returns `false`.
35///
36/// This is created by the `predicate::{eq, ne}` functions.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct EqPredicate<T> {
39    constant: T,
40    op: EqOps,
41}
42
43impl<P, T> Predicate<P> for EqPredicate<T>
44where
45    T: std::borrow::Borrow<P> + fmt::Debug,
46    P: fmt::Debug + PartialEq + ?Sized,
47{
48    fn eval(&self, variable: &P) -> bool {
49        match self.op {
50            EqOps::Equal => variable.eq(self.constant.borrow()),
51            EqOps::NotEqual => variable.ne(self.constant.borrow()),
52        }
53    }
54
55    fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
56        utils::default_find_case(self, expected, variable).map(|case| {
57            case.add_product(reflection::Product::new(
58                "var",
59                utils::DebugAdapter::new(variable).to_string(),
60            ))
61        })
62    }
63}
64
65impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug {}
66
67impl<T> fmt::Display for EqPredicate<T>
68where
69    T: fmt::Debug,
70{
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        let palette = crate::Palette::new(f.alternate());
73        write!(
74            f,
75            "{} {} {}",
76            palette.var("var"),
77            palette.description(self.op),
78            palette.expected(utils::DebugAdapter::new(&self.constant)),
79        )
80    }
81}
82
83/// Creates a new predicate that will return `true` when the given `variable` is
84/// equal to a pre-defined value.
85///
86/// # Examples
87///
88/// ```
89/// use predicates::prelude::*;
90///
91/// let predicate_fn = predicate::eq(5);
92/// assert_eq!(true, predicate_fn.eval(&5));
93/// assert_eq!(false, predicate_fn.eval(&10));
94///
95/// let predicate_fn = predicate::eq("Hello");
96/// assert_eq!(true, predicate_fn.eval("Hello"));
97/// assert_eq!(false, predicate_fn.eval("Goodbye"));
98///
99/// let predicate_fn = predicate::eq(String::from("Hello"));
100/// assert_eq!(true, predicate_fn.eval("Hello"));
101/// assert_eq!(false, predicate_fn.eval("Goodbye"));
102/// ```
103pub fn eq<T>(constant: T) -> EqPredicate<T>
104where
105    T: fmt::Debug + PartialEq,
106{
107    EqPredicate {
108        constant,
109        op: EqOps::Equal,
110    }
111}
112
113/// Creates a new predicate that will return `true` when the given `variable` is
114/// _not_ equal to a pre-defined value.
115///
116/// # Examples
117///
118/// ```
119/// use predicates::prelude::*;
120///
121/// let predicate_fn = predicate::ne(5);
122/// assert_eq!(false, predicate_fn.eval(&5));
123/// assert_eq!(true, predicate_fn.eval(&10));
124/// ```
125pub fn ne<T>(constant: T) -> EqPredicate<T>
126where
127    T: PartialEq + fmt::Debug,
128{
129    EqPredicate {
130        constant,
131        op: EqOps::NotEqual,
132    }
133}
134
135#[derive(Clone, Copy, Debug, PartialEq, Eq)]
136enum OrdOps {
137    LessThan,
138    LessThanOrEqual,
139    GreaterThanOrEqual,
140    GreaterThan,
141}
142
143impl fmt::Display for OrdOps {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        let op = match *self {
146            OrdOps::LessThan => "<",
147            OrdOps::LessThanOrEqual => "<=",
148            OrdOps::GreaterThanOrEqual => ">=",
149            OrdOps::GreaterThan => ">",
150        };
151        write!(f, "{op}")
152    }
153}
154
155/// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
156/// value, otherwise returns `false`.
157///
158/// This is created by the `predicate::{gt, ge, lt, le}` functions.
159#[derive(Debug, Clone, Copy, PartialEq, Eq)]
160pub struct OrdPredicate<T> {
161    constant: T,
162    op: OrdOps,
163}
164
165impl<P, T> Predicate<P> for OrdPredicate<T>
166where
167    T: std::borrow::Borrow<P> + fmt::Debug,
168    P: fmt::Debug + PartialOrd + ?Sized,
169{
170    fn eval(&self, variable: &P) -> bool {
171        match self.op {
172            OrdOps::LessThan => variable.lt(self.constant.borrow()),
173            OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()),
174            OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()),
175            OrdOps::GreaterThan => variable.gt(self.constant.borrow()),
176        }
177    }
178
179    fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
180        utils::default_find_case(self, expected, variable).map(|case| {
181            case.add_product(reflection::Product::new(
182                "var",
183                utils::DebugAdapter::new(variable).to_string(),
184            ))
185        })
186    }
187}
188
189impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug {}
190
191impl<T> fmt::Display for OrdPredicate<T>
192where
193    T: fmt::Debug,
194{
195    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
196        let palette = crate::Palette::new(f.alternate());
197        write!(
198            f,
199            "{} {} {}",
200            palette.var("var"),
201            palette.description(self.op),
202            palette.expected(utils::DebugAdapter::new(&self.constant)),
203        )
204    }
205}
206
207/// Creates a new predicate that will return `true` when the given `variable` is
208/// less than a pre-defined value.
209///
210/// # Examples
211///
212/// ```
213/// use predicates::prelude::*;
214///
215/// let predicate_fn = predicate::lt(5);
216/// assert_eq!(true, predicate_fn.eval(&4));
217/// assert_eq!(false, predicate_fn.eval(&6));
218///
219/// let predicate_fn = predicate::lt("b");
220/// assert_eq!(true, predicate_fn.eval("a"));
221/// assert_eq!(false, predicate_fn.eval("c"));
222///
223/// let predicate_fn = predicate::lt(String::from("b"));
224/// assert_eq!(true, predicate_fn.eval("a"));
225/// assert_eq!(false, predicate_fn.eval("c"));
226/// ```
227pub fn lt<T>(constant: T) -> OrdPredicate<T>
228where
229    T: fmt::Debug + PartialOrd,
230{
231    OrdPredicate {
232        constant,
233        op: OrdOps::LessThan,
234    }
235}
236
237/// Creates a new predicate that will return `true` when the given `variable` is
238/// less than or equal to a pre-defined value.
239///
240/// # Examples
241///
242/// ```
243/// use predicates::prelude::*;
244///
245/// let predicate_fn = predicate::le(5);
246/// assert_eq!(true, predicate_fn.eval(&4));
247/// assert_eq!(true, predicate_fn.eval(&5));
248/// assert_eq!(false, predicate_fn.eval(&6));
249/// ```
250pub fn le<T>(constant: T) -> OrdPredicate<T>
251where
252    T: PartialOrd + fmt::Debug,
253{
254    OrdPredicate {
255        constant,
256        op: OrdOps::LessThanOrEqual,
257    }
258}
259
260/// Creates a new predicate that will return `true` when the given `variable` is
261/// greater than or equal to a pre-defined value.
262///
263/// # Examples
264///
265/// ```
266/// use predicates::prelude::*;
267///
268/// let predicate = predicate::ge(5);
269/// assert_eq!(false, predicate.eval(&4));
270/// assert_eq!(true, predicate.eval(&5));
271/// assert_eq!(true, predicate.eval(&6));
272/// ```
273pub fn ge<T>(constant: T) -> OrdPredicate<T>
274where
275    T: PartialOrd + fmt::Debug,
276{
277    OrdPredicate {
278        constant,
279        op: OrdOps::GreaterThanOrEqual,
280    }
281}
282
283/// Creates a new predicate that will return `true` when the given `variable` is
284/// greater than a pre-defined value.
285///
286/// # Examples
287///
288/// ```
289/// use predicates::prelude::*;
290///
291/// let predicate_fn = predicate::gt(5);
292/// assert_eq!(false, predicate_fn.eval(&4));
293/// assert_eq!(false, predicate_fn.eval(&5));
294/// assert_eq!(true, predicate_fn.eval(&6));
295/// ```
296pub fn gt<T>(constant: T) -> OrdPredicate<T>
297where
298    T: PartialOrd + fmt::Debug,
299{
300    OrdPredicate {
301        constant,
302        op: OrdOps::GreaterThan,
303    }
304}