Skip to main content

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