Skip to main content

qubit_function/predicates/bi_predicate/
fn_bi_predicate_ops.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `FnBiPredicateOps` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15/// Extension trait providing logical composition methods for closures.
16///
17/// This trait is automatically implemented for all closures and
18/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
19/// chaining starting from a closure.
20///
21/// # Examples
22///
23/// ```rust
24/// use qubit_function::{BiPredicate, FnBiPredicateOps};
25///
26/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
27/// let first_larger = |x: &i32, y: &i32| x > y;
28///
29/// // Combine bi-predicates using extension methods
30/// let pred = is_sum_positive.and(first_larger);
31/// assert!(pred.test(&10, &5));
32/// assert!(!pred.test(&3, &8));
33/// ```
34///
35/// # Author
36///
37/// Haixing Hu
38pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized {
39    /// Returns a bi-predicate that represents the logical AND of this
40    /// bi-predicate and another.
41    ///
42    /// # Parameters
43    ///
44    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
45    ///   is passed by value and will transfer ownership.** If you need to
46    ///   preserve the original bi-predicate, clone it first (if it implements
47    ///   `Clone`). Can be:
48    ///   - Another closure: `|x: &T, y: &U| -> bool`
49    ///   - A function pointer: `fn(&T, &U) -> bool`
50    ///   - A `BoxBiPredicate<T, U>`
51    ///   - An `RcBiPredicate<T, U>`
52    ///   - An `ArcBiPredicate<T, U>`
53    ///   - Any type implementing `BiPredicate<T, U>`
54    ///
55    /// # Returns
56    ///
57    /// A `BoxBiPredicate` representing the logical AND.
58    fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
59    where
60        Self: 'static,
61        P: BiPredicate<T, U> + 'static,
62        T: 'static,
63        U: 'static,
64    {
65        BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
66    }
67
68    /// Returns a bi-predicate that represents the logical OR of this
69    /// bi-predicate and another.
70    ///
71    /// # Parameters
72    ///
73    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
74    ///   is passed by value and will transfer ownership.** If you need to
75    ///   preserve the original bi-predicate, clone it first (if it implements
76    ///   `Clone`). Can be:
77    ///   - Another closure: `|x: &T, y: &U| -> bool`
78    ///   - A function pointer: `fn(&T, &U) -> bool`
79    ///   - A `BoxBiPredicate<T, U>`
80    ///   - An `RcBiPredicate<T, U>`
81    ///   - An `ArcBiPredicate<T, U>`
82    ///   - Any type implementing `BiPredicate<T, U>`
83    ///
84    /// # Returns
85    ///
86    /// A `BoxBiPredicate` representing the logical OR.
87    fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
88    where
89        Self: 'static,
90        P: BiPredicate<T, U> + 'static,
91        T: 'static,
92        U: 'static,
93    {
94        BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
95    }
96
97    /// Returns a bi-predicate that represents the logical negation of
98    /// this bi-predicate.
99    ///
100    /// # Returns
101    ///
102    /// A `BoxBiPredicate` representing the logical negation.
103    fn not(self) -> BoxBiPredicate<T, U>
104    where
105        Self: 'static,
106        T: 'static,
107        U: 'static,
108    {
109        BoxBiPredicate::new(move |first, second| !self(first, second))
110    }
111
112    /// Returns a bi-predicate that represents the logical NAND (NOT
113    /// AND) of this bi-predicate and another.
114    ///
115    /// NAND returns `true` unless both bi-predicates are `true`.
116    /// Equivalent to `!(self AND other)`.
117    ///
118    /// # Parameters
119    ///
120    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
121    ///   is passed by value and will transfer ownership.** If you need to
122    ///   preserve the original bi-predicate, clone it first (if it implements
123    ///   `Clone`). Can be:
124    ///   - Another closure: `|x: &T, y: &U| -> bool`
125    ///   - A function pointer: `fn(&T, &U) -> bool`
126    ///   - A `BoxBiPredicate<T, U>`
127    ///   - An `RcBiPredicate<T, U>`
128    ///   - An `ArcBiPredicate<T, U>`
129    ///   - Any type implementing `BiPredicate<T, U>`
130    ///
131    /// # Returns
132    ///
133    /// A `BoxBiPredicate` representing the logical NAND.
134    fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
135    where
136        Self: 'static,
137        P: BiPredicate<T, U> + 'static,
138        T: 'static,
139        U: 'static,
140    {
141        BoxBiPredicate::new(move |first, second| {
142            !(self(first, second) && other.test(first, second))
143        })
144    }
145
146    /// Returns a bi-predicate that represents the logical XOR
147    /// (exclusive OR) of this bi-predicate and another.
148    ///
149    /// XOR returns `true` if exactly one of the bi-predicates is
150    /// `true`.
151    ///
152    /// # Parameters
153    ///
154    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
155    ///   is passed by value and will transfer ownership.** If you need to
156    ///   preserve the original bi-predicate, clone it first (if it implements
157    ///   `Clone`). Can be:
158    ///   - Another closure: `|x: &T, y: &U| -> bool`
159    ///   - A function pointer: `fn(&T, &U) -> bool`
160    ///   - A `BoxBiPredicate<T, U>`
161    ///   - An `RcBiPredicate<T, U>`
162    ///   - An `ArcBiPredicate<T, U>`
163    ///   - Any type implementing `BiPredicate<T, U>`
164    ///
165    /// # Returns
166    ///
167    /// A `BoxBiPredicate` representing the logical XOR.
168    fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
169    where
170        Self: 'static,
171        P: BiPredicate<T, U> + 'static,
172        T: 'static,
173        U: 'static,
174    {
175        BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
176    }
177
178    /// Returns a bi-predicate that represents the logical NOR (NOT
179    /// OR) of this bi-predicate and another.
180    ///
181    /// NOR returns `true` only if both bi-predicates are `false`.
182    /// Equivalent to `!(self OR other)`.
183    ///
184    /// # Parameters
185    ///
186    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
187    ///   is passed by value and will transfer ownership.** If you need to
188    ///   preserve the original bi-predicate, clone it first (if it implements
189    ///   `Clone`). Can be:
190    ///   - Another closure: `|x: &T, y: &U| -> bool`
191    ///   - A function pointer: `fn(&T, &U) -> bool`
192    ///   - A `BoxBiPredicate<T, U>`
193    ///   - An `RcBiPredicate<T, U>`
194    ///   - An `ArcBiPredicate<T, U>`
195    ///   - Any type implementing `BiPredicate<T, U>`
196    ///
197    /// # Returns
198    ///
199    /// A `BoxBiPredicate` representing the logical NOR.
200    fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
201    where
202        Self: 'static,
203        P: BiPredicate<T, U> + 'static,
204        T: 'static,
205        U: 'static,
206    {
207        BoxBiPredicate::new(move |first, second| {
208            !(self(first, second) || other.test(first, second))
209        })
210    }
211}
212
213// Blanket implementation for all closures
214impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool {}