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`. |
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 | { |
70 | fn eval(&self, item: &Item) -> bool { |
71 | self.a.eval(item) && self.b.eval(item) |
72 | } |
73 | |
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 | { |
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 | { |
115 | 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] |
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] |
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] |
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] |
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] |
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] |
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] |
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] |
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`. |
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 | { |
242 | fn eval(&self, item: &Item) -> bool { |
243 | self.a.eval(item) || self.b.eval(item) |
244 | } |
245 | |
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 | { |
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 | { |
287 | 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] |
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] |
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] |
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] |
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] |
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] |
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] |
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] |
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`. |
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 | { |
407 | fn eval(&self, item: &Item) -> bool { |
408 | !self.inner.eval(item) |
409 | } |
410 | |
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 | { |
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 | { |
434 | 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)); |
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)); |
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)); |
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 | |