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