1 // Copyright (c) 2018 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 
11 use std::fmt;
12 
13 use crate::reflection;
14 use crate::utils;
15 use crate::Predicate;
16 
17 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
18 enum EqOps {
19     Equal,
20     NotEqual,
21 }
22 
23 impl fmt::Display for EqOps {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result24     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)]
38 pub struct EqPredicate<T>
39 where
40     T: fmt::Debug + PartialEq,
41 {
42     constant: T,
43     op: EqOps,
44 }
45 
46 impl<T> Predicate<T> for EqPredicate<T>
47 where
48     T: fmt::Debug + PartialEq,
49 {
eval(&self, variable: &T) -> bool50     fn eval(&self, variable: &T) -> bool {
51         match self.op {
52             EqOps::Equal => variable.eq(&self.constant),
53             EqOps::NotEqual => variable.ne(&self.constant),
54         }
55     }
56 
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>57     fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
58         utils::default_find_case(self, expected, variable).map(|case| {
59             case.add_product(reflection::Product::new(
60                 "var",
61                 utils::DebugAdapter::new(variable).to_string(),
62             ))
63         })
64     }
65 }
66 
67 impl<'a, T> Predicate<T> for EqPredicate<&'a T>
68 where
69     T: fmt::Debug + PartialEq + ?Sized,
70 {
eval(&self, variable: &T) -> bool71     fn eval(&self, variable: &T) -> bool {
72         match self.op {
73             EqOps::Equal => variable.eq(self.constant),
74             EqOps::NotEqual => variable.ne(self.constant),
75         }
76     }
77 
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>78     fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
79         utils::default_find_case(self, expected, variable).map(|case| {
80             case.add_product(reflection::Product::new(
81                 "var",
82                 utils::DebugAdapter::new(variable).to_string(),
83             ))
84         })
85     }
86 }
87 
88 impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug + PartialEq {}
89 
90 impl<T> fmt::Display for EqPredicate<T>
91 where
92     T: fmt::Debug + PartialEq,
93 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result94     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
95         let palette = crate::Palette::current();
96         write!(
97             f,
98             "{} {} {}",
99             palette.var.paint("var"),
100             palette.description.paint(self.op),
101             palette
102                 .expected
103                 .paint(utils::DebugAdapter::new(&self.constant)),
104         )
105     }
106 }
107 
108 /// Creates a new predicate that will return `true` when the given `variable` is
109 /// equal to a pre-defined value.
110 ///
111 /// # Examples
112 ///
113 /// ```
114 /// use predicates::prelude::*;
115 ///
116 /// let predicate_fn = predicate::eq(5);
117 /// assert_eq!(true, predicate_fn.eval(&5));
118 /// assert_eq!(false, predicate_fn.eval(&10));
119 ///
120 /// let predicate_fn = predicate::eq("Hello");
121 /// assert_eq!(true, predicate_fn.eval("Hello"));
122 /// assert_eq!(false, predicate_fn.eval("Goodbye"));
123 /// ```
eq<T>(constant: T) -> EqPredicate<T> where T: fmt::Debug + PartialEq,124 pub fn eq<T>(constant: T) -> EqPredicate<T>
125 where
126     T: fmt::Debug + PartialEq,
127 {
128     EqPredicate {
129         constant,
130         op: EqOps::Equal,
131     }
132 }
133 
134 /// Creates a new predicate that will return `true` when the given `variable` is
135 /// _not_ equal to a pre-defined value.
136 ///
137 /// # Examples
138 ///
139 /// ```
140 /// use predicates::prelude::*;
141 ///
142 /// let predicate_fn = predicate::ne(5);
143 /// assert_eq!(false, predicate_fn.eval(&5));
144 /// assert_eq!(true, predicate_fn.eval(&10));
145 /// ```
ne<T>(constant: T) -> EqPredicate<T> where T: PartialEq + fmt::Debug,146 pub fn ne<T>(constant: T) -> EqPredicate<T>
147 where
148     T: PartialEq + fmt::Debug,
149 {
150     EqPredicate {
151         constant,
152         op: EqOps::NotEqual,
153     }
154 }
155 
156 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
157 enum OrdOps {
158     LessThan,
159     LessThanOrEqual,
160     GreaterThanOrEqual,
161     GreaterThan,
162 }
163 
164 impl fmt::Display for OrdOps {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result165     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166         let op = match *self {
167             OrdOps::LessThan => "<",
168             OrdOps::LessThanOrEqual => "<=",
169             OrdOps::GreaterThanOrEqual => ">=",
170             OrdOps::GreaterThan => ">",
171         };
172         write!(f, "{}", op)
173     }
174 }
175 
176 /// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
177 /// value, otherwise returns `false`.
178 ///
179 /// This is created by the `predicate::{gt, ge, lt, le}` functions.
180 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
181 pub struct OrdPredicate<T>
182 where
183     T: fmt::Debug + PartialOrd,
184 {
185     constant: T,
186     op: OrdOps,
187 }
188 
189 impl<T> Predicate<T> for OrdPredicate<T>
190 where
191     T: fmt::Debug + PartialOrd,
192 {
eval(&self, variable: &T) -> bool193     fn eval(&self, variable: &T) -> bool {
194         match self.op {
195             OrdOps::LessThan => variable.lt(&self.constant),
196             OrdOps::LessThanOrEqual => variable.le(&self.constant),
197             OrdOps::GreaterThanOrEqual => variable.ge(&self.constant),
198             OrdOps::GreaterThan => variable.gt(&self.constant),
199         }
200     }
201 
find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>>202     fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
203         utils::default_find_case(self, expected, variable).map(|case| {
204             case.add_product(reflection::Product::new(
205                 "var",
206                 utils::DebugAdapter::new(variable).to_string(),
207             ))
208         })
209     }
210 }
211 
212 impl<'a, T> Predicate<T> for OrdPredicate<&'a T>
213 where
214     T: fmt::Debug + PartialOrd + ?Sized,
215 {
eval(&self, variable: &T) -> bool216     fn eval(&self, variable: &T) -> bool {
217         match self.op {
218             OrdOps::LessThan => variable.lt(self.constant),
219             OrdOps::LessThanOrEqual => variable.le(self.constant),
220             OrdOps::GreaterThanOrEqual => variable.ge(self.constant),
221             OrdOps::GreaterThan => variable.gt(self.constant),
222         }
223     }
224 
find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>>225     fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
226         utils::default_find_case(self, expected, variable).map(|case| {
227             case.add_product(reflection::Product::new(
228                 "var",
229                 utils::DebugAdapter::new(variable).to_string(),
230             ))
231         })
232     }
233 }
234 
235 impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug + PartialOrd {}
236 
237 impl<T> fmt::Display for OrdPredicate<T>
238 where
239     T: fmt::Debug + PartialOrd,
240 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result241     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242         let palette = crate::Palette::current();
243         write!(
244             f,
245             "{} {} {}",
246             palette.var.paint("var"),
247             palette.description.paint(self.op),
248             palette
249                 .expected
250                 .paint(utils::DebugAdapter::new(&self.constant)),
251         )
252     }
253 }
254 
255 /// Creates a new predicate that will return `true` when the given `variable` is
256 /// less than a pre-defined value.
257 ///
258 /// # Examples
259 ///
260 /// ```
261 /// use predicates::prelude::*;
262 ///
263 /// let predicate_fn = predicate::lt(5);
264 /// assert_eq!(true, predicate_fn.eval(&4));
265 /// assert_eq!(false, predicate_fn.eval(&6));
266 ///
267 /// let predicate_fn = predicate::lt("b");
268 /// assert_eq!(true, predicate_fn.eval("a"));
269 /// assert_eq!(false, predicate_fn.eval("c"));
270 /// ```
lt<T>(constant: T) -> OrdPredicate<T> where T: fmt::Debug + PartialOrd,271 pub fn lt<T>(constant: T) -> OrdPredicate<T>
272 where
273     T: fmt::Debug + PartialOrd,
274 {
275     OrdPredicate {
276         constant,
277         op: OrdOps::LessThan,
278     }
279 }
280 
281 /// Creates a new predicate that will return `true` when the given `variable` is
282 /// less than or equal to a pre-defined value.
283 ///
284 /// # Examples
285 ///
286 /// ```
287 /// use predicates::prelude::*;
288 ///
289 /// let predicate_fn = predicate::le(5);
290 /// assert_eq!(true, predicate_fn.eval(&4));
291 /// assert_eq!(true, predicate_fn.eval(&5));
292 /// assert_eq!(false, predicate_fn.eval(&6));
293 /// ```
le<T>(constant: T) -> OrdPredicate<T> where T: PartialOrd + fmt::Debug,294 pub fn le<T>(constant: T) -> OrdPredicate<T>
295 where
296     T: PartialOrd + fmt::Debug,
297 {
298     OrdPredicate {
299         constant,
300         op: OrdOps::LessThanOrEqual,
301     }
302 }
303 
304 /// Creates a new predicate that will return `true` when the given `variable` is
305 /// greater than or equal to a pre-defined value.
306 ///
307 /// # Examples
308 ///
309 /// ```
310 /// use predicates::prelude::*;
311 ///
312 /// let predicate = predicate::ge(5);
313 /// assert_eq!(false, predicate.eval(&4));
314 /// assert_eq!(true, predicate.eval(&5));
315 /// assert_eq!(true, predicate.eval(&6));
316 /// ```
ge<T>(constant: T) -> OrdPredicate<T> where T: PartialOrd + fmt::Debug,317 pub fn ge<T>(constant: T) -> OrdPredicate<T>
318 where
319     T: PartialOrd + fmt::Debug,
320 {
321     OrdPredicate {
322         constant,
323         op: OrdOps::GreaterThanOrEqual,
324     }
325 }
326 
327 /// Creates a new predicate that will return `true` when the given `variable` is
328 /// greater than a pre-defined value.
329 ///
330 /// # Examples
331 ///
332 /// ```
333 /// use predicates::prelude::*;
334 ///
335 /// let predicate_fn = predicate::gt(5);
336 /// assert_eq!(false, predicate_fn.eval(&4));
337 /// assert_eq!(false, predicate_fn.eval(&5));
338 /// assert_eq!(true, predicate_fn.eval(&6));
339 /// ```
gt<T>(constant: T) -> OrdPredicate<T> where T: PartialOrd + fmt::Debug,340 pub fn gt<T>(constant: T) -> OrdPredicate<T>
341 where
342     T: PartialOrd + fmt::Debug,
343 {
344     OrdPredicate {
345         constant,
346         op: OrdOps::GreaterThan,
347     }
348 }
349