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}
309