Skip to main content

qubit_function/predicates/predicate/
fn_predicate_ops.rs

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