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 boolean logic combinators over `Predicate`s.
10 
11 use std::fmt;
12 use std::marker::PhantomData;
13 
14 use crate::reflection;
15 use crate::Predicate;
16 
17 /// Predicate that combines two `Predicate`s, returning the AND of the results.
18 ///
19 /// This is created by the `Predicate::and` function.
20 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
21 pub struct AndPredicate<M1, M2, Item>
22 where
23     M1: Predicate<Item>,
24     M2: Predicate<Item>,
25     Item: ?Sized,
26 {
27     a: M1,
28     b: M2,
29     _phantom: PhantomData<Item>,
30 }
31 
32 impl<M1, M2, Item> AndPredicate<M1, M2, Item>
33 where
34     M1: Predicate<Item>,
35     M2: Predicate<Item>,
36     Item: ?Sized,
37 {
38     /// Create a new `AndPredicate` over predicates `a` and `b`.
new(a: M1, b: M2) -> AndPredicate<M1, M2, Item>39     pub fn new(a: M1, b: M2) -> AndPredicate<M1, M2, Item> {
40         AndPredicate {
41             a,
42             b,
43             _phantom: PhantomData,
44         }
45     }
46 }
47 
48 impl<M1, M2, Item> Predicate<Item> for AndPredicate<M1, M2, Item>
49 where
50     M1: Predicate<Item>,
51     M2: Predicate<Item>,
52     Item: ?Sized,
53 {
eval(&self, item: &Item) -> bool54     fn eval(&self, item: &Item) -> bool {
55         self.a.eval(item) && self.b.eval(item)
56     }
57 
find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>>58     fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
59         let child_a = self.a.find_case(expected, variable);
60         match (expected, child_a) {
61             (true, Some(child_a)) => self.b.find_case(expected, variable).map(|child_b| {
62                 reflection::Case::new(Some(self), expected)
63                     .add_child(child_a)
64                     .add_child(child_b)
65             }),
66             (true, None) => None,
67             (false, Some(child_a)) => {
68                 Some(reflection::Case::new(Some(self), expected).add_child(child_a))
69             }
70             (false, None) => self
71                 .b
72                 .find_case(expected, variable)
73                 .map(|child_b| reflection::Case::new(Some(self), expected).add_child(child_b)),
74         }
75     }
76 }
77 
78 impl<M1, M2, Item> reflection::PredicateReflection for AndPredicate<M1, M2, Item>
79 where
80     M1: Predicate<Item>,
81     M2: Predicate<Item>,
82     Item: ?Sized,
83 {
children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a>84     fn children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a> {
85         let params = vec![
86             reflection::Child::new("left", &self.a),
87             reflection::Child::new("right", &self.b),
88         ];
89         Box::new(params.into_iter())
90     }
91 }
92 
93 impl<M1, M2, Item> fmt::Display for AndPredicate<M1, M2, Item>
94 where
95     M1: Predicate<Item>,
96     M2: Predicate<Item>,
97     Item: ?Sized,
98 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result99     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100         write!(f, "({} && {})", self.a, self.b)
101     }
102 }
103 
104 #[cfg(test)]
105 mod test_and {
106     use crate::prelude::*;
107 
108     #[test]
find_case_true()109     fn find_case_true() {
110         assert!(predicate::always()
111             .and(predicate::always())
112             .find_case(true, &5)
113             .is_some());
114     }
115 
116     #[test]
find_case_true_left_fail()117     fn find_case_true_left_fail() {
118         assert!(predicate::never()
119             .and(predicate::always())
120             .find_case(true, &5)
121             .is_none());
122     }
123 
124     #[test]
find_case_true_right_fail()125     fn find_case_true_right_fail() {
126         assert!(predicate::always()
127             .and(predicate::never())
128             .find_case(true, &5)
129             .is_none());
130     }
131 
132     #[test]
find_case_true_fails()133     fn find_case_true_fails() {
134         assert!(predicate::never()
135             .and(predicate::never())
136             .find_case(true, &5)
137             .is_none());
138     }
139 
140     #[test]
find_case_false()141     fn find_case_false() {
142         assert!(predicate::never()
143             .and(predicate::never())
144             .find_case(false, &5)
145             .is_some());
146     }
147 
148     #[test]
find_case_false_fails()149     fn find_case_false_fails() {
150         assert!(predicate::always()
151             .and(predicate::always())
152             .find_case(false, &5)
153             .is_none());
154     }
155 
156     #[test]
find_case_false_left_fail()157     fn find_case_false_left_fail() {
158         assert!(predicate::never()
159             .and(predicate::always())
160             .find_case(false, &5)
161             .is_some());
162     }
163 
164     #[test]
find_case_false_right_fail()165     fn find_case_false_right_fail() {
166         assert!(predicate::always()
167             .and(predicate::never())
168             .find_case(false, &5)
169             .is_some());
170     }
171 }
172 
173 /// Predicate that combines two `Predicate`s, returning the OR of the results.
174 ///
175 /// This is created by the `Predicate::or` function.
176 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
177 pub struct OrPredicate<M1, M2, Item>
178 where
179     M1: Predicate<Item>,
180     M2: Predicate<Item>,
181     Item: ?Sized,
182 {
183     a: M1,
184     b: M2,
185     _phantom: PhantomData<Item>,
186 }
187 
188 impl<M1, M2, Item> OrPredicate<M1, M2, Item>
189 where
190     M1: Predicate<Item>,
191     M2: Predicate<Item>,
192     Item: ?Sized,
193 {
194     /// Create a new `OrPredicate` over predicates `a` and `b`.
new(a: M1, b: M2) -> OrPredicate<M1, M2, Item>195     pub fn new(a: M1, b: M2) -> OrPredicate<M1, M2, Item> {
196         OrPredicate {
197             a,
198             b,
199             _phantom: PhantomData,
200         }
201     }
202 }
203 
204 impl<M1, M2, Item> Predicate<Item> for OrPredicate<M1, M2, Item>
205 where
206     M1: Predicate<Item>,
207     M2: Predicate<Item>,
208     Item: ?Sized,
209 {
eval(&self, item: &Item) -> bool210     fn eval(&self, item: &Item) -> bool {
211         self.a.eval(item) || self.b.eval(item)
212     }
213 
find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>>214     fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
215         let child_a = self.a.find_case(expected, variable);
216         match (expected, child_a) {
217             (true, Some(child_a)) => {
218                 Some(reflection::Case::new(Some(self), expected).add_child(child_a))
219             }
220             (true, None) => self
221                 .b
222                 .find_case(expected, variable)
223                 .map(|child_b| reflection::Case::new(Some(self), expected).add_child(child_b)),
224             (false, Some(child_a)) => self.b.find_case(expected, variable).map(|child_b| {
225                 reflection::Case::new(Some(self), expected)
226                     .add_child(child_a)
227                     .add_child(child_b)
228             }),
229             (false, None) => None,
230         }
231     }
232 }
233 
234 impl<M1, M2, Item> reflection::PredicateReflection for OrPredicate<M1, M2, Item>
235 where
236     M1: Predicate<Item>,
237     M2: Predicate<Item>,
238     Item: ?Sized,
239 {
children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a>240     fn children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a> {
241         let params = vec![
242             reflection::Child::new("left", &self.a),
243             reflection::Child::new("right", &self.b),
244         ];
245         Box::new(params.into_iter())
246     }
247 }
248 
249 impl<M1, M2, Item> fmt::Display for OrPredicate<M1, M2, Item>
250 where
251     M1: Predicate<Item>,
252     M2: Predicate<Item>,
253     Item: ?Sized,
254 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result255     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
256         write!(f, "({} || {})", self.a, self.b)
257     }
258 }
259 
260 #[cfg(test)]
261 mod test_or {
262     use crate::prelude::*;
263 
264     #[test]
find_case_true()265     fn find_case_true() {
266         assert!(predicate::always()
267             .or(predicate::always())
268             .find_case(true, &5)
269             .is_some());
270     }
271 
272     #[test]
find_case_true_left_fail()273     fn find_case_true_left_fail() {
274         assert!(predicate::never()
275             .or(predicate::always())
276             .find_case(true, &5)
277             .is_some());
278     }
279 
280     #[test]
find_case_true_right_fail()281     fn find_case_true_right_fail() {
282         assert!(predicate::always()
283             .or(predicate::never())
284             .find_case(true, &5)
285             .is_some());
286     }
287 
288     #[test]
find_case_true_fails()289     fn find_case_true_fails() {
290         assert!(predicate::never()
291             .or(predicate::never())
292             .find_case(true, &5)
293             .is_none());
294     }
295 
296     #[test]
find_case_false()297     fn find_case_false() {
298         assert!(predicate::never()
299             .or(predicate::never())
300             .find_case(false, &5)
301             .is_some());
302     }
303 
304     #[test]
find_case_false_fails()305     fn find_case_false_fails() {
306         assert!(predicate::always()
307             .or(predicate::always())
308             .find_case(false, &5)
309             .is_none());
310     }
311 
312     #[test]
find_case_false_left_fail()313     fn find_case_false_left_fail() {
314         assert!(predicate::never()
315             .or(predicate::always())
316             .find_case(false, &5)
317             .is_none());
318     }
319 
320     #[test]
find_case_false_right_fail()321     fn find_case_false_right_fail() {
322         assert!(predicate::always()
323             .or(predicate::never())
324             .find_case(false, &5)
325             .is_none());
326     }
327 }
328 
329 /// Predicate that returns a `Predicate` taking the logical NOT of the result.
330 ///
331 /// This is created by the `Predicate::not` function.
332 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
333 pub struct NotPredicate<M, Item>
334 where
335     M: Predicate<Item>,
336     Item: ?Sized,
337 {
338     inner: M,
339     _phantom: PhantomData<Item>,
340 }
341 
342 impl<M, Item> NotPredicate<M, Item>
343 where
344     M: Predicate<Item>,
345     Item: ?Sized,
346 {
347     /// Create a new `NotPredicate` over predicate `inner`.
new(inner: M) -> NotPredicate<M, Item>348     pub fn new(inner: M) -> NotPredicate<M, Item> {
349         NotPredicate {
350             inner,
351             _phantom: PhantomData,
352         }
353     }
354 }
355 
356 impl<M, Item> Predicate<Item> for NotPredicate<M, Item>
357 where
358     M: Predicate<Item>,
359     Item: ?Sized,
360 {
eval(&self, item: &Item) -> bool361     fn eval(&self, item: &Item) -> bool {
362         !self.inner.eval(item)
363     }
364 
find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>>365     fn find_case<'a>(&'a self, expected: bool, variable: &Item) -> Option<reflection::Case<'a>> {
366         self.inner
367             .find_case(!expected, variable)
368             .map(|child| reflection::Case::new(Some(self), expected).add_child(child))
369     }
370 }
371 
372 impl<M, Item> reflection::PredicateReflection for NotPredicate<M, Item>
373 where
374     M: Predicate<Item>,
375     Item: ?Sized,
376 {
children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a>377     fn children<'a>(&'a self) -> Box<dyn Iterator<Item = reflection::Child<'a>> + 'a> {
378         let params = vec![reflection::Child::new("predicate", &self.inner)];
379         Box::new(params.into_iter())
380     }
381 }
382 
383 impl<M, Item> fmt::Display for NotPredicate<M, Item>
384 where
385     M: Predicate<Item>,
386     Item: ?Sized,
387 {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result388     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389         write!(f, "(! {})", self.inner)
390     }
391 }
392 
393 /// `Predicate` extension that adds boolean logic.
394 pub trait PredicateBooleanExt<Item: ?Sized>
395 where
396     Self: Predicate<Item>,
397 {
398     /// Compute the logical AND of two `Predicate` results, returning the result.
399     ///
400     /// # Examples
401     ///
402     /// ```
403     /// use predicates::prelude::*;
404     ///
405     /// let predicate_fn1 = predicate::always().and(predicate::always());
406     /// let predicate_fn2 = predicate::always().and(predicate::never());
407     /// assert_eq!(true, predicate_fn1.eval(&4));
408     /// assert_eq!(false, predicate_fn2.eval(&4));
and<B>(self, other: B) -> AndPredicate<Self, B, Item> where B: Predicate<Item>, Self: Sized,409     fn and<B>(self, other: B) -> AndPredicate<Self, B, Item>
410     where
411         B: Predicate<Item>,
412         Self: Sized,
413     {
414         AndPredicate::new(self, other)
415     }
416 
417     /// Compute the logical OR of two `Predicate` results, returning the result.
418     ///
419     /// # Examples
420     ///
421     /// ```
422     /// use predicates::prelude::*;
423     ///
424     /// let predicate_fn1 = predicate::always().or(predicate::always());
425     /// let predicate_fn2 = predicate::always().or(predicate::never());
426     /// let predicate_fn3 = predicate::never().or(predicate::never());
427     /// assert_eq!(true, predicate_fn1.eval(&4));
428     /// assert_eq!(true, predicate_fn2.eval(&4));
429     /// assert_eq!(false, predicate_fn3.eval(&4));
or<B>(self, other: B) -> OrPredicate<Self, B, Item> where B: Predicate<Item>, Self: Sized,430     fn or<B>(self, other: B) -> OrPredicate<Self, B, Item>
431     where
432         B: Predicate<Item>,
433         Self: Sized,
434     {
435         OrPredicate::new(self, other)
436     }
437 
438     /// Compute the logical NOT of a `Predicate`, returning the result.
439     ///
440     /// # Examples
441     ///
442     /// ```
443     /// use predicates::prelude::*;
444     ///
445     /// let predicate_fn1 = predicate::always().not();
446     /// let predicate_fn2 = predicate::never().not();
447     /// assert_eq!(false, predicate_fn1.eval(&4));
448     /// assert_eq!(true, predicate_fn2.eval(&4));
not(self) -> NotPredicate<Self, Item> where Self: Sized,449     fn not(self) -> NotPredicate<Self, Item>
450     where
451         Self: Sized,
452     {
453         NotPredicate::new(self)
454     }
455 }
456 
457 impl<P, Item> PredicateBooleanExt<Item> for P
458 where
459     P: Predicate<Item>,
460     Item: ?Sized,
461 {
462 }
463