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