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