Skip to main content

qubit_function/predicates/predicate/
fn_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 `FnPredicateOps` 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 function
18/// pointers that match `Fn(&T) -> bool`, enabling method chaining starting
19/// from a closure.
20///
21/// # Examples
22///
23/// ```rust
24/// use qubit_function::{Predicate, FnPredicateOps};
25///
26/// let is_positive = |x: &i32| *x > 0;
27/// let is_even = |x: &i32| x % 2 == 0;
28///
29/// // Combine predicates using extension methods
30/// let pred = is_positive.and(is_even);
31/// assert!(pred.test(&4));
32/// assert!(!pred.test(&3));
33/// ```
34///
35/// # Author
36///
37/// Haixing Hu
38pub trait FnPredicateOps<T>: Fn(&T) -> bool + Sized {
39    /// Returns a predicate that represents the logical AND of this predicate
40    /// and another.
41    ///
42    /// # Parameters
43    ///
44    /// * `other` - The other predicate to combine with. **Note: This parameter
45    ///   is passed by value and will transfer ownership.** If you need to
46    ///   preserve the original predicate, clone it first (if it implements
47    ///   `Clone`). Can be:
48    ///   - Another closure
49    ///   - A function pointer
50    ///   - A `BoxPredicate<T>`, `RcPredicate<T>`, or `ArcPredicate<T>`
51    ///
52    /// # Returns
53    ///
54    /// A `BoxPredicate` representing the logical AND.
55    ///
56    /// # Examples
57    ///
58    /// ```rust
59    /// use qubit_function::{Predicate, FnPredicateOps};
60    ///
61    /// let is_positive = |x: &i32| *x > 0;
62    /// let is_even = |x: &i32| x % 2 == 0;
63    ///
64    /// let combined = is_positive.and(is_even);
65    /// assert!(combined.test(&4));
66    /// assert!(!combined.test(&3));
67    /// ```
68    fn and<P>(self, other: P) -> BoxPredicate<T>
69    where
70        Self: 'static,
71        P: Predicate<T> + 'static,
72        T: 'static,
73    {
74        BoxPredicate::new(move |value: &T| self.test(value) && other.test(value))
75    }
76
77    /// Returns a predicate that represents the logical OR of this predicate
78    /// and another.
79    ///
80    /// # Parameters
81    ///
82    /// * `other` - The other predicate to combine with. **Note: This parameter
83    ///   is passed by value and will transfer ownership.** If you need to
84    ///   preserve the original predicate, clone it first (if it implements
85    ///   `Clone`). Can be:
86    ///   - Another closure
87    ///   - A function pointer
88    ///   - A `BoxPredicate<T>`, `RcPredicate<T>`, or `ArcPredicate<T>`
89    ///   - Any type implementing `Predicate<T>`
90    ///
91    /// # Returns
92    ///
93    /// A `BoxPredicate` representing the logical OR.
94    ///
95    /// # Examples
96    ///
97    /// ```rust
98    /// use qubit_function::{Predicate, FnPredicateOps};
99    ///
100    /// let is_negative = |x: &i32| *x < 0;
101    /// let is_large = |x: &i32| *x > 100;
102    ///
103    /// let combined = is_negative.or(is_large);
104    /// assert!(combined.test(&-5));
105    /// assert!(combined.test(&150));
106    /// assert!(!combined.test(&50));
107    /// ```
108    fn or<P>(self, other: P) -> BoxPredicate<T>
109    where
110        Self: 'static,
111        P: Predicate<T> + 'static,
112        T: 'static,
113    {
114        BoxPredicate::new(move |value: &T| self.test(value) || other.test(value))
115    }
116
117    /// Returns a predicate that represents the logical negation of this
118    /// predicate.
119    ///
120    /// # Returns
121    ///
122    /// A `BoxPredicate` representing the logical negation.
123    fn not(self) -> BoxPredicate<T>
124    where
125        Self: 'static,
126        T: 'static,
127    {
128        BoxPredicate::new(move |value: &T| !self.test(value))
129    }
130
131    /// Returns a predicate that represents the logical NAND (NOT AND) of this
132    /// predicate and another.
133    ///
134    /// NAND returns `true` unless both predicates are `true`.
135    /// Equivalent to `!(self AND other)`.
136    ///
137    /// # Parameters
138    ///
139    /// * `other` - The other predicate to combine with. **Note: This parameter
140    ///   is passed by value and will transfer ownership.** If you need to
141    ///   preserve the original predicate, clone it first (if it implements
142    ///   `Clone`). Accepts closures, function pointers, or any
143    ///   `Predicate<T>` implementation.
144    ///
145    /// # Returns
146    ///
147    /// A `BoxPredicate` representing the logical NAND.
148    ///
149    /// # Examples
150    ///
151    /// ```rust
152    /// use qubit_function::{Predicate, FnPredicateOps};
153    ///
154    /// let is_positive = |x: &i32| *x > 0;
155    /// let is_even = |x: &i32| x % 2 == 0;
156    ///
157    /// let nand = is_positive.nand(is_even);
158    /// assert!(nand.test(&3));   // !(true && false) = true
159    /// assert!(!nand.test(&4));  // !(true && true) = false
160    /// ```
161    fn nand<P>(self, other: P) -> BoxPredicate<T>
162    where
163        Self: 'static,
164        P: Predicate<T> + 'static,
165        T: 'static,
166    {
167        BoxPredicate::new(move |value: &T| !(self.test(value) && other.test(value)))
168    }
169
170    /// Returns a predicate that represents the logical XOR (exclusive OR) of
171    /// this predicate and another.
172    ///
173    /// XOR returns `true` if exactly one of the predicates is `true`.
174    ///
175    /// # Parameters
176    ///
177    /// * `other` - The other predicate to combine with. **Note: This parameter
178    ///   is passed by value and will transfer ownership.** If you need to
179    ///   preserve the original predicate, clone it first (if it implements
180    ///   `Clone`). Accepts closures, function pointers, or any
181    ///   `Predicate<T>` implementation.
182    ///
183    /// # Returns
184    ///
185    /// A `BoxPredicate` representing the logical XOR.
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use qubit_function::{Predicate, FnPredicateOps};
191    ///
192    /// let is_positive = |x: &i32| *x > 0;
193    /// let is_even = |x: &i32| x % 2 == 0;
194    ///
195    /// let xor = is_positive.xor(is_even);
196    /// assert!(xor.test(&3));    // true ^ false = true
197    /// assert!(!xor.test(&4));   // true ^ true = false
198    /// assert!(!xor.test(&-1));  // false ^ false = false
199    /// ```
200    fn xor<P>(self, other: P) -> BoxPredicate<T>
201    where
202        Self: 'static,
203        P: Predicate<T> + 'static,
204        T: 'static,
205    {
206        BoxPredicate::new(move |value: &T| self.test(value) ^ other.test(value))
207    }
208
209    /// Returns a predicate that represents the logical NOR (NOT OR) of this
210    /// predicate and another.
211    ///
212    /// NOR returns `true` only when both predicates are `false`. Equivalent
213    /// to `!(self OR other)`.
214    ///
215    /// # Parameters
216    ///
217    /// * `other` - The other predicate to combine with. **Note: This parameter
218    ///   is passed by value and will transfer ownership.** If you need to
219    ///   preserve the original predicate, clone it first (if it implements
220    ///   `Clone`). Accepts closures, function pointers, or any
221    ///   `Predicate<T>` implementation.
222    ///
223    /// # Returns
224    ///
225    /// A `BoxPredicate` representing the logical NOR.
226    ///
227    /// # Examples
228    ///
229    /// ```rust
230    /// use qubit_function::{Predicate, FnPredicateOps};
231    ///
232    /// let is_positive = |x: &i32| *x > 0;
233    /// let is_even = |x: &i32| x % 2 == 0;
234    ///
235    /// let nor = is_positive.nor(is_even);
236    /// assert!(nor.test(&-3));   // !(false || false) = true
237    /// assert!(!nor.test(&4));   // !(true || true) = false
238    /// assert!(!nor.test(&3));   // !(true || false) = false
239    /// ```
240    fn nor<P>(self, other: P) -> BoxPredicate<T>
241    where
242        Self: 'static,
243        P: Predicate<T> + 'static,
244        T: 'static,
245    {
246        BoxPredicate::new(move |value: &T| !(self.test(value) || other.test(value)))
247    }
248}
249
250// Blanket implementation for all closures
251impl<T, F> FnPredicateOps<T> for F where F: Fn(&T) -> bool {}