Skip to main content

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