qubit_function/tester/rc_tester.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `RcTester` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15// ============================================================================
16// RcTester: Single-Threaded Shared Ownership Implementation
17// ============================================================================
18
19/// Single-threaded shared ownership Tester implemented using `Rc`
20///
21/// `RcTester` wraps a closure in `Rc<dyn Fn() -> bool>`, allowing the tester
22/// to be cloned and shared within a single thread. Since it doesn't use atomic
23/// operations, it has lower overhead than `ArcTester`.
24///
25/// # Characteristics
26///
27/// - **Shared ownership**: Can be cloned
28/// - **Single-threaded**: Cannot be sent across threads
29/// - **Low overhead**: Uses `Fn` without needing `RefCell`
30/// - **Borrowing combination**: `and()`/`or()`/`not()` borrow `&self`
31///
32/// # Use Cases
33///
34/// - Single-threaded testing scenarios requiring sharing
35/// - Event-driven systems (single-threaded)
36/// - Callback-intensive code requiring cloneable tests
37/// - Performance-sensitive single-threaded code
38///
39/// # Examples
40///
41/// ```rust
42/// use qubit_function::{RcTester, Tester};
43///
44/// let shared = RcTester::new(|| true);
45///
46/// // Clone for multiple uses
47/// let clone1 = shared.clone();
48/// let clone2 = shared.clone();
49///
50/// // Non-consuming combination
51/// let combined = shared.and(&clone1);
52/// ```
53///
54/// # Author
55///
56/// Haixing Hu
57pub struct RcTester {
58 pub(super) function: Rc<dyn Fn() -> bool>,
59}
60
61impl RcTester {
62 /// Creates a new `RcTester` from a closure
63 ///
64 /// # Type Parameters
65 ///
66 /// * `F` - Closure type implementing `Fn() -> bool`
67 ///
68 /// # Parameters
69 ///
70 /// * `f` - The closure to wrap
71 ///
72 /// # Return Value
73 ///
74 /// A new `RcTester` instance
75 ///
76 /// # Examples
77 ///
78 /// ```rust
79 /// use qubit_function::RcTester;
80 ///
81 /// let tester = RcTester::new(|| true);
82 /// ```
83 #[inline]
84 pub fn new<F>(f: F) -> Self
85 where
86 F: Fn() -> bool + 'static,
87 {
88 RcTester {
89 function: Rc::new(f),
90 }
91 }
92
93 /// Combines this tester with another tester using logical AND
94 ///
95 /// Returns a new `RcTester` that returns `true` only when both tests
96 /// pass. Borrows `&self`, so the original tester remains available.
97 ///
98 /// # Parameters
99 ///
100 /// * `next` - The tester to combine with
101 ///
102 /// # Return Value
103 ///
104 /// A new `RcTester` representing logical AND
105 ///
106 /// # Examples
107 ///
108 /// ```rust
109 /// use qubit_function::{RcTester, Tester};
110 ///
111 /// let first = RcTester::new(|| true);
112 /// let second = RcTester::new(|| true);
113 /// let combined = first.and(&second);
114 /// // first and second are still available
115 /// ```
116 #[inline]
117 pub fn and(&self, next: &RcTester) -> RcTester {
118 let self_fn = Rc::clone(&self.function);
119 let next_fn = Rc::clone(&next.function);
120 RcTester {
121 function: Rc::new(move || self_fn() && next_fn()),
122 }
123 }
124
125 /// Combines this tester with another tester using logical OR
126 ///
127 /// Returns a new `RcTester` that returns `true` if either test passes.
128 /// Borrows `&self`, so the original tester remains available.
129 ///
130 /// # Parameters
131 ///
132 /// * `next` - The tester to combine with
133 ///
134 /// # Return Value
135 ///
136 /// A new `RcTester` representing logical OR
137 ///
138 /// # Examples
139 ///
140 /// ```rust
141 /// use qubit_function::{RcTester, Tester};
142 ///
143 /// let first = RcTester::new(|| false);
144 /// let second = RcTester::new(|| true);
145 /// let combined = first.or(&second);
146 /// // first and second are still available
147 /// ```
148 #[inline]
149 pub fn or(&self, next: &RcTester) -> RcTester {
150 let self_fn = Rc::clone(&self.function);
151 let next_fn = Rc::clone(&next.function);
152 RcTester {
153 function: Rc::new(move || self_fn() || next_fn()),
154 }
155 }
156
157 /// Negates the result of this tester
158 ///
159 /// Returns a new `RcTester` that returns the opposite value of the
160 /// original test result. Borrows `&self`, so the original tester remains
161 /// available.
162 ///
163 /// # Return Value
164 ///
165 /// A new `RcTester` representing logical NOT
166 ///
167 /// # Examples
168 ///
169 /// ```rust
170 /// use qubit_function::{RcTester, Tester};
171 ///
172 /// let original = RcTester::new(|| true);
173 /// let negated = original.not();
174 /// // original is still available
175 /// ```
176 #[allow(clippy::should_implement_trait)]
177 #[inline]
178 pub fn not(&self) -> RcTester {
179 let self_fn = Rc::clone(&self.function);
180 RcTester {
181 function: Rc::new(move || !self_fn()),
182 }
183 }
184
185 /// Combines this tester with another tester using logical NAND
186 ///
187 /// Returns a new `RcTester` that returns `true` unless both tests pass.
188 /// Borrows `&self`, so the original tester remains available.
189 ///
190 /// # Parameters
191 ///
192 /// * `next` - The tester to combine with
193 ///
194 /// # Return Value
195 ///
196 /// A new `RcTester` representing logical NAND
197 ///
198 /// # Examples
199 ///
200 /// ```rust
201 /// use qubit_function::{RcTester, Tester};
202 ///
203 /// let first = RcTester::new(|| true);
204 /// let second = RcTester::new(|| true);
205 /// let nand = first.nand(&second);
206 ///
207 /// // Both true returns false
208 /// assert!(!nand.test());
209 ///
210 /// // first and second still available
211 /// assert!(first.test());
212 /// assert!(second.test());
213 /// ```
214 #[inline]
215 pub fn nand(&self, next: &RcTester) -> RcTester {
216 let self_fn = Rc::clone(&self.function);
217 let next_fn = Rc::clone(&next.function);
218 RcTester {
219 function: Rc::new(move || !(self_fn() && next_fn())),
220 }
221 }
222
223 /// Combines this tester with another tester using logical XOR
224 ///
225 /// Returns a new `RcTester` that returns `true` if exactly one test
226 /// passes. Borrows `&self`, so the original tester remains available.
227 ///
228 /// # Parameters
229 ///
230 /// * `next` - The tester to combine with
231 ///
232 /// # Return Value
233 ///
234 /// A new `RcTester` representing logical XOR
235 ///
236 /// # Examples
237 ///
238 /// ```rust
239 /// use qubit_function::{RcTester, Tester};
240 ///
241 /// let first = RcTester::new(|| true);
242 /// let second = RcTester::new(|| false);
243 /// let xor = first.xor(&second);
244 ///
245 /// // One true one false returns true
246 /// assert!(xor.test());
247 ///
248 /// // first and second still available
249 /// assert!(first.test());
250 /// assert!(!second.test());
251 /// ```
252 #[inline]
253 pub fn xor(&self, next: &RcTester) -> RcTester {
254 let self_fn = Rc::clone(&self.function);
255 let next_fn = Rc::clone(&next.function);
256 RcTester {
257 function: Rc::new(move || self_fn() ^ next_fn()),
258 }
259 }
260
261 /// Combines this tester with another tester using logical NOR
262 ///
263 /// Returns a new `RcTester` that returns `true` only when both tests
264 /// fail. Borrows `&self`, so the original tester remains available.
265 ///
266 /// # Parameters
267 ///
268 /// * `next` - The tester to combine with
269 ///
270 /// # Return Value
271 ///
272 /// A new `RcTester` representing logical NOR
273 ///
274 /// # Examples
275 ///
276 /// ```rust
277 /// use qubit_function::{RcTester, Tester};
278 ///
279 /// let first = RcTester::new(|| false);
280 /// let second = RcTester::new(|| false);
281 /// let nor = first.nor(&second);
282 ///
283 /// // Both false returns true
284 /// assert!(nor.test());
285 ///
286 /// // first and second still available
287 /// assert!(!first.test());
288 /// assert!(!second.test());
289 /// ```
290 #[inline]
291 pub fn nor(&self, next: &RcTester) -> RcTester {
292 let self_fn = Rc::clone(&self.function);
293 let next_fn = Rc::clone(&next.function);
294 RcTester {
295 function: Rc::new(move || !(self_fn() || next_fn())),
296 }
297 }
298}
299
300impl Tester for RcTester {
301 #[inline]
302 fn test(&self) -> bool {
303 (self.function)()
304 }
305
306 #[inline]
307 fn into_box(self) -> BoxTester {
308 BoxTester {
309 function: Box::new(move || (self.function)()),
310 }
311 }
312
313 #[inline]
314 fn into_rc(self) -> RcTester {
315 self
316 }
317
318 // Note: RcTester is not Send + Sync, so into_arc() cannot be
319 // implemented. Calling into_arc() on RcTester will result in a
320 // compile error due to the Send + Sync trait bounds not being
321 // satisfied. The default Tester trait implementation will be used.
322
323 #[inline]
324 fn into_fn(self) -> impl Fn() -> bool {
325 move || (self.function)()
326 }
327
328 #[inline]
329 fn to_box(&self) -> BoxTester {
330 let self_fn = self.function.clone();
331 BoxTester {
332 function: Box::new(move || self_fn()),
333 }
334 }
335
336 #[inline]
337 fn to_rc(&self) -> RcTester {
338 self.clone()
339 }
340
341 // Note: RcTester is not Send + Sync, so to_arc() cannot be
342 // implemented. Calling to_arc() on RcTester will result in a compile
343 // error due to the Send + Sync trait bounds not being satisfied. The
344 // default Tester trait implementation will be used.
345
346 #[inline]
347 fn to_fn(&self) -> impl Fn() -> bool {
348 let self_fn = self.function.clone();
349 move || self_fn()
350 }
351}
352
353impl Clone for RcTester {
354 /// Creates a clone of this `RcTester`.
355 ///
356 /// The cloned instance shares the same underlying function with
357 /// the original, allowing multiple references to the same test
358 /// logic.
359 #[inline]
360 fn clone(&self) -> Self {
361 Self {
362 function: Rc::clone(&self.function),
363 }
364 }
365}
366
367// ============================================================================
368// Tester Implementation for Closures
369// ============================================================================
370
371impl<F> Tester for F
372where
373 F: Fn() -> bool,
374{
375 #[inline]
376 fn test(&self) -> bool {
377 self()
378 }
379
380 #[inline]
381 fn into_box(self) -> BoxTester
382 where
383 Self: Sized + 'static,
384 {
385 BoxTester::new(self)
386 }
387
388 #[inline]
389 fn into_rc(self) -> RcTester
390 where
391 Self: Sized + 'static,
392 {
393 RcTester::new(self)
394 }
395
396 #[inline]
397 fn into_arc(self) -> ArcTester
398 where
399 Self: Sized + Send + Sync + 'static,
400 {
401 ArcTester::new(self)
402 }
403
404 #[inline]
405 fn into_fn(self) -> impl Fn() -> bool
406 where
407 Self: Sized + 'static,
408 {
409 self
410 }
411
412 #[inline]
413 fn to_box(&self) -> BoxTester
414 where
415 Self: Clone + Sized + 'static,
416 {
417 self.clone().into_box()
418 }
419
420 #[inline]
421 fn to_rc(&self) -> RcTester
422 where
423 Self: Clone + Sized + 'static,
424 {
425 self.clone().into_rc()
426 }
427
428 #[inline]
429 fn to_arc(&self) -> ArcTester
430 where
431 Self: Clone + Sized + Send + Sync + 'static,
432 {
433 self.clone().into_arc()
434 }
435
436 #[inline]
437 fn to_fn(&self) -> impl Fn() -> bool
438 where
439 Self: Clone + Sized,
440 {
441 self.clone()
442 }
443}