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