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}