qubit_function/predicates/bi_predicate.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # BiPredicate Abstraction
10//!
11//! Provides a Rust implementation similar to Java's `BiPredicate`
12//! interface for testing whether two values satisfy a condition.
13//!
14//! ## Core Semantics
15//!
16//! A **BiPredicate** is fundamentally a pure judgment operation that
17//! tests whether two values satisfy a specific condition. It should
18//! be:
19//!
20//! - **Read-only**: Does not modify the tested values
21//! - **Side-effect free**: Does not change external state (from the
22//! user's perspective)
23//! - **Repeatable**: Same inputs should produce the same result
24//! - **Deterministic**: Judgment logic should be predictable
25//!
26//! It is similar to the `Fn(&T, &U) -> bool` trait in the standard library.
27//!
28//! ## Design Philosophy
29//!
30//! This module follows the same principles as the `Predicate` module:
31//!
32//! 1. **Single Trait**: Only one `BiPredicate<T, U>` trait with
33//! `&self`, keeping the API simple and semantically clear
34//! 2. **No BiPredicateMut**: All stateful scenarios use interior
35//! mutability (`RefCell`, `Cell`, `Mutex`) instead of `&mut self`
36//! 3. **No BiPredicateOnce**: Violates bi-predicate semantics -
37//! judgments should be repeatable
38//! 4. **Three Implementations**: `BoxBiPredicate`, `RcBiPredicate`,
39//! and `ArcBiPredicate` cover all ownership scenarios
40//!
41//! ## Type Selection Guide
42//!
43//! | Scenario | Recommended Type | Reason |
44//! |----------|------------------|--------|
45//! | One-time use | `BoxBiPredicate` | Single ownership, no overhead |
46//! | Multi-threaded | `ArcBiPredicate` | Thread-safe, clonable |
47//! | Single-threaded reuse | `RcBiPredicate` | Better performance |
48//! | Stateful predicate | Any type + `RefCell`/`Cell`/`Mutex` | Interior mutability |
49//!
50//! ## Examples
51//!
52//! ### Basic Usage with Closures
53//!
54//! ```rust
55//! use qubit_function::bi_predicate::BiPredicate;
56//!
57//! let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
58//! assert!(is_sum_positive.test(&5, &3));
59//! assert!(!is_sum_positive.test(&-3, &-7));
60//! ```
61//!
62//! ### BoxBiPredicate - Single Ownership
63//!
64//! ```rust
65//! use qubit_function::bi_predicate::{BiPredicate, BoxBiPredicate};
66//!
67//! let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0)
68//! .and(BoxBiPredicate::new(|x, y| x > y));
69//! assert!(pred.test(&10, &5));
70//! ```
71//!
72//! ### Closure Composition with Extension Methods
73//!
74//! Closures automatically gain `and`, `or`, `not` methods through the
75//! `FnBiPredicateOps` extension trait, returning `BoxBiPredicate`:
76//!
77//! ```rust
78//! use qubit_function::bi_predicate::{BiPredicate,
79//! FnBiPredicateOps};
80//!
81//! // Compose closures directly - result is BoxBiPredicate
82//! let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
83//! let first_larger = |x: &i32, y: &i32| x > y;
84//!
85//! let combined = is_sum_positive.and(first_larger);
86//! assert!(combined.test(&10, &5));
87//! assert!(!combined.test(&3, &8));
88//!
89//! // Use `or` for disjunction
90//! let negative_sum = |x: &i32, y: &i32| x + y < 0;
91//! let both_large = |x: &i32, y: &i32| *x > 100 && *y > 100;
92//! let either = negative_sum.or(both_large);
93//! assert!(either.test(&-10, &5));
94//! assert!(either.test(&200, &150));
95//! ```
96//!
97//! ### RcBiPredicate - Single-threaded Reuse
98//!
99//! ```rust
100//! use qubit_function::bi_predicate::{BiPredicate, RcBiPredicate};
101//!
102//! let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
103//! let combined1 = pred.and(RcBiPredicate::new(|x, y| x > y));
104//! let combined2 = pred.or(RcBiPredicate::new(|x, y| *x > 100));
105//!
106//! // Original predicate is still usable
107//! assert!(pred.test(&5, &3));
108//! ```
109//!
110//! ### ArcBiPredicate - Thread-safe Sharing
111//!
112//! ```rust
113//! use qubit_function::bi_predicate::{BiPredicate, ArcBiPredicate};
114//! use std::thread;
115//!
116//! let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
117//! let pred_clone = pred.clone();
118//!
119//! let handle = thread::spawn(move || {
120//! pred_clone.test(&10, &5)
121//! });
122//!
123//! assert!(handle.join().unwrap());
124//! assert!(pred.test(&3, &7)); // Original still usable
125//! ```
126//!
127//! ### Stateful BiPredicates with Interior Mutability
128//!
129//! ```rust
130//! use qubit_function::bi_predicate::{BiPredicate, BoxBiPredicate};
131//! use std::cell::Cell;
132//!
133//! let count = Cell::new(0);
134//! let pred = BoxBiPredicate::new(move |x: &i32, y: &i32| {
135//! count.set(count.get() + 1);
136//! x + y > 0
137//! });
138//!
139//! // No need for `mut` - interior mutability handles state
140//! assert!(pred.test(&5, &3));
141//! assert!(!pred.test(&-8, &-3));
142//! ```
143//!
144//! ## Author
145//!
146//! Haixing Hu
147use std::rc::Rc;
148use std::sync::Arc;
149
150use crate::macros::{
151 impl_arc_conversions,
152 impl_box_conversions,
153 impl_closure_trait,
154 impl_rc_conversions,
155};
156use crate::predicates::macros::{
157 constants::{
158 ALWAYS_FALSE_NAME,
159 ALWAYS_TRUE_NAME,
160 },
161 impl_box_predicate_methods,
162 impl_predicate_clone,
163 impl_predicate_common_methods,
164 impl_predicate_debug_display,
165 impl_shared_predicate_methods,
166};
167
168/// Type alias for bi-predicate function to simplify complex types.
169///
170/// This type alias represents a function that takes two references and returns a boolean.
171/// It is used to reduce type complexity in struct definitions.
172type BiPredicateFn<T, U> = dyn Fn(&T, &U) -> bool;
173
174/// Type alias for thread-safe bi-predicate function to simplify complex types.
175///
176/// This type alias represents a function that takes two references and returns a boolean,
177/// with Send + Sync bounds for thread-safe usage. It is used to reduce type complexity
178/// in Arc-based struct definitions.
179type SendSyncBiPredicateFn<T, U> = dyn Fn(&T, &U) -> bool + Send + Sync;
180
181/// A bi-predicate trait for testing whether two values satisfy a
182/// condition.
183///
184/// This trait represents a **pure judgment operation** - it tests
185/// whether two given values meet certain criteria without modifying
186/// either the values or the bi-predicate itself (from the user's
187/// perspective). This semantic clarity distinguishes bi-predicates
188/// from consumers or transformers.
189///
190/// ## Design Rationale
191///
192/// This is a **minimal trait** that only defines:
193/// - The core `test` method using `&self` (immutable borrow)
194/// - Type conversion methods (`into_box`, `into_rc`, `into_arc`)
195/// - Closure conversion method (`into_fn`)
196///
197/// Logical composition methods (`and`, `or`, `not`, `xor`, `nand`,
198/// `nor`) are intentionally **not** part of the trait. Instead, they
199/// are implemented on concrete types (`BoxBiPredicate`,
200/// `RcBiPredicate`, `ArcBiPredicate`), allowing each implementation
201/// to maintain its specific ownership characteristics:
202///
203/// - `BoxBiPredicate`: Methods consume `self` (single ownership)
204/// - `RcBiPredicate`: Methods borrow `&self` (shared ownership)
205/// - `ArcBiPredicate`: Methods borrow `&self` (thread-safe shared
206/// ownership)
207///
208/// ## Why `&self` Instead of `&mut self`?
209///
210/// Bi-predicates use `&self` because:
211///
212/// 1. **Semantic Clarity**: A bi-predicate is a judgment, not a
213/// mutation
214/// 2. **Flexibility**: Can be used in immutable contexts
215/// 3. **Simplicity**: No need for `mut` in user code
216/// 4. **Interior Mutability**: State (if needed) can be managed with
217/// `RefCell`, `Cell`, or `Mutex`
218///
219/// ## Automatic Implementation for Closures
220///
221/// Any closure matching `Fn(&T, &U) -> bool` automatically implements
222/// this trait, providing seamless integration with Rust's closure
223/// system.
224///
225/// ## Examples
226///
227/// ### Basic Usage
228///
229/// ```rust
230/// use qubit_function::bi_predicate::BiPredicate;
231///
232/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
233/// assert!(is_sum_positive.test(&5, &3));
234/// assert!(!is_sum_positive.test(&-5, &-3));
235/// ```
236///
237/// ### Type Conversion
238///
239/// ```rust
240/// use qubit_function::bi_predicate::{BiPredicate,
241/// BoxBiPredicate};
242///
243/// let closure = |x: &i32, y: &i32| x + y > 0;
244/// let boxed: BoxBiPredicate<i32, i32> = closure.into_box();
245/// assert!(boxed.test(&5, &3));
246/// ```
247///
248/// ### Stateful BiPredicate with Interior Mutability
249///
250/// ```rust
251/// use qubit_function::bi_predicate::{BiPredicate,
252/// BoxBiPredicate};
253/// use std::cell::Cell;
254///
255/// let count = Cell::new(0);
256/// let counting_pred = BoxBiPredicate::new(move |x: &i32, y: &i32| {
257/// count.set(count.get() + 1);
258/// x + y > 0
259/// });
260///
261/// // Note: No `mut` needed - interior mutability handles state
262/// assert!(counting_pred.test(&5, &3));
263/// assert!(!counting_pred.test(&-5, &-3));
264/// ```
265///
266/// ## Author
267///
268/// Haixing Hu
269pub trait BiPredicate<T, U> {
270 /// Tests whether the given values satisfy this bi-predicate.
271 ///
272 /// # Parameters
273 ///
274 /// * `first` - The first value to test.
275 /// * `second` - The second value to test.
276 ///
277 /// # Returns
278 ///
279 /// `true` if the values satisfy this bi-predicate, `false`
280 /// otherwise.
281 fn test(&self, first: &T, second: &U) -> bool;
282
283 /// Converts this bi-predicate into a `BoxBiPredicate`.
284 ///
285 /// # Returns
286 ///
287 /// A `BoxBiPredicate` wrapping this bi-predicate.
288 ///
289 /// # Default Implementation
290 ///
291 /// The default implementation wraps the bi-predicate in a
292 /// closure that calls `test`, providing automatic conversion
293 /// for custom types that only implement the core `test`
294 /// method.
295 fn into_box(self) -> BoxBiPredicate<T, U>
296 where
297 Self: Sized + 'static,
298 T: 'static,
299 U: 'static,
300 {
301 BoxBiPredicate::new(move |first, second| self.test(first, second))
302 }
303
304 /// Converts this bi-predicate into an `RcBiPredicate`.
305 ///
306 /// # Returns
307 ///
308 /// An `RcBiPredicate` wrapping this bi-predicate.
309 ///
310 /// # Default Implementation
311 ///
312 /// The default implementation wraps the bi-predicate in a
313 /// closure that calls `test`, providing automatic conversion
314 /// for custom types that only implement the core `test`
315 /// method.
316 fn into_rc(self) -> RcBiPredicate<T, U>
317 where
318 Self: Sized + 'static,
319 T: 'static,
320 U: 'static,
321 {
322 RcBiPredicate::new(move |first, second| self.test(first, second))
323 }
324
325 /// Converts this bi-predicate into an `ArcBiPredicate`.
326 ///
327 /// # Returns
328 ///
329 /// An `ArcBiPredicate` wrapping this bi-predicate.
330 ///
331 /// # Default Implementation
332 ///
333 /// The default implementation wraps the bi-predicate in a
334 /// closure that calls `test`, providing automatic conversion
335 /// for custom types that only implement the core `test`
336 /// method. Note that this requires `Send + Sync` bounds for
337 /// thread-safe sharing.
338 fn into_arc(self) -> ArcBiPredicate<T, U>
339 where
340 Self: Sized + Send + Sync + 'static,
341 T: 'static,
342 U: 'static,
343 {
344 ArcBiPredicate::new(move |first, second| self.test(first, second))
345 }
346
347 /// Converts this bi-predicate into a closure that can be used
348 /// directly with standard library methods.
349 ///
350 /// This method consumes the bi-predicate and returns a closure
351 /// with signature `Fn(&T, &U) -> bool`. Since `Fn` is a subtrait
352 /// of `FnMut`, the returned closure can be used in any context
353 /// that requires either `Fn(&T, &U) -> bool` or
354 /// `FnMut(&T, &U) -> bool`.
355 ///
356 /// # Returns
357 ///
358 /// A closure implementing `Fn(&T, &U) -> bool` (also usable as
359 /// `FnMut(&T, &U) -> bool`).
360 ///
361 /// # Default Implementation
362 ///
363 /// The default implementation returns a closure that calls the
364 /// `test` method, providing automatic conversion for custom
365 /// types.
366 ///
367 /// # Examples
368 ///
369 /// ## Using with Iterator Methods
370 ///
371 /// ```rust
372 /// use qubit_function::bi_predicate::{BiPredicate,
373 /// BoxBiPredicate};
374 ///
375 /// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
376 ///
377 /// let pairs = vec![(1, 2), (-1, 3), (5, -6)];
378 /// let mut closure = pred.into_fn();
379 /// let positives: Vec<_> = pairs.iter()
380 /// .filter(|(x, y)| closure(x, y))
381 /// .collect();
382 /// assert_eq!(positives, vec![&(1, 2), &(-1, 3)]);
383 /// ```
384 fn into_fn(self) -> impl Fn(&T, &U) -> bool
385 where
386 Self: Sized + 'static,
387 {
388 move |first, second| self.test(first, second)
389 }
390
391 fn to_box(&self) -> BoxBiPredicate<T, U>
392 where
393 Self: Sized + Clone + 'static,
394 T: 'static,
395 U: 'static,
396 {
397 self.clone().into_box()
398 }
399
400 fn to_rc(&self) -> RcBiPredicate<T, U>
401 where
402 Self: Sized + Clone + 'static,
403 T: 'static,
404 U: 'static,
405 {
406 self.clone().into_rc()
407 }
408
409 fn to_arc(&self) -> ArcBiPredicate<T, U>
410 where
411 Self: Sized + Clone + Send + Sync + 'static,
412 T: 'static,
413 U: 'static,
414 {
415 self.clone().into_arc()
416 }
417
418 fn to_fn(&self) -> impl Fn(&T, &U) -> bool
419 where
420 Self: Sized + Clone + 'static,
421 {
422 self.clone().into_fn()
423 }
424}
425
426/// A Box-based bi-predicate with single ownership.
427///
428/// This type is suitable for one-time use scenarios where the
429/// bi-predicate does not need to be cloned or shared. Composition
430/// methods consume `self`, reflecting the single-ownership model.
431///
432/// # Examples
433///
434/// ```rust
435/// use qubit_function::bi_predicate::{BiPredicate, BoxBiPredicate};
436///
437/// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
438/// assert!(pred.test(&5, &3));
439///
440/// // Chaining consumes the bi-predicate
441/// let combined = pred.and(BoxBiPredicate::new(|x, y| x > y));
442/// assert!(combined.test(&10, &5));
443/// ```
444///
445/// # Author
446///
447/// Haixing Hu
448pub struct BoxBiPredicate<T, U> {
449 function: Box<BiPredicateFn<T, U>>,
450 name: Option<String>,
451}
452
453impl<T, U> BoxBiPredicate<T, U> {
454 // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
455 impl_predicate_common_methods!(
456 BoxBiPredicate<T, U>,
457 (Fn(&T, &U) -> bool + 'static),
458 |f| Box::new(f)
459 );
460
461 // Generates: and(), or(), not(), nand(), xor(), nor()
462 impl_box_predicate_methods!(BoxBiPredicate<T, U>);
463}
464
465// Generates: impl Debug for BoxBiPredicate<T, U> and impl Display for BoxBiPredicate<T, U>
466impl_predicate_debug_display!(BoxBiPredicate<T, U>);
467
468impl<T, U> BiPredicate<T, U> for BoxBiPredicate<T, U> {
469 fn test(&self, first: &T, second: &U) -> bool {
470 (self.function)(first, second)
471 }
472
473 // Generates: into_box(), into_rc(), into_fn()
474 impl_box_conversions!(
475 BoxBiPredicate<T, U>,
476 RcBiPredicate,
477 Fn(&T, &U) -> bool
478 );
479}
480
481/// An Rc-based bi-predicate with single-threaded shared ownership.
482///
483/// This type is suitable for scenarios where the bi-predicate needs
484/// to be reused in a single-threaded context. Composition methods
485/// borrow `&self`, allowing the original bi-predicate to remain
486/// usable after composition.
487///
488/// # Examples
489///
490/// ```rust
491/// use qubit_function::bi_predicate::{BiPredicate, RcBiPredicate};
492///
493/// let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
494/// assert!(pred.test(&5, &3));
495///
496/// // Original bi-predicate remains usable after composition
497/// let combined = pred.and(RcBiPredicate::new(|x, y| x > y));
498/// assert!(pred.test(&5, &3)); // Still works
499/// ```
500///
501/// # Author
502///
503/// Haixing Hu
504pub struct RcBiPredicate<T, U> {
505 function: Rc<BiPredicateFn<T, U>>,
506 name: Option<String>,
507}
508
509impl<T, U> RcBiPredicate<T, U> {
510 // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
511 impl_predicate_common_methods!(
512 RcBiPredicate<T, U>,
513 (Fn(&T, &U) -> bool + 'static),
514 |f| Rc::new(f)
515 );
516
517 // Generates: and(), or(), not(), nand(), xor(), nor()
518 impl_shared_predicate_methods!(RcBiPredicate<T, U>, 'static);
519}
520
521// Generates: impl Clone for RcBiPredicate<T, U>
522impl_predicate_clone!(RcBiPredicate<T, U>);
523
524// Generates: impl Debug for RcBiPredicate<T, U> and impl Display for RcBiPredicate<T, U>
525impl_predicate_debug_display!(RcBiPredicate<T, U>);
526
527// Implements BiPredicate trait for RcBiPredicate<T, U>
528impl<T, U> BiPredicate<T, U> for RcBiPredicate<T, U> {
529 fn test(&self, first: &T, second: &U) -> bool {
530 (self.function)(first, second)
531 }
532
533 // Generates: into_box(), into_rc(), into_fn(), to_box(), to_rc(), to_fn()
534 impl_rc_conversions!(
535 RcBiPredicate<T, U>,
536 BoxBiPredicate,
537 Fn(first: &T, second: &U) -> bool
538 );
539}
540
541/// An Arc-based bi-predicate with thread-safe shared ownership.
542///
543/// This type is suitable for scenarios where the bi-predicate needs
544/// to be shared across threads. Composition methods borrow `&self`,
545/// allowing the original bi-predicate to remain usable after
546/// composition.
547///
548/// # Examples
549///
550/// ```rust
551/// use qubit_function::bi_predicate::{BiPredicate, ArcBiPredicate};
552///
553/// let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
554/// assert!(pred.test(&5, &3));
555///
556/// // Original bi-predicate remains usable after composition
557/// let combined = pred.and(ArcBiPredicate::new(|x, y| x > y));
558/// assert!(pred.test(&5, &3)); // Still works
559///
560/// // Can be cloned and sent across threads
561/// let pred_clone = pred.clone();
562/// std::thread::spawn(move || {
563/// assert!(pred_clone.test(&10, &5));
564/// }).join().unwrap();
565/// ```
566///
567/// # Author
568///
569/// Haixing Hu
570pub struct ArcBiPredicate<T, U> {
571 function: Arc<SendSyncBiPredicateFn<T, U>>,
572 name: Option<String>,
573}
574
575impl<T, U> ArcBiPredicate<T, U> {
576 // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
577 impl_predicate_common_methods!(
578 ArcBiPredicate<T, U>,
579 (Fn(&T, &U) -> bool + Send + Sync + 'static),
580 |f| Arc::new(f)
581 );
582
583 // Generates: and(), or(), not(), nand(), xor(), nor()
584 impl_shared_predicate_methods!(
585 ArcBiPredicate<T, U>,
586 Send + Sync + 'static
587 );
588}
589
590// Generates: impl Clone for ArcBiPredicate<T, U>
591impl_predicate_clone!(ArcBiPredicate<T, U>);
592
593// Generates: impl Debug for ArcBiPredicate<T, U> and impl Display for ArcBiPredicate<T, U>
594impl_predicate_debug_display!(ArcBiPredicate<T, U>);
595
596// Implements BiPredicate trait for ArcBiPredicate<T, U>
597impl<T, U> BiPredicate<T, U> for ArcBiPredicate<T, U> {
598 fn test(&self, first: &T, second: &U) -> bool {
599 (self.function)(first, second)
600 }
601
602 // Generates: into_box, into_rc, into_arc, into_fn, to_box, to_rc, to_arc, to_fn
603 impl_arc_conversions!(
604 ArcBiPredicate<T, U>,
605 BoxBiPredicate,
606 RcBiPredicate,
607 Fn(first: &T, second: &U) -> bool
608 );
609}
610
611// Blanket implementation for all closures that match
612// Fn(&T, &U) -> bool. This provides optimal implementations for
613// closures by wrapping them directly into the target type.
614impl_closure_trait!(
615 BiPredicate<T, U>,
616 test,
617 Fn(first: &T, second: &U) -> bool
618);
619
620/// Extension trait providing logical composition methods for closures.
621///
622/// This trait is automatically implemented for all closures and
623/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
624/// chaining starting from a closure.
625///
626/// # Examples
627///
628/// ```rust
629/// use qubit_function::bi_predicate::{BiPredicate, FnBiPredicateOps};
630///
631/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
632/// let first_larger = |x: &i32, y: &i32| x > y;
633///
634/// // Combine bi-predicates using extension methods
635/// let pred = is_sum_positive.and(first_larger);
636/// assert!(pred.test(&10, &5));
637/// assert!(!pred.test(&3, &8));
638/// ```
639///
640/// # Author
641///
642/// Haixing Hu
643pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized {
644 /// Returns a bi-predicate that represents the logical AND of this
645 /// bi-predicate and another.
646 ///
647 /// # Parameters
648 ///
649 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
650 /// is passed by value and will transfer ownership.** If you need to
651 /// preserve the original bi-predicate, clone it first (if it implements
652 /// `Clone`). Can be:
653 /// - Another closure: `|x: &T, y: &U| -> bool`
654 /// - A function pointer: `fn(&T, &U) -> bool`
655 /// - A `BoxBiPredicate<T, U>`
656 /// - An `RcBiPredicate<T, U>`
657 /// - An `ArcBiPredicate<T, U>`
658 /// - Any type implementing `BiPredicate<T, U>`
659 ///
660 /// # Returns
661 ///
662 /// A `BoxBiPredicate` representing the logical AND.
663 fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
664 where
665 Self: 'static,
666 P: BiPredicate<T, U> + 'static,
667 T: 'static,
668 U: 'static,
669 {
670 BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
671 }
672
673 /// Returns a bi-predicate that represents the logical OR of this
674 /// bi-predicate and another.
675 ///
676 /// # Parameters
677 ///
678 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
679 /// is passed by value and will transfer ownership.** If you need to
680 /// preserve the original bi-predicate, clone it first (if it implements
681 /// `Clone`). Can be:
682 /// - Another closure: `|x: &T, y: &U| -> bool`
683 /// - A function pointer: `fn(&T, &U) -> bool`
684 /// - A `BoxBiPredicate<T, U>`
685 /// - An `RcBiPredicate<T, U>`
686 /// - An `ArcBiPredicate<T, U>`
687 /// - Any type implementing `BiPredicate<T, U>`
688 ///
689 /// # Returns
690 ///
691 /// A `BoxBiPredicate` representing the logical OR.
692 fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
693 where
694 Self: 'static,
695 P: BiPredicate<T, U> + 'static,
696 T: 'static,
697 U: 'static,
698 {
699 BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
700 }
701
702 /// Returns a bi-predicate that represents the logical negation of
703 /// this bi-predicate.
704 ///
705 /// # Returns
706 ///
707 /// A `BoxBiPredicate` representing the logical negation.
708 fn not(self) -> BoxBiPredicate<T, U>
709 where
710 Self: 'static,
711 T: 'static,
712 U: 'static,
713 {
714 BoxBiPredicate::new(move |first, second| !self(first, second))
715 }
716
717 /// Returns a bi-predicate that represents the logical NAND (NOT
718 /// AND) of this bi-predicate and another.
719 ///
720 /// NAND returns `true` unless both bi-predicates are `true`.
721 /// Equivalent to `!(self AND other)`.
722 ///
723 /// # Parameters
724 ///
725 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
726 /// is passed by value and will transfer ownership.** If you need to
727 /// preserve the original bi-predicate, clone it first (if it implements
728 /// `Clone`). Can be:
729 /// - Another closure: `|x: &T, y: &U| -> bool`
730 /// - A function pointer: `fn(&T, &U) -> bool`
731 /// - A `BoxBiPredicate<T, U>`
732 /// - An `RcBiPredicate<T, U>`
733 /// - An `ArcBiPredicate<T, U>`
734 /// - Any type implementing `BiPredicate<T, U>`
735 ///
736 /// # Returns
737 ///
738 /// A `BoxBiPredicate` representing the logical NAND.
739 fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
740 where
741 Self: 'static,
742 P: BiPredicate<T, U> + 'static,
743 T: 'static,
744 U: 'static,
745 {
746 BoxBiPredicate::new(move |first, second| {
747 !(self(first, second) && other.test(first, second))
748 })
749 }
750
751 /// Returns a bi-predicate that represents the logical XOR
752 /// (exclusive OR) of this bi-predicate and another.
753 ///
754 /// XOR returns `true` if exactly one of the bi-predicates is
755 /// `true`.
756 ///
757 /// # Parameters
758 ///
759 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
760 /// is passed by value and will transfer ownership.** If you need to
761 /// preserve the original bi-predicate, clone it first (if it implements
762 /// `Clone`). Can be:
763 /// - Another closure: `|x: &T, y: &U| -> bool`
764 /// - A function pointer: `fn(&T, &U) -> bool`
765 /// - A `BoxBiPredicate<T, U>`
766 /// - An `RcBiPredicate<T, U>`
767 /// - An `ArcBiPredicate<T, U>`
768 /// - Any type implementing `BiPredicate<T, U>`
769 ///
770 /// # Returns
771 ///
772 /// A `BoxBiPredicate` representing the logical XOR.
773 fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
774 where
775 Self: 'static,
776 P: BiPredicate<T, U> + 'static,
777 T: 'static,
778 U: 'static,
779 {
780 BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
781 }
782
783 /// Returns a bi-predicate that represents the logical NOR (NOT
784 /// OR) of this bi-predicate and another.
785 ///
786 /// NOR returns `true` only if both bi-predicates are `false`.
787 /// Equivalent to `!(self OR other)`.
788 ///
789 /// # Parameters
790 ///
791 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
792 /// is passed by value and will transfer ownership.** If you need to
793 /// preserve the original bi-predicate, clone it first (if it implements
794 /// `Clone`). Can be:
795 /// - Another closure: `|x: &T, y: &U| -> bool`
796 /// - A function pointer: `fn(&T, &U) -> bool`
797 /// - A `BoxBiPredicate<T, U>`
798 /// - An `RcBiPredicate<T, U>`
799 /// - An `ArcBiPredicate<T, U>`
800 /// - Any type implementing `BiPredicate<T, U>`
801 ///
802 /// # Returns
803 ///
804 /// A `BoxBiPredicate` representing the logical NOR.
805 fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
806 where
807 Self: 'static,
808 P: BiPredicate<T, U> + 'static,
809 T: 'static,
810 U: 'static,
811 {
812 BoxBiPredicate::new(move |first, second| {
813 !(self(first, second) || other.test(first, second))
814 })
815 }
816}
817
818// Blanket implementation for all closures
819impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool {}