Skip to main content

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