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