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
13use std::ops::Not;
14
15use super::{
16    ArcTester,
17    BoxTester,
18    Rc,
19    Tester,
20};
21
22// ============================================================================
23// RcTester: Single-Threaded Shared Ownership Implementation
24// ============================================================================
25
26/// Single-threaded shared ownership Tester implemented using `Rc`
27///
28/// `RcTester` wraps a closure in `Rc<dyn Fn() -> bool>`, allowing the tester
29/// to be cloned and shared within a single thread. Since it doesn't use atomic
30/// operations, it has lower overhead than `ArcTester`.
31///
32/// # Characteristics
33///
34/// - **Shared ownership**: Can be cloned
35/// - **Single-threaded**: Cannot be sent across threads
36/// - **Low overhead**: Uses `Fn` without needing `RefCell`
37/// - **Borrowing combination**: `and()`/`or()` borrow `&self`
38///
39/// # Use Cases
40///
41/// - Single-threaded testing scenarios requiring sharing
42/// - Event-driven systems (single-threaded)
43/// - Callback-intensive code requiring cloneable tests
44/// - Performance-sensitive single-threaded code
45///
46/// # Examples
47///
48/// ```rust
49/// use qubit_function::{RcTester, Tester};
50///
51/// let shared = RcTester::new(|| true);
52///
53/// // Clone for multiple uses
54/// let clone1 = shared.clone();
55/// let clone2 = shared.clone();
56///
57/// // Non-consuming combination
58/// let combined = shared.and(&clone1);
59/// ```
60///
61pub struct RcTester {
62    pub(super) function: Rc<dyn Fn() -> bool>,
63}
64
65impl RcTester {
66    /// Creates a new `RcTester` from a closure
67    ///
68    /// # Type Parameters
69    ///
70    /// * `F` - Closure type implementing `Fn() -> bool`
71    ///
72    /// # Parameters
73    ///
74    /// * `f` - The closure to wrap
75    ///
76    /// # Return Value
77    ///
78    /// A new `RcTester` instance
79    ///
80    /// # Examples
81    ///
82    /// ```rust
83    /// use qubit_function::RcTester;
84    ///
85    /// let tester = RcTester::new(|| true);
86    /// ```
87    #[inline]
88    pub fn new<F>(f: F) -> Self
89    where
90        F: Fn() -> bool + 'static,
91    {
92        RcTester {
93            function: Rc::new(f),
94        }
95    }
96
97    /// Combines this tester with another tester using logical AND
98    ///
99    /// Returns a new `RcTester` that returns `true` only when both tests
100    /// pass. Borrows `&self`, so the original tester remains available.
101    ///
102    /// # Parameters
103    ///
104    /// * `next` - The tester to combine with
105    ///
106    /// # Return Value
107    ///
108    /// A new `RcTester` representing logical AND
109    ///
110    /// # Examples
111    ///
112    /// ```rust
113    /// use qubit_function::{RcTester, Tester};
114    ///
115    /// let first = RcTester::new(|| true);
116    /// let second = RcTester::new(|| true);
117    /// let combined = first.and(&second);
118    /// // first and second are still available
119    /// ```
120    #[inline]
121    pub fn and(&self, next: &RcTester) -> RcTester {
122        let self_fn = Rc::clone(&self.function);
123        let next_fn = Rc::clone(&next.function);
124        RcTester {
125            function: Rc::new(move || self_fn() && next_fn()),
126        }
127    }
128
129    /// Combines this tester with another tester using logical OR
130    ///
131    /// Returns a new `RcTester` that returns `true` if either test passes.
132    /// Borrows `&self`, so the original tester remains available.
133    ///
134    /// # Parameters
135    ///
136    /// * `next` - The tester to combine with
137    ///
138    /// # Return Value
139    ///
140    /// A new `RcTester` representing logical OR
141    ///
142    /// # Examples
143    ///
144    /// ```rust
145    /// use qubit_function::{RcTester, Tester};
146    ///
147    /// let first = RcTester::new(|| false);
148    /// let second = RcTester::new(|| true);
149    /// let combined = first.or(&second);
150    /// // first and second are still available
151    /// ```
152    #[inline]
153    pub fn or(&self, next: &RcTester) -> RcTester {
154        let self_fn = Rc::clone(&self.function);
155        let next_fn = Rc::clone(&next.function);
156        RcTester {
157            function: Rc::new(move || self_fn() || next_fn()),
158        }
159    }
160
161    /// Combines this tester with another tester using logical NAND
162    ///
163    /// Returns a new `RcTester` that returns `true` unless both tests pass.
164    /// Borrows `&self`, so the original tester remains available.
165    ///
166    /// # Parameters
167    ///
168    /// * `next` - The tester to combine with
169    ///
170    /// # Return Value
171    ///
172    /// A new `RcTester` representing logical NAND
173    ///
174    /// # Examples
175    ///
176    /// ```rust
177    /// use qubit_function::{RcTester, Tester};
178    ///
179    /// let first = RcTester::new(|| true);
180    /// let second = RcTester::new(|| true);
181    /// let nand = first.nand(&second);
182    ///
183    /// // Both true returns false
184    /// assert!(!nand.test());
185    ///
186    /// // first and second still available
187    /// assert!(first.test());
188    /// assert!(second.test());
189    /// ```
190    #[inline]
191    pub fn nand(&self, next: &RcTester) -> RcTester {
192        let self_fn = Rc::clone(&self.function);
193        let next_fn = Rc::clone(&next.function);
194        RcTester {
195            function: Rc::new(move || !(self_fn() && next_fn())),
196        }
197    }
198
199    /// Combines this tester with another tester using logical XOR
200    ///
201    /// Returns a new `RcTester` that returns `true` if exactly one test
202    /// passes. Borrows `&self`, so the original tester remains available.
203    ///
204    /// # Parameters
205    ///
206    /// * `next` - The tester to combine with
207    ///
208    /// # Return Value
209    ///
210    /// A new `RcTester` representing logical XOR
211    ///
212    /// # Examples
213    ///
214    /// ```rust
215    /// use qubit_function::{RcTester, Tester};
216    ///
217    /// let first = RcTester::new(|| true);
218    /// let second = RcTester::new(|| false);
219    /// let xor = first.xor(&second);
220    ///
221    /// // One true one false returns true
222    /// assert!(xor.test());
223    ///
224    /// // first and second still available
225    /// assert!(first.test());
226    /// assert!(!second.test());
227    /// ```
228    #[inline]
229    pub fn xor(&self, next: &RcTester) -> RcTester {
230        let self_fn = Rc::clone(&self.function);
231        let next_fn = Rc::clone(&next.function);
232        RcTester {
233            function: Rc::new(move || self_fn() ^ next_fn()),
234        }
235    }
236
237    /// Combines this tester with another tester using logical NOR
238    ///
239    /// Returns a new `RcTester` that returns `true` only when both tests
240    /// fail. Borrows `&self`, so the original tester remains available.
241    ///
242    /// # Parameters
243    ///
244    /// * `next` - The tester to combine with
245    ///
246    /// # Return Value
247    ///
248    /// A new `RcTester` representing logical NOR
249    ///
250    /// # Examples
251    ///
252    /// ```rust
253    /// use qubit_function::{RcTester, Tester};
254    ///
255    /// let first = RcTester::new(|| false);
256    /// let second = RcTester::new(|| false);
257    /// let nor = first.nor(&second);
258    ///
259    /// // Both false returns true
260    /// assert!(nor.test());
261    ///
262    /// // first and second still available
263    /// assert!(!first.test());
264    /// assert!(!second.test());
265    /// ```
266    #[inline]
267    pub fn nor(&self, next: &RcTester) -> RcTester {
268        let self_fn = Rc::clone(&self.function);
269        let next_fn = Rc::clone(&next.function);
270        RcTester {
271            function: Rc::new(move || !(self_fn() || next_fn())),
272        }
273    }
274}
275
276impl Not for RcTester {
277    type Output = RcTester;
278
279    #[inline]
280    fn not(self) -> Self::Output {
281        let func = self.function;
282        RcTester {
283            function: Rc::new(move || !func()),
284        }
285    }
286}
287
288impl Not for &RcTester {
289    type Output = RcTester;
290
291    #[inline]
292    fn not(self) -> Self::Output {
293        let func = Rc::clone(&self.function);
294        RcTester {
295            function: Rc::new(move || !func()),
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}