Skip to main content

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::current();
73        write!(
74            f,
75            "{} {} {}",
76            palette.var.paint("var"),
77            palette.description.paint(self.op),
78            palette
79                .expected
80                .paint(utils::DebugAdapter::new(&self.constant)),
81        )
82    }
83}
84
85/// Creates a new predicate that will return `true` when the given `variable` is
86/// equal to a pre-defined value.
87///
88/// # Examples
89///
90/// ```
91/// use predicates::prelude::*;
92///
93/// let predicate_fn = predicate::eq(5);
94/// assert_eq!(true, predicate_fn.eval(&5));
95/// assert_eq!(false, predicate_fn.eval(&10));
96///
97/// let predicate_fn = predicate::eq("Hello");
98/// assert_eq!(true, predicate_fn.eval("Hello"));
99/// assert_eq!(false, predicate_fn.eval("Goodbye"));
100///
101/// let predicate_fn = predicate::eq(String::from("Hello"));
102/// assert_eq!(true, predicate_fn.eval("Hello"));
103/// assert_eq!(false, predicate_fn.eval("Goodbye"));
104/// ```
105pub fn eq<T>(constant: T) -> EqPredicate<T>
106where
107    T: fmt::Debug + PartialEq,
108{
109    EqPredicate {
110        constant,
111        op: EqOps::Equal,
112    }
113}
114
115/// Creates a new predicate that will return `true` when the given `variable` is
116/// _not_ equal to a pre-defined value.
117///
118/// # Examples
119///
120/// ```
121/// use predicates::prelude::*;
122///
123/// let predicate_fn = predicate::ne(5);
124/// assert_eq!(false, predicate_fn.eval(&5));
125/// assert_eq!(true, predicate_fn.eval(&10));
126/// ```
127pub fn ne<T>(constant: T) -> EqPredicate<T>
128where
129    T: PartialEq + fmt::Debug,
130{
131    EqPredicate {
132        constant,
133        op: EqOps::NotEqual,
134    }
135}
136
137#[derive(Clone, Copy, Debug, PartialEq, Eq)]
138enum OrdOps {
139    LessThan,
140    LessThanOrEqual,
141    GreaterThanOrEqual,
142    GreaterThan,
143}
144
145impl fmt::Display for OrdOps {
146    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
147        let op = match *self {
148            OrdOps::LessThan => "<",
149            OrdOps::LessThanOrEqual => "<=",
150            OrdOps::GreaterThanOrEqual => ">=",
151            OrdOps::GreaterThan => ">",
152        };
153        write!(f, "{}", op)
154    }
155}
156
157/// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
158/// value, otherwise returns `false`.
159///
160/// This is created by the `predicate::{gt, ge, lt, le}` functions.
161#[derive(Debug, Clone, Copy, PartialEq, Eq)]
162pub struct OrdPredicate<T> {
163    constant: T,
164    op: OrdOps,
165}
166
167impl<P, T> Predicate<P> for OrdPredicate<T>
168where
169    T: std::borrow::Borrow<P> + fmt::Debug,
170    P: fmt::Debug + PartialOrd + ?Sized,
171{
172    fn eval(&self, variable: &P) -> bool {
173        match self.op {
174            OrdOps::LessThan => variable.lt(self.constant.borrow()),
175            OrdOps::LessThanOrEqual => variable.le(self.constant.borrow()),
176            OrdOps::GreaterThanOrEqual => variable.ge(self.constant.borrow()),
177            OrdOps::GreaterThan => variable.gt(self.constant.borrow()),
178        }
179    }
180
181    fn find_case<'a>(&'a self, expected: bool, variable: &P) -> Option<reflection::Case<'a>> {
182        utils::default_find_case(self, expected, variable).map(|case| {
183            case.add_product(reflection::Product::new(
184                "var",
185                utils::DebugAdapter::new(variable).to_string(),
186            ))
187        })
188    }
189}
190
191impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug {}
192
193impl<T> fmt::Display for OrdPredicate<T>
194where
195    T: fmt::Debug,
196{
197    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198        let palette = crate::Palette::current();
199        write!(
200            f,
201            "{} {} {}",
202            palette.var.paint("var"),
203            palette.description.paint(self.op),
204            palette
205                .expected
206                .paint(utils::DebugAdapter::new(&self.constant)),
207        )
208    }
209}
210
211/// Creates a new predicate that will return `true` when the given `variable` is
212/// less than a pre-defined value.
213///
214/// # Examples
215///
216/// ```
217/// use predicates::prelude::*;
218///
219/// let predicate_fn = predicate::lt(5);
220/// assert_eq!(true, predicate_fn.eval(&4));
221/// assert_eq!(false, predicate_fn.eval(&6));
222///
223/// let predicate_fn = predicate::lt("b");
224/// assert_eq!(true, predicate_fn.eval("a"));
225/// assert_eq!(false, predicate_fn.eval("c"));
226///
227/// let predicate_fn = predicate::lt(String::from("b"));
228/// assert_eq!(true, predicate_fn.eval("a"));
229/// assert_eq!(false, predicate_fn.eval("c"));
230/// ```
231pub fn lt<T>(constant: T) -> OrdPredicate<T>
232where
233    T: fmt::Debug + PartialOrd,
234{
235    OrdPredicate {
236        constant,
237        op: OrdOps::LessThan,
238    }
239}
240
241/// Creates a new predicate that will return `true` when the given `variable` is
242/// less than or equal to a pre-defined value.
243///
244/// # Examples
245///
246/// ```
247/// use predicates::prelude::*;
248///
249/// let predicate_fn = predicate::le(5);
250/// assert_eq!(true, predicate_fn.eval(&4));
251/// assert_eq!(true, predicate_fn.eval(&5));
252/// assert_eq!(false, predicate_fn.eval(&6));
253/// ```
254pub fn le<T>(constant: T) -> OrdPredicate<T>
255where
256    T: PartialOrd + fmt::Debug,
257{
258    OrdPredicate {
259        constant,
260        op: OrdOps::LessThanOrEqual,
261    }
262}
263
264/// Creates a new predicate that will return `true` when the given `variable` is
265/// greater than or equal to a pre-defined value.
266///
267/// # Examples
268///
269/// ```
270/// use predicates::prelude::*;
271///
272/// let predicate = predicate::ge(5);
273/// assert_eq!(false, predicate.eval(&4));
274/// assert_eq!(true, predicate.eval(&5));
275/// assert_eq!(true, predicate.eval(&6));
276/// ```
277pub fn ge<T>(constant: T) -> OrdPredicate<T>
278where
279    T: PartialOrd + fmt::Debug,
280{
281    OrdPredicate {
282        constant,
283        op: OrdOps::GreaterThanOrEqual,
284    }
285}
286
287/// Creates a new predicate that will return `true` when the given `variable` is
288/// greater than a pre-defined value.
289///
290/// # Examples
291///
292/// ```
293/// use predicates::prelude::*;
294///
295/// let predicate_fn = predicate::gt(5);
296/// assert_eq!(false, predicate_fn.eval(&4));
297/// assert_eq!(false, predicate_fn.eval(&5));
298/// assert_eq!(true, predicate_fn.eval(&6));
299/// ```
300pub fn gt<T>(constant: T) -> OrdPredicate<T>
301where
302    T: PartialOrd + fmt::Debug,
303{
304    OrdPredicate {
305        constant,
306        op: OrdOps::GreaterThan,
307    }
308}