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