Skip to main content

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}