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 {}