prism3_function/predicates/
bi_predicate.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism 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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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 prism3_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        T: 'static,
388        U: 'static,
389    {
390        move |first, second| self.test(first, second)
391    }
392
393    fn to_box(&self) -> BoxBiPredicate<T, U>
394    where
395        Self: Sized + Clone + 'static,
396        T: 'static,
397        U: 'static,
398    {
399        self.clone().into_box()
400    }
401
402    fn to_rc(&self) -> RcBiPredicate<T, U>
403    where
404        Self: Sized + Clone + 'static,
405        T: 'static,
406        U: 'static,
407    {
408        self.clone().into_rc()
409    }
410
411    fn to_arc(&self) -> ArcBiPredicate<T, U>
412    where
413        Self: Sized + Clone + Send + Sync + 'static,
414        T: 'static,
415        U: 'static,
416    {
417        self.clone().into_arc()
418    }
419
420    fn to_fn(&self) -> impl Fn(&T, &U) -> bool
421    where
422        Self: Sized + Clone + 'static,
423        T: 'static,
424        U: 'static,
425    {
426        self.clone().into_fn()
427    }
428}
429
430/// A Box-based bi-predicate with single ownership.
431///
432/// This type is suitable for one-time use scenarios where the
433/// bi-predicate does not need to be cloned or shared. Composition
434/// methods consume `self`, reflecting the single-ownership model.
435///
436/// # Examples
437///
438/// ```rust
439/// use prism3_function::bi_predicate::{BiPredicate, BoxBiPredicate};
440///
441/// let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
442/// assert!(pred.test(&5, &3));
443///
444/// // Chaining consumes the bi-predicate
445/// let combined = pred.and(BoxBiPredicate::new(|x, y| x > y));
446/// assert!(combined.test(&10, &5));
447/// ```
448///
449/// # Author
450///
451/// Haixing Hu
452pub struct BoxBiPredicate<T, U> {
453    function: Box<BiPredicateFn<T, U>>,
454    name: Option<String>,
455}
456
457impl<T, U> BoxBiPredicate<T, U> {
458    // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
459    impl_predicate_common_methods!(
460        BoxBiPredicate<T, U>,
461        (Fn(&T, &U) -> bool + 'static),
462        |f| Box::new(f)
463    );
464
465    // Generates: and(), or(), not(), nand(), xor(), nor()
466    impl_box_predicate_methods!(BoxBiPredicate<T, U>);
467}
468
469// Generates: impl Debug for BoxBiPredicate<T, U> and impl Display for BoxBiPredicate<T, U>
470impl_predicate_debug_display!(BoxBiPredicate<T, U>);
471
472impl<T, U> BiPredicate<T, U> for BoxBiPredicate<T, U> {
473    fn test(&self, first: &T, second: &U) -> bool {
474        (self.function)(first, second)
475    }
476
477    // Generates: into_box(), into_rc(), into_fn()
478    impl_box_conversions!(
479        BoxBiPredicate<T, U>,
480        RcBiPredicate,
481        Fn(&T, &U) -> bool
482    );
483}
484
485/// An Rc-based bi-predicate with single-threaded shared ownership.
486///
487/// This type is suitable for scenarios where the bi-predicate needs
488/// to be reused in a single-threaded context. Composition methods
489/// borrow `&self`, allowing the original bi-predicate to remain
490/// usable after composition.
491///
492/// # Examples
493///
494/// ```rust
495/// use prism3_function::bi_predicate::{BiPredicate, RcBiPredicate};
496///
497/// let pred = RcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
498/// assert!(pred.test(&5, &3));
499///
500/// // Original bi-predicate remains usable after composition
501/// let combined = pred.and(RcBiPredicate::new(|x, y| x > y));
502/// assert!(pred.test(&5, &3));  // Still works
503/// ```
504///
505/// # Author
506///
507/// Haixing Hu
508pub struct RcBiPredicate<T, U> {
509    function: Rc<BiPredicateFn<T, U>>,
510    name: Option<String>,
511}
512
513impl<T: 'static, U: 'static> RcBiPredicate<T, U> {
514    // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
515    impl_predicate_common_methods!(
516        RcBiPredicate<T, U>,
517        (Fn(&T, &U) -> bool + 'static),
518        |f| Rc::new(f)
519    );
520
521    // Generates: and(), or(), not(), nand(), xor(), nor()
522    impl_shared_predicate_methods!(RcBiPredicate<T, U>, 'static);
523}
524
525// Generates: impl Clone for RcBiPredicate<T, U>
526impl_predicate_clone!(RcBiPredicate<T, U>);
527
528// Generates: impl Debug for RcBiPredicate<T, U> and impl Display for RcBiPredicate<T, U>
529impl_predicate_debug_display!(RcBiPredicate<T, U>);
530
531// Implements BiPredicate trait for RcBiPredicate<T, U>
532impl<T, U> BiPredicate<T, U> for RcBiPredicate<T, U> {
533    fn test(&self, first: &T, second: &U) -> bool {
534        (self.function)(first, second)
535    }
536
537    // Generates: into_box(), into_rc(), into_fn(), to_box(), to_rc(), to_fn()
538    impl_rc_conversions!(
539        RcBiPredicate<T, U>,
540        BoxBiPredicate,
541        Fn(first: &T, second: &U) -> bool
542    );
543}
544
545/// An Arc-based bi-predicate with thread-safe shared ownership.
546///
547/// This type is suitable for scenarios where the bi-predicate needs
548/// to be shared across threads. Composition methods borrow `&self`,
549/// allowing the original bi-predicate to remain usable after
550/// composition.
551///
552/// # Examples
553///
554/// ```rust
555/// use prism3_function::bi_predicate::{BiPredicate, ArcBiPredicate};
556///
557/// let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
558/// assert!(pred.test(&5, &3));
559///
560/// // Original bi-predicate remains usable after composition
561/// let combined = pred.and(ArcBiPredicate::new(|x, y| x > y));
562/// assert!(pred.test(&5, &3));  // Still works
563///
564/// // Can be cloned and sent across threads
565/// let pred_clone = pred.clone();
566/// std::thread::spawn(move || {
567///     assert!(pred_clone.test(&10, &5));
568/// }).join().unwrap();
569/// ```
570///
571/// # Author
572///
573/// Haixing Hu
574pub struct ArcBiPredicate<T, U> {
575    function: Arc<SendSyncBiPredicateFn<T, U>>,
576    name: Option<String>,
577}
578
579impl<T: 'static, U: 'static> ArcBiPredicate<T, U> {
580    // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
581    impl_predicate_common_methods!(
582        ArcBiPredicate<T, U>,
583        (Fn(&T, &U) -> bool + Send + Sync + 'static),
584        |f| Arc::new(f)
585    );
586
587    // Generates: and(), or(), not(), nand(), xor(), nor()
588    impl_shared_predicate_methods!(
589        ArcBiPredicate<T, U>,
590        Send + Sync + 'static
591    );
592}
593
594// Generates: impl Clone for ArcBiPredicate<T, U>
595impl_predicate_clone!(ArcBiPredicate<T, U>);
596
597// Generates: impl Debug for ArcBiPredicate<T, U> and impl Display for ArcBiPredicate<T, U>
598impl_predicate_debug_display!(ArcBiPredicate<T, U>);
599
600// Implements BiPredicate trait for ArcBiPredicate<T, U>
601impl<T: 'static, U: 'static> BiPredicate<T, U> for ArcBiPredicate<T, U> {
602    fn test(&self, first: &T, second: &U) -> bool {
603        (self.function)(first, second)
604    }
605
606    // Generates: into_box, into_rc, into_arc, into_fn, to_box, to_rc, to_arc, to_fn
607    impl_arc_conversions!(
608        ArcBiPredicate<T, U>,
609        BoxBiPredicate,
610        RcBiPredicate,
611        Fn(first: &T, second: &U) -> bool
612    );
613}
614
615// Blanket implementation for all closures that match
616// Fn(&T, &U) -> bool. This provides optimal implementations for
617// closures by wrapping them directly into the target type.
618impl_closure_trait!(
619    BiPredicate<T, U>,
620    test,
621    Fn(first: &T, second: &U) -> bool
622);
623
624/// Extension trait providing logical composition methods for closures.
625///
626/// This trait is automatically implemented for all closures and
627/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
628/// chaining starting from a closure.
629///
630/// # Examples
631///
632/// ```rust
633/// use prism3_function::bi_predicate::{BiPredicate, FnBiPredicateOps};
634///
635/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
636/// let first_larger = |x: &i32, y: &i32| x > y;
637///
638/// // Combine bi-predicates using extension methods
639/// let pred = is_sum_positive.and(first_larger);
640/// assert!(pred.test(&10, &5));
641/// assert!(!pred.test(&3, &8));
642/// ```
643///
644/// # Author
645///
646/// Haixing Hu
647pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized + 'static {
648    /// Returns a bi-predicate that represents the logical AND of this
649    /// bi-predicate and another.
650    ///
651    /// # Parameters
652    ///
653    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
654    ///   is passed by value and will transfer ownership.** If you need to
655    ///   preserve the original bi-predicate, clone it first (if it implements
656    ///   `Clone`). Can be:
657    ///   - Another closure: `|x: &T, y: &U| -> bool`
658    ///   - A function pointer: `fn(&T, &U) -> bool`
659    ///   - A `BoxBiPredicate<T, U>`
660    ///   - An `RcBiPredicate<T, U>`
661    ///   - An `ArcBiPredicate<T, U>`
662    ///   - Any type implementing `BiPredicate<T, U>`
663    ///
664    /// # Returns
665    ///
666    /// A `BoxBiPredicate` representing the logical AND.
667    fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
668    where
669        P: BiPredicate<T, U> + 'static,
670        T: 'static,
671        U: 'static,
672    {
673        BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
674    }
675
676    /// Returns a bi-predicate that represents the logical OR of this
677    /// bi-predicate and another.
678    ///
679    /// # Parameters
680    ///
681    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
682    ///   is passed by value and will transfer ownership.** If you need to
683    ///   preserve the original bi-predicate, clone it first (if it implements
684    ///   `Clone`). Can be:
685    ///   - Another closure: `|x: &T, y: &U| -> bool`
686    ///   - A function pointer: `fn(&T, &U) -> bool`
687    ///   - A `BoxBiPredicate<T, U>`
688    ///   - An `RcBiPredicate<T, U>`
689    ///   - An `ArcBiPredicate<T, U>`
690    ///   - Any type implementing `BiPredicate<T, U>`
691    ///
692    /// # Returns
693    ///
694    /// A `BoxBiPredicate` representing the logical OR.
695    fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
696    where
697        P: BiPredicate<T, U> + 'static,
698        T: 'static,
699        U: 'static,
700    {
701        BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
702    }
703
704    /// Returns a bi-predicate that represents the logical negation of
705    /// this bi-predicate.
706    ///
707    /// # Returns
708    ///
709    /// A `BoxBiPredicate` representing the logical negation.
710    fn not(self) -> BoxBiPredicate<T, U>
711    where
712        T: 'static,
713        U: 'static,
714    {
715        BoxBiPredicate::new(move |first, second| !self(first, second))
716    }
717
718    /// Returns a bi-predicate that represents the logical NAND (NOT
719    /// AND) of this bi-predicate and another.
720    ///
721    /// NAND returns `true` unless both bi-predicates are `true`.
722    /// Equivalent to `!(self AND other)`.
723    ///
724    /// # Parameters
725    ///
726    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
727    ///   is passed by value and will transfer ownership.** If you need to
728    ///   preserve the original bi-predicate, clone it first (if it implements
729    ///   `Clone`). Can be:
730    ///   - Another closure: `|x: &T, y: &U| -> bool`
731    ///   - A function pointer: `fn(&T, &U) -> bool`
732    ///   - A `BoxBiPredicate<T, U>`
733    ///   - An `RcBiPredicate<T, U>`
734    ///   - An `ArcBiPredicate<T, U>`
735    ///   - Any type implementing `BiPredicate<T, U>`
736    ///
737    /// # Returns
738    ///
739    /// A `BoxBiPredicate` representing the logical NAND.
740    fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
741    where
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        P: BiPredicate<T, U> + 'static,
776        T: 'static,
777        U: 'static,
778    {
779        BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
780    }
781
782    /// Returns a bi-predicate that represents the logical NOR (NOT
783    /// OR) of this bi-predicate and another.
784    ///
785    /// NOR returns `true` only if both bi-predicates are `false`.
786    /// Equivalent to `!(self OR other)`.
787    ///
788    /// # Parameters
789    ///
790    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
791    ///   is passed by value and will transfer ownership.** If you need to
792    ///   preserve the original bi-predicate, clone it first (if it implements
793    ///   `Clone`). Can be:
794    ///   - Another closure: `|x: &T, y: &U| -> bool`
795    ///   - A function pointer: `fn(&T, &U) -> bool`
796    ///   - A `BoxBiPredicate<T, U>`
797    ///   - An `RcBiPredicate<T, U>`
798    ///   - An `ArcBiPredicate<T, U>`
799    ///   - Any type implementing `BiPredicate<T, U>`
800    ///
801    /// # Returns
802    ///
803    /// A `BoxBiPredicate` representing the logical NOR.
804    fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
805    where
806        P: BiPredicate<T, U> + 'static,
807        T: 'static,
808        U: 'static,
809    {
810        BoxBiPredicate::new(move |first, second| {
811            !(self(first, second) || other.test(first, second))
812        })
813    }
814}
815
816// Blanket implementation for all closures
817impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool + 'static {}