Skip to main content

qubit_function/testers/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    Rc,
17    Tester,
18    arc_tester::ArcTester,
19    box_tester::BoxTester,
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 { function: Rc::new(f) }
93    }
94
95    /// Combines this tester with another tester using logical AND
96    ///
97    /// Returns a new `RcTester` that returns `true` only when both tests
98    /// pass. Borrows `&self`, so the original tester remains available.
99    ///
100    /// # Parameters
101    ///
102    /// * `next` - The tester to combine with
103    ///
104    /// # Return Value
105    ///
106    /// A new `RcTester` representing logical AND
107    ///
108    /// # Examples
109    ///
110    /// ```rust
111    /// use qubit_function::{RcTester, Tester};
112    ///
113    /// let first = RcTester::new(|| true);
114    /// let second = RcTester::new(|| true);
115    /// let combined = first.and(&second);
116    /// // first and second are still available
117    /// ```
118    #[inline]
119    pub fn and(&self, next: &RcTester) -> RcTester {
120        let self_fn = Rc::clone(&self.function);
121        let next_fn = Rc::clone(&next.function);
122        RcTester {
123            function: Rc::new(move || self_fn() && next_fn()),
124        }
125    }
126
127    /// Combines this tester with another tester using logical OR
128    ///
129    /// Returns a new `RcTester` that returns `true` if either test passes.
130    /// Borrows `&self`, so the original tester remains available.
131    ///
132    /// # Parameters
133    ///
134    /// * `next` - The tester to combine with
135    ///
136    /// # Return Value
137    ///
138    /// A new `RcTester` representing logical OR
139    ///
140    /// # Examples
141    ///
142    /// ```rust
143    /// use qubit_function::{RcTester, Tester};
144    ///
145    /// let first = RcTester::new(|| false);
146    /// let second = RcTester::new(|| true);
147    /// let combined = first.or(&second);
148    /// // first and second are still available
149    /// ```
150    #[inline]
151    pub fn or(&self, next: &RcTester) -> RcTester {
152        let self_fn = Rc::clone(&self.function);
153        let next_fn = Rc::clone(&next.function);
154        RcTester {
155            function: Rc::new(move || self_fn() || next_fn()),
156        }
157    }
158
159    /// Combines this tester with another tester using logical NAND
160    ///
161    /// Returns a new `RcTester` that returns `true` unless both tests pass.
162    /// Borrows `&self`, so the original tester remains available.
163    ///
164    /// # Parameters
165    ///
166    /// * `next` - The tester to combine with
167    ///
168    /// # Return Value
169    ///
170    /// A new `RcTester` representing logical NAND
171    ///
172    /// # Examples
173    ///
174    /// ```rust
175    /// use qubit_function::{RcTester, Tester};
176    ///
177    /// let first = RcTester::new(|| true);
178    /// let second = RcTester::new(|| true);
179    /// let nand = first.nand(&second);
180    ///
181    /// // Both true returns false
182    /// assert!(!nand.test());
183    ///
184    /// // first and second still available
185    /// assert!(first.test());
186    /// assert!(second.test());
187    /// ```
188    #[inline]
189    pub fn nand(&self, next: &RcTester) -> RcTester {
190        let self_fn = Rc::clone(&self.function);
191        let next_fn = Rc::clone(&next.function);
192        RcTester {
193            function: Rc::new(move || !(self_fn() && next_fn())),
194        }
195    }
196
197    /// Combines this tester with another tester using logical XOR
198    ///
199    /// Returns a new `RcTester` that returns `true` if exactly one test
200    /// passes. Borrows `&self`, so the original tester remains available.
201    ///
202    /// # Parameters
203    ///
204    /// * `next` - The tester to combine with
205    ///
206    /// # Return Value
207    ///
208    /// A new `RcTester` representing logical XOR
209    ///
210    /// # Examples
211    ///
212    /// ```rust
213    /// use qubit_function::{RcTester, Tester};
214    ///
215    /// let first = RcTester::new(|| true);
216    /// let second = RcTester::new(|| false);
217    /// let xor = first.xor(&second);
218    ///
219    /// // One true one false returns true
220    /// assert!(xor.test());
221    ///
222    /// // first and second still available
223    /// assert!(first.test());
224    /// assert!(!second.test());
225    /// ```
226    #[inline]
227    pub fn xor(&self, next: &RcTester) -> RcTester {
228        let self_fn = Rc::clone(&self.function);
229        let next_fn = Rc::clone(&next.function);
230        RcTester {
231            function: Rc::new(move || self_fn() ^ next_fn()),
232        }
233    }
234
235    /// Combines this tester with another tester using logical NOR
236    ///
237    /// Returns a new `RcTester` that returns `true` only when both tests
238    /// fail. Borrows `&self`, so the original tester remains available.
239    ///
240    /// # Parameters
241    ///
242    /// * `next` - The tester to combine with
243    ///
244    /// # Return Value
245    ///
246    /// A new `RcTester` representing logical NOR
247    ///
248    /// # Examples
249    ///
250    /// ```rust
251    /// use qubit_function::{RcTester, Tester};
252    ///
253    /// let first = RcTester::new(|| false);
254    /// let second = RcTester::new(|| false);
255    /// let nor = first.nor(&second);
256    ///
257    /// // Both false returns true
258    /// assert!(nor.test());
259    ///
260    /// // first and second still available
261    /// assert!(!first.test());
262    /// assert!(!second.test());
263    /// ```
264    #[inline]
265    pub fn nor(&self, next: &RcTester) -> RcTester {
266        let self_fn = Rc::clone(&self.function);
267        let next_fn = Rc::clone(&next.function);
268        RcTester {
269            function: Rc::new(move || !(self_fn() || next_fn())),
270        }
271    }
272}
273
274impl Not for RcTester {
275    type Output = RcTester;
276
277    #[inline]
278    fn not(self) -> Self::Output {
279        let func = self.function;
280        RcTester {
281            function: Rc::new(move || !func()),
282        }
283    }
284}
285
286impl Not for &RcTester {
287    type Output = RcTester;
288
289    #[inline]
290    fn not(self) -> Self::Output {
291        let func = Rc::clone(&self.function);
292        RcTester {
293            function: Rc::new(move || !func()),
294        }
295    }
296}
297
298impl Tester for RcTester {
299    #[inline]
300    fn test(&self) -> bool {
301        (self.function)()
302    }
303
304    #[inline]
305    fn into_box(self) -> BoxTester {
306        BoxTester {
307            function: Box::new(move || (self.function)()),
308        }
309    }
310
311    #[inline]
312    fn into_rc(self) -> RcTester {
313        self
314    }
315
316    // Note: RcTester is not Send + Sync, so into_arc() cannot be
317    // implemented. Calling into_arc() on RcTester will result in a
318    // compile error due to the Send + Sync trait bounds not being
319    // satisfied. The default Tester trait implementation will be used.
320
321    #[inline]
322    fn into_fn(self) -> impl Fn() -> bool {
323        move || (self.function)()
324    }
325
326    #[inline]
327    fn to_box(&self) -> BoxTester {
328        let self_fn = self.function.clone();
329        BoxTester {
330            function: Box::new(move || self_fn()),
331        }
332    }
333
334    #[inline]
335    fn to_rc(&self) -> RcTester {
336        self.clone()
337    }
338
339    // Note: RcTester is not Send + Sync, so to_arc() cannot be
340    // implemented. Calling to_arc() on RcTester will result in a compile
341    // error due to the Send + Sync trait bounds not being satisfied. The
342    // default Tester trait implementation will be used.
343
344    #[inline]
345    fn to_fn(&self) -> impl Fn() -> bool {
346        let self_fn = self.function.clone();
347        move || self_fn()
348    }
349}
350
351impl Clone for RcTester {
352    /// Creates a clone of this `RcTester`.
353    ///
354    /// The cloned instance shares the same underlying function with
355    /// the original, allowing multiple references to the same test
356    /// logic.
357    #[inline]
358    fn clone(&self) -> Self {
359        Self {
360            function: Rc::clone(&self.function),
361        }
362    }
363}
364
365// ============================================================================
366// Tester Implementation for Closures
367// ============================================================================
368
369impl<F> Tester for F
370where
371    F: Fn() -> bool,
372{
373    #[inline]
374    fn test(&self) -> bool {
375        self()
376    }
377
378    #[inline]
379    fn into_box(self) -> BoxTester
380    where
381        Self: Sized + 'static,
382    {
383        BoxTester::new(self)
384    }
385
386    #[inline]
387    fn into_rc(self) -> RcTester
388    where
389        Self: Sized + 'static,
390    {
391        RcTester::new(self)
392    }
393
394    #[inline]
395    fn into_arc(self) -> ArcTester
396    where
397        Self: Sized + Send + Sync + 'static,
398    {
399        ArcTester::new(self)
400    }
401
402    #[inline]
403    fn into_fn(self) -> impl Fn() -> bool
404    where
405        Self: Sized + 'static,
406    {
407        self
408    }
409
410    #[inline]
411    fn to_box(&self) -> BoxTester
412    where
413        Self: Clone + Sized + 'static,
414    {
415        self.clone().into_box()
416    }
417
418    #[inline]
419    fn to_rc(&self) -> RcTester
420    where
421        Self: Clone + Sized + 'static,
422    {
423        self.clone().into_rc()
424    }
425
426    #[inline]
427    fn to_arc(&self) -> ArcTester
428    where
429        Self: Clone + Sized + Send + Sync + 'static,
430    {
431        self.clone().into_arc()
432    }
433
434    #[inline]
435    fn to_fn(&self) -> impl Fn() -> bool
436    where
437        Self: Clone + Sized,
438    {
439        self.clone()
440    }
441}