Skip to main content

qubit_function/
tester.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Tester Type
10//!
11//! Provides tester implementations that test conditions or states and return
12//! boolean values, without accepting input parameters.
13//!
14//! # Overview
15//!
16//! **Tester** is a functional abstraction for testing conditions or states
17//! without accepting input. It can check system status, wait for conditions,
18//! or perform health checks.
19//!
20//! This module implements **Option 3** from the design document: a unified
21//! `Tester` trait with multiple concrete implementations optimized for
22//! different ownership and concurrency scenarios.
23//!
24//! # Core Design Principles
25//!
26//! 1. **Returns boolean**: `Tester` returns `bool` to indicate test results
27//! 2. **Uses `&self`**: Tester is only responsible for "judgment", not
28//!    "state management"
29//! 3. **No TesterOnce**: Very limited use cases, lacks practical examples
30//! 4. **State management is caller's responsibility**: Tester only reads
31//!    state, does not modify state
32//!
33//! # Three Implementations
34//!
35//! - **`BoxTester`**: Single ownership using `Box<dyn Fn() -> bool>`.
36//!   Zero overhead, cannot be cloned. Best for one-time use and builder
37//!   patterns.
38//!
39//! - **`ArcTester`**: Thread-safe shared ownership using
40//!   `Arc<dyn Fn() -> bool + Send + Sync>`. Can be cloned and sent across
41//!   threads. Lock-free overhead.
42//!
43//! - **`RcTester`**: Single-threaded shared ownership using
44//!   `Rc<dyn Fn() -> bool>`. Can be cloned but cannot be sent across
45//!   threads. Lower overhead than `ArcTester`.
46//!
47//! # Comparison with Other Functional Abstractions
48//!
49//! | Type      | Input | Output | self      | Modify? | Use Cases   |
50//! |-----------|-------|--------|-----------|---------|-------------|
51//! | Tester    | None  | `bool` | `&self`   | No      | State Check |
52//! | Predicate | `&T`  | `bool` | `&self`   | No      | Filter      |
53//! | Supplier  | None  | `T`    | `&mut`    | Yes     | Factory     |
54//!
55//! # Examples
56//!
57//! ## Basic State Checking
58//!
59//! ```rust
60//! use qubit_function::{BoxTester, Tester};
61//! use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
62//!
63//! // State managed externally
64//! let count = Arc::new(AtomicUsize::new(0));
65//! let count_clone = Arc::clone(&count);
66//!
67//! let tester = BoxTester::new(move || {
68//!     count_clone.load(Ordering::Relaxed) <= 3
69//! });
70//!
71//! assert!(tester.test());  // true (0)
72//! count.fetch_add(1, Ordering::Relaxed);
73//! assert!(tester.test());  // true (1)
74//! count.fetch_add(1, Ordering::Relaxed);
75//! assert!(tester.test());  // true (2)
76//! count.fetch_add(1, Ordering::Relaxed);
77//! assert!(tester.test());  // true (3)
78//! count.fetch_add(1, Ordering::Relaxed);
79//! assert!(!tester.test()); // false (4)
80//! ```
81//!
82//! ## Logical Combination
83//!
84//! ```rust
85//! use qubit_function::{BoxTester, Tester};
86//! use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
87//!
88//! // Simulate microservice health check scenario
89//! let cpu_usage = Arc::new(AtomicUsize::new(0));
90//! let memory_usage = Arc::new(AtomicUsize::new(0));
91//! let is_healthy = Arc::new(AtomicBool::new(true));
92//! let is_ready = Arc::new(AtomicBool::new(false));
93//! let max_cpu = 80;
94//! let max_memory = 90;
95//!
96//! let cpu_clone = Arc::clone(&cpu_usage);
97//! let memory_clone = Arc::clone(&memory_usage);
98//! let health_clone = Arc::clone(&is_healthy);
99//! let ready_clone = Arc::clone(&is_ready);
100//!
101//! // System resource check: CPU and memory within safe limits
102//! let resources_ok = BoxTester::new(move || {
103//!     cpu_clone.load(Ordering::Relaxed) < max_cpu
104//! })
105//! .and(move || {
106//!     memory_clone.load(Ordering::Relaxed) < max_memory
107//! });
108//!
109//! // Service status check: healthy or ready
110//! let service_ok = BoxTester::new(move || {
111//!     health_clone.load(Ordering::Relaxed)
112//! })
113//! .or(move || {
114//!     ready_clone.load(Ordering::Relaxed)
115//! });
116//!
117//! // Combined condition: resources normal and service available
118//! let can_accept_traffic = resources_ok.and(service_ok);
119//!
120//! // Test different state combinations
121//! // Initial state: resources normal and service healthy
122//! cpu_usage.store(50, Ordering::Relaxed);
123//! memory_usage.store(60, Ordering::Relaxed);
124//! assert!(can_accept_traffic.test()); // resources normal and service healthy
125//!
126//! // Service unhealthy but ready
127//! is_healthy.store(false, Ordering::Relaxed);
128//! is_ready.store(true, Ordering::Relaxed);
129//! assert!(can_accept_traffic.test()); // resources normal and service ready
130//!
131//! // CPU usage too high
132//! cpu_usage.store(95, Ordering::Relaxed);
133//! assert!(!can_accept_traffic.test()); // resources exceeded
134//!
135//! // Service unhealthy but ready
136//! is_healthy.store(false, Ordering::Relaxed);
137//! cpu_usage.store(50, Ordering::Relaxed);
138//! assert!(can_accept_traffic.test()); // still ready
139//! ```
140//!
141//! ## Thread-Safe Sharing
142//!
143//! ```rust
144//! use qubit_function::{ArcTester, Tester};
145//! use std::thread;
146//!
147//! let shared = ArcTester::new(|| true);
148//! let clone = shared.clone();
149//!
150//! let handle = thread::spawn(move || {
151//!     clone.test()
152//! });
153//!
154//! assert!(handle.join().unwrap());
155//! ```
156//!
157//! # Author
158//!
159//! Haixing Hu
160use std::rc::Rc;
161use std::sync::Arc;
162
163// ============================================================================
164// Core Tester Trait
165// ============================================================================
166
167/// Tests whether a state or condition holds
168///
169/// Tester is a functional abstraction for testing states or conditions. It
170/// accepts no parameters and returns a boolean value indicating the test
171/// result of some state or condition.
172///
173/// # Core Characteristics
174///
175/// - **No input parameters**: Captures context through closures
176/// - **Returns boolean**: Indicates test results
177/// - **Uses `&self`**: Does not modify its own state, only reads external
178///   state
179/// - **Repeatable calls**: The same Tester can call `test()` multiple times
180///
181/// # Use Cases
182///
183/// - **State checking**: Check system or service status
184/// - **Condition waiting**: Repeatedly check until conditions are met
185/// - **Health monitoring**: Check system health status
186/// - **Precondition validation**: Verify conditions before operations
187///
188/// # Design Philosophy
189///
190/// Tester's responsibility is "test judgment", not "state management".
191/// State management is the caller's responsibility. Tester only reads state
192/// and returns judgment results.
193///
194/// # Examples
195///
196/// ```rust
197/// use qubit_function::{BoxTester, Tester};
198/// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
199///
200/// // State managed externally
201/// let ready = Arc::new(AtomicBool::new(false));
202/// let ready_clone = Arc::clone(&ready);
203///
204/// // Tester only responsible for reading state
205/// let tester = BoxTester::new(move || {
206///     ready_clone.load(Ordering::Acquire)
207/// });
208///
209/// // Can be called multiple times
210/// assert!(!tester.test());
211/// ready.store(true, Ordering::Release);
212/// assert!(tester.test());
213/// ```
214///
215/// # Author
216///
217/// Haixing Hu
218pub trait Tester {
219    /// Executes the test and returns the test result
220    ///
221    /// This method can be called multiple times without modifying the Tester's
222    /// own state.
223    ///
224    /// # Return Value
225    ///
226    /// Returns `true` if the condition holds, otherwise returns `false`
227    ///
228    /// # Examples
229    ///
230    /// ```rust
231    /// use qubit_function::{BoxTester, Tester};
232    ///
233    /// let tester = BoxTester::new(|| true);
234    /// assert!(tester.test());
235    /// ```
236    fn test(&self) -> bool;
237
238    /// Converts this tester to `BoxTester`
239    ///
240    /// # Return Value
241    ///
242    /// A `BoxTester` that wraps this tester
243    ///
244    /// # Examples
245    ///
246    /// ```rust
247    /// use qubit_function::{Tester, BoxTester};
248    ///
249    /// let closure = || true;
250    /// let boxed: BoxTester = closure.into_box();
251    /// ```
252    #[inline]
253    fn into_box(self) -> BoxTester
254    where
255        Self: Sized + 'static,
256    {
257        BoxTester {
258            function: Box::new(move || self.test()),
259        }
260    }
261
262    /// Converts this tester to `RcTester`
263    ///
264    /// # Return Value
265    ///
266    /// A `RcTester` that wraps this tester
267    ///
268    /// # Examples
269    ///
270    /// ```rust
271    /// use qubit_function::{Tester, RcTester};
272    ///
273    /// let closure = || true;
274    /// let rc: RcTester = closure.into_rc();
275    /// ```
276    #[inline]
277    fn into_rc(self) -> RcTester
278    where
279        Self: Sized + 'static,
280    {
281        RcTester {
282            function: Rc::new(move || self.test()),
283        }
284    }
285
286    /// Converts this tester to `ArcTester`
287    ///
288    /// # Return Value
289    ///
290    /// An `ArcTester` that wraps this tester
291    ///
292    /// # Examples
293    ///
294    /// ```rust
295    /// use qubit_function::{Tester, ArcTester};
296    ///
297    /// let closure = || true;
298    /// let arc: ArcTester = closure.into_arc();
299    /// ```
300    #[inline]
301    fn into_arc(self) -> ArcTester
302    where
303        Self: Sized + Send + Sync + 'static,
304    {
305        ArcTester {
306            function: Arc::new(move || self.test()),
307        }
308    }
309
310    /// Converts this tester to a boxed function pointer
311    ///
312    /// # Return Value
313    ///
314    /// A `Box<dyn Fn() -> bool>` that wraps this tester
315    ///
316    /// # Examples
317    ///
318    /// ```rust
319    /// use qubit_function::Tester;
320    ///
321    /// let closure = || true;
322    /// let func = closure.into_fn();
323    /// assert!(func());
324    /// ```
325    #[inline]
326    fn into_fn(self) -> impl Fn() -> bool
327    where
328        Self: Sized + 'static,
329    {
330        Box::new(move || self.test())
331    }
332
333    /// Clones and converts this tester to `BoxTester`
334    ///
335    /// # Return Value
336    ///
337    /// A `BoxTester` that wraps a clone of this tester
338    ///
339    /// # Examples
340    ///
341    /// ```rust
342    /// use qubit_function::{Tester, BoxTester, ArcTester};
343    ///
344    /// let arc = ArcTester::new(|| true);
345    /// let boxed: BoxTester = arc.to_box();
346    /// // arc is still available
347    /// ```
348    #[inline]
349    fn to_box(&self) -> BoxTester
350    where
351        Self: Clone + 'static,
352    {
353        self.clone().into_box()
354    }
355
356    /// Clones and converts this tester to `RcTester`
357    ///
358    /// # Return Value
359    ///
360    /// A `RcTester` that wraps a clone of this tester
361    ///
362    /// # Examples
363    ///
364    /// ```rust
365    /// use qubit_function::{Tester, RcTester, ArcTester};
366    ///
367    /// let arc = ArcTester::new(|| true);
368    /// let rc: RcTester = arc.to_rc();
369    /// // arc is still available
370    /// ```
371    #[inline]
372    fn to_rc(&self) -> RcTester
373    where
374        Self: Clone + 'static,
375    {
376        self.clone().into_rc()
377    }
378
379    /// Clones and converts this tester to `ArcTester`
380    ///
381    /// # Return Value
382    ///
383    /// An `ArcTester` that wraps a clone of this tester
384    ///
385    /// # Examples
386    ///
387    /// ```rust
388    /// use qubit_function::{Tester, ArcTester, RcTester};
389    ///
390    /// let rc = RcTester::new(|| true);
391    /// // Note: This will panic for RcTester as it's not Send + Sync
392    /// // let arc: ArcTester = rc.to_arc();
393    /// ```
394    #[inline]
395    fn to_arc(&self) -> ArcTester
396    where
397        Self: Clone + Send + Sync + 'static,
398    {
399        self.clone().into_arc()
400    }
401
402    /// Clones and converts this tester to a boxed function pointer
403    ///
404    /// # Return Value
405    ///
406    /// A `Box<dyn Fn() -> bool>` that wraps a clone of this tester
407    ///
408    /// # Examples
409    ///
410    /// ```rust
411    /// use qubit_function::{Tester, ArcTester};
412    ///
413    /// let arc = ArcTester::new(|| true);
414    /// let func = arc.to_fn();
415    /// // arc is still available
416    /// assert!(func());
417    /// ```
418    #[inline]
419    fn to_fn(&self) -> impl Fn() -> bool
420    where
421        Self: Clone + 'static,
422    {
423        self.clone().into_fn()
424    }
425}
426
427// ============================================================================
428// BoxTester: Single Ownership Implementation
429// ============================================================================
430
431/// Single ownership Tester implemented using `Box`
432///
433/// `BoxTester` wraps a closure in `Box<dyn Fn() -> bool>`, providing single
434/// ownership semantics with no additional allocation overhead beyond the
435/// initial boxing.
436///
437/// # Characteristics
438///
439/// - **Single ownership**: Cannot be cloned
440/// - **Zero overhead**: Single heap allocation
441/// - **Consuming combination**: `and()`/`or()`/`not()` consume `self`
442/// - **Type flexibility**: Accepts any `Tester` implementation
443///
444/// # Use Cases
445///
446/// - One-time testing scenarios
447/// - Builder patterns requiring ownership transfer
448/// - Simple state checking without sharing
449/// - Chained calls with ownership transfer
450///
451/// # Examples
452///
453/// ```rust
454/// use qubit_function::{BoxTester, Tester};
455/// use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
456///
457/// // State managed externally
458/// let count = Arc::new(AtomicUsize::new(0));
459/// let count_clone = Arc::clone(&count);
460///
461/// let tester = BoxTester::new(move || {
462///     count_clone.load(Ordering::Relaxed) < 3
463/// });
464///
465/// assert!(tester.test());
466/// count.fetch_add(1, Ordering::Relaxed);
467/// assert!(tester.test());
468/// count.fetch_add(1, Ordering::Relaxed);
469/// assert!(tester.test());
470/// count.fetch_add(1, Ordering::Relaxed);
471/// assert!(!tester.test());
472///
473/// // Logical combination
474/// let combined = BoxTester::new(|| true)
475///     .and(|| false)
476///     .or(|| true);
477/// assert!(combined.test());
478/// ```
479///
480/// # Author
481///
482/// Haixing Hu
483pub struct BoxTester {
484    function: Box<dyn Fn() -> bool>,
485}
486
487impl BoxTester {
488    /// Creates a new `BoxTester` from a closure
489    ///
490    /// # Type Parameters
491    ///
492    /// * `F` - Closure type implementing `Fn() -> bool`
493    ///
494    /// # Parameters
495    ///
496    /// * `f` - The closure to wrap
497    ///
498    /// # Return Value
499    ///
500    /// A new `BoxTester` instance
501    ///
502    /// # Examples
503    ///
504    /// ```rust
505    /// use qubit_function::BoxTester;
506    ///
507    /// let tester = BoxTester::new(|| true);
508    /// ```
509    #[inline]
510    pub fn new<F>(f: F) -> Self
511    where
512        F: Fn() -> bool + 'static,
513    {
514        BoxTester {
515            function: Box::new(f),
516        }
517    }
518
519    /// Combines this tester with another tester using logical AND
520    ///
521    /// Returns a new `BoxTester` that returns `true` only when both tests
522    /// pass. Short-circuit evaluation: if the first test fails, the second
523    /// will not be executed.
524    ///
525    /// # Type Parameters
526    ///
527    /// * `T` - Type implementing `Tester`
528    ///
529    /// # Parameters
530    ///
531    /// * `next` - The tester to combine with
532    ///
533    /// # Return Value
534    ///
535    /// A new `BoxTester` representing logical AND
536    ///
537    /// # Examples
538    ///
539    /// ```rust
540    /// use qubit_function::{BoxTester, Tester};
541    /// use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
542    ///
543    /// // Simulate service status
544    /// let request_count = Arc::new(AtomicUsize::new(0));
545    /// let is_available = Arc::new(AtomicBool::new(true));
546    /// let max_requests = 1000;
547    ///
548    /// let count_clone = Arc::clone(&request_count);
549    /// let available_clone = Arc::clone(&is_available);
550    ///
551    /// // Service available and request count not exceeded
552    /// let service_ok = BoxTester::new(move || {
553    ///     available_clone.load(Ordering::Relaxed)
554    /// })
555    /// .and(move || {
556    ///     count_clone.load(Ordering::Relaxed) < max_requests
557    /// });
558    ///
559    /// // Initial state: available and request count 0
560    /// assert!(service_ok.test());
561    ///
562    /// // Simulate request increase
563    /// request_count.store(500, Ordering::Relaxed);
564    /// assert!(service_ok.test());
565    ///
566    /// // Request count exceeded
567    /// request_count.store(1500, Ordering::Relaxed);
568    /// assert!(!service_ok.test());
569    ///
570    /// // Service unavailable
571    /// is_available.store(false, Ordering::Relaxed);
572    /// assert!(!service_ok.test());
573    /// ```
574    #[inline]
575    pub fn and<T>(self, next: T) -> BoxTester
576    where
577        T: Tester + 'static,
578    {
579        let self_fn = self.function;
580        let next_tester = next;
581        BoxTester::new(move || self_fn() && next_tester.test())
582    }
583
584    /// Combines this tester with another tester using logical OR
585    ///
586    /// Returns a new `BoxTester` that returns `true` if either test passes.
587    /// Short-circuit evaluation: if the first test passes, the second will
588    /// not be executed.
589    ///
590    /// # Type Parameters
591    ///
592    /// * `T` - Type implementing `Tester`
593    ///
594    /// # Parameters
595    ///
596    /// * `next` - The tester to combine with
597    ///
598    /// # Return Value
599    ///
600    /// A new `BoxTester` representing logical OR
601    ///
602    /// # Examples
603    ///
604    /// ```rust
605    /// use qubit_function::{BoxTester, Tester};
606    /// use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
607    ///
608    /// // Simulate service status
609    /// let request_count = Arc::new(AtomicUsize::new(0));
610    /// let is_healthy = Arc::new(AtomicBool::new(true));
611    /// let max_requests = 100;
612    ///
613    /// let count_clone = Arc::clone(&request_count);
614    /// let health_clone = Arc::clone(&is_healthy);
615    ///
616    /// // Service healthy or low request count
617    /// let can_serve = BoxTester::new(move || {
618    ///     health_clone.load(Ordering::Relaxed)
619    /// })
620    /// .or(move || {
621    ///     count_clone.load(Ordering::Relaxed) < max_requests
622    /// });
623    ///
624    /// // Initial state: healthy and request count 0
625    /// assert!(can_serve.test());
626    ///
627    /// // Request count increased but within limit
628    /// request_count.store(50, Ordering::Relaxed);
629    /// assert!(can_serve.test());
630    ///
631    /// // Request count exceeded but service healthy
632    /// request_count.store(150, Ordering::Relaxed);
633    /// assert!(can_serve.test()); // still healthy
634    ///
635    /// // Service unhealthy but low request count
636    /// is_healthy.store(false, Ordering::Relaxed);
637    /// request_count.store(50, Ordering::Relaxed);
638    /// assert!(can_serve.test()); // low request count
639    ///
640    /// // Unhealthy and high request count
641    /// request_count.store(150, Ordering::Relaxed);
642    /// assert!(!can_serve.test());
643    /// ```
644    #[inline]
645    pub fn or<T>(self, next: T) -> BoxTester
646    where
647        T: Tester + 'static,
648    {
649        let self_fn = self.function;
650        let next_tester = next;
651        BoxTester::new(move || self_fn() || next_tester.test())
652    }
653
654    /// Negates the result of this tester
655    ///
656    /// Returns a new `BoxTester` that returns the opposite value of the
657    /// original test result.
658    ///
659    /// # Return Value
660    ///
661    /// A new `BoxTester` representing logical NOT
662    ///
663    /// # Examples
664    ///
665    /// ```rust
666    /// use qubit_function::{BoxTester, Tester};
667    /// use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
668    ///
669    /// // Simulate resource usage
670    /// let memory_usage = Arc::new(AtomicUsize::new(0));
671    /// let max_memory = 1024; // MB
672    ///
673    /// let memory_clone = Arc::clone(&memory_usage);
674    ///
675    /// // Memory usage not exceeded
676    /// let memory_ok = BoxTester::new(move || {
677    ///     memory_clone.load(Ordering::Relaxed) <= max_memory
678    /// });
679    ///
680    /// // Initial state: normal memory usage
681    /// memory_usage.store(512, Ordering::Relaxed);
682    /// assert!(memory_ok.test());
683    ///
684    /// // Memory usage exceeded (negated)
685    /// let memory_critical = memory_ok.not();
686    /// assert!(!memory_critical.test());
687    ///
688    /// // Memory usage exceeded
689    /// memory_usage.store(2048, Ordering::Relaxed);
690    /// assert!(memory_critical.test());
691    /// ```
692    #[allow(clippy::should_implement_trait)]
693    #[inline]
694    pub fn not(self) -> BoxTester {
695        let self_fn = self.function;
696        BoxTester::new(move || !self_fn())
697    }
698
699    /// Combines this tester with another tester using logical NAND
700    ///
701    /// Returns a new `BoxTester` that returns `true` unless both tests pass.
702    /// Equivalent to `!(self AND other)`.
703    ///
704    /// # Type Parameters
705    ///
706    /// * `T` - Type implementing `Tester`
707    ///
708    /// # Parameters
709    ///
710    /// * `next` - The tester to combine with
711    ///
712    /// # Return Value
713    ///
714    /// A new `BoxTester` representing logical NAND
715    ///
716    /// # Examples
717    ///
718    /// ```rust
719    /// use qubit_function::{BoxTester, Tester};
720    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
721    ///
722    /// let flag1 = Arc::new(AtomicBool::new(true));
723    /// let flag2 = Arc::new(AtomicBool::new(true));
724    ///
725    /// let flag1_clone = Arc::clone(&flag1);
726    /// let flag2_clone = Arc::clone(&flag2);
727    ///
728    /// let nand = BoxTester::new(move || {
729    ///     flag1_clone.load(Ordering::Relaxed)
730    /// })
731    /// .nand(move || {
732    ///     flag2_clone.load(Ordering::Relaxed)
733    /// });
734    ///
735    /// // Both true returns false
736    /// assert!(!nand.test());
737    ///
738    /// // At least one false returns true
739    /// flag1.store(false, Ordering::Relaxed);
740    /// assert!(nand.test());
741    /// ```
742    #[inline]
743    pub fn nand<T>(self, next: T) -> BoxTester
744    where
745        T: Tester + 'static,
746    {
747        let self_fn = self.function;
748        let next_tester = next;
749        BoxTester::new(move || !(self_fn() && next_tester.test()))
750    }
751
752    /// Combines this tester with another tester using logical XOR
753    ///
754    /// Returns a new `BoxTester` that returns `true` if exactly one test
755    /// passes.
756    ///
757    /// # Type Parameters
758    ///
759    /// * `T` - Type implementing `Tester`
760    ///
761    /// # Parameters
762    ///
763    /// * `next` - The tester to combine with
764    ///
765    /// # Return Value
766    ///
767    /// A new `BoxTester` representing logical XOR
768    ///
769    /// # Examples
770    ///
771    /// ```rust
772    /// use qubit_function::{BoxTester, Tester};
773    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
774    ///
775    /// let flag1 = Arc::new(AtomicBool::new(true));
776    /// let flag2 = Arc::new(AtomicBool::new(false));
777    ///
778    /// let flag1_clone1 = Arc::clone(&flag1);
779    /// let flag2_clone1 = Arc::clone(&flag2);
780    ///
781    /// let xor = BoxTester::new(move || {
782    ///     flag1_clone1.load(Ordering::Relaxed)
783    /// })
784    /// .xor(move || {
785    ///     flag2_clone1.load(Ordering::Relaxed)
786    /// });
787    ///
788    /// // One true one false returns true
789    /// assert!(xor.test());
790    ///
791    /// // Both true returns false
792    /// flag2.store(true, Ordering::Relaxed);
793    /// assert!(!xor.test());
794    ///
795    /// // Both false returns false
796    /// flag1.store(false, Ordering::Relaxed);
797    /// flag2.store(false, Ordering::Relaxed);
798    /// assert!(!xor.test());
799    /// ```
800    #[inline]
801    pub fn xor<T>(self, next: T) -> BoxTester
802    where
803        T: Tester + 'static,
804    {
805        let self_fn = self.function;
806        let next_tester = next;
807        BoxTester::new(move || self_fn() ^ next_tester.test())
808    }
809
810    /// Combines this tester with another tester using logical NOR
811    ///
812    /// Returns a new `BoxTester` that returns `true` only when both tests
813    /// fail. Equivalent to `!(self OR other)`.
814    ///
815    /// # Type Parameters
816    ///
817    /// * `T` - Type implementing `Tester`
818    ///
819    /// # Parameters
820    ///
821    /// * `next` - The tester to combine with
822    ///
823    /// # Return Value
824    ///
825    /// A new `BoxTester` representing logical NOR
826    ///
827    /// # Examples
828    ///
829    /// ```rust
830    /// use qubit_function::{BoxTester, Tester};
831    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
832    ///
833    /// let flag1 = Arc::new(AtomicBool::new(false));
834    /// let flag2 = Arc::new(AtomicBool::new(false));
835    ///
836    /// let flag1_clone = Arc::clone(&flag1);
837    /// let flag2_clone = Arc::clone(&flag2);
838    ///
839    /// let nor = BoxTester::new(move || {
840    ///     flag1_clone.load(Ordering::Relaxed)
841    /// })
842    /// .nor(move || {
843    ///     flag2_clone.load(Ordering::Relaxed)
844    /// });
845    ///
846    /// // Both false returns true
847    /// assert!(nor.test());
848    ///
849    /// // At least one true returns false
850    /// flag1.store(true, Ordering::Relaxed);
851    /// assert!(!nor.test());
852    /// ```
853    #[inline]
854    pub fn nor<T>(self, next: T) -> BoxTester
855    where
856        T: Tester + 'static,
857    {
858        let self_fn = self.function;
859        let next_tester = next;
860        BoxTester::new(move || !(self_fn() || next_tester.test()))
861    }
862}
863
864impl Tester for BoxTester {
865    #[inline]
866    fn test(&self) -> bool {
867        (self.function)()
868    }
869
870    #[inline]
871    fn into_box(self) -> BoxTester {
872        self
873    }
874
875    #[inline]
876    fn into_rc(self) -> RcTester {
877        let func = self.function;
878        RcTester {
879            function: Rc::new(func),
880        }
881    }
882
883    // Note: BoxTester does not implement Send + Sync, so into_arc()
884    // cannot be implemented. Calling into_arc() on BoxTester will result
885    // in a compile error due to the Send + Sync trait bounds not being
886    // satisfied. The default Tester trait implementation will be used.
887
888    #[inline]
889    fn into_fn(self) -> impl Fn() -> bool {
890        self.function
891    }
892
893    // Note: BoxTester does not implement Clone, so to_box(), to_rc(),
894    // to_arc(), and to_fn() cannot be implemented. Calling these methods
895    // on BoxTester will result in a compile error due to the Clone trait
896    // bound not being satisfied. The default Tester trait implementations
897    // will be used.
898}
899
900// ============================================================================
901// ArcTester: Thread-Safe Shared Ownership Implementation
902// ============================================================================
903
904/// Thread-safe shared ownership Tester implemented using `Arc`
905///
906/// `ArcTester` wraps a closure in `Arc<dyn Fn() -> bool + Send + Sync>`,
907/// allowing the tester to be cloned and safely shared across threads.
908///
909/// # Characteristics
910///
911/// - **Shared ownership**: Can be cloned
912/// - **Thread-safe**: Can be sent across threads
913/// - **Lock-free overhead**: Uses `Fn` without needing `Mutex`
914/// - **Borrowing combination**: `and()`/`or()`/`not()` borrow `&self`
915///
916/// # Use Cases
917///
918/// - Multi-threaded testing scenarios
919/// - Health checks shared across threads
920/// - Test states requiring concurrent access
921/// - Background monitoring tasks
922///
923/// # Examples
924///
925/// ```rust
926/// use qubit_function::{ArcTester, Tester};
927/// use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
928/// use std::thread;
929///
930/// // Shared atomic counter
931/// let counter = Arc::new(AtomicUsize::new(0));
932/// let counter_clone = Arc::clone(&counter);
933///
934/// let shared = ArcTester::new(move || {
935///     counter_clone.load(Ordering::Relaxed) <= 5
936/// });
937///
938/// let clone = shared.clone();
939/// let handle = thread::spawn(move || {
940///     clone.test()
941/// });
942///
943/// assert!(handle.join().unwrap());
944/// counter.fetch_add(1, Ordering::Relaxed);
945/// assert!(shared.test());
946/// ```
947///
948/// # Author
949///
950/// Haixing Hu
951pub struct ArcTester {
952    function: Arc<dyn Fn() -> bool + Send + Sync>,
953}
954
955impl ArcTester {
956    /// Creates a new `ArcTester` from a closure
957    ///
958    /// # Type Parameters
959    ///
960    /// * `F` - Closure type implementing `Fn() -> bool + Send + Sync`
961    ///
962    /// # Parameters
963    ///
964    /// * `f` - The closure to wrap
965    ///
966    /// # Return Value
967    ///
968    /// A new `ArcTester` instance
969    ///
970    /// # Examples
971    ///
972    /// ```rust
973    /// use qubit_function::ArcTester;
974    ///
975    /// let tester = ArcTester::new(|| true);
976    /// ```
977    #[inline]
978    pub fn new<F>(f: F) -> Self
979    where
980        F: Fn() -> bool + Send + Sync + 'static,
981    {
982        ArcTester {
983            function: Arc::new(f),
984        }
985    }
986
987    /// Combines this tester with another tester using logical AND
988    ///
989    /// Returns a new `ArcTester` that returns `true` only when both tests
990    /// pass. Borrows `&self`, so the original tester remains available.
991    ///
992    /// # Parameters
993    ///
994    /// * `next` - The tester to combine with
995    ///
996    /// # Return Value
997    ///
998    /// A new `ArcTester` representing logical AND
999    ///
1000    /// # Examples
1001    ///
1002    /// ```rust
1003    /// use qubit_function::{ArcTester, Tester};
1004    /// use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
1005    /// use std::thread;
1006    ///
1007    /// // Simulate database connection pool status
1008    /// let active_connections = Arc::new(AtomicUsize::new(0));
1009    /// let is_pool_healthy = Arc::new(AtomicBool::new(true));
1010    /// let max_connections = 50;
1011    ///
1012    /// let conn_clone = Arc::clone(&active_connections);
1013    /// let health_clone = Arc::clone(&is_pool_healthy);
1014    ///
1015    /// // Connection pool health check
1016    /// let pool_healthy = ArcTester::new(move || {
1017    ///     health_clone.load(Ordering::Relaxed)
1018    /// });
1019    ///
1020    /// // Connection count check
1021    /// let conn_ok = ArcTester::new(move || {
1022    ///     conn_clone.load(Ordering::Relaxed) < max_connections
1023    /// });
1024    ///
1025    /// // Combined check: pool healthy and connection count not exceeded
1026    /// let pool_ready = pool_healthy.and(&conn_ok);
1027    ///
1028    /// // Multi-threaded test
1029    /// let pool_ready_clone = pool_ready.clone();
1030    /// let handle = thread::spawn(move || {
1031    ///     pool_ready_clone.test()
1032    /// });
1033    ///
1034    /// // Initial state should pass
1035    /// assert!(handle.join().unwrap());
1036    /// assert!(pool_ready.test());
1037    ///
1038    /// // Connection count exceeded
1039    /// active_connections.store(60, Ordering::Relaxed);
1040    /// assert!(!pool_ready.test());
1041    ///
1042    /// // Connection pool unhealthy
1043    /// is_pool_healthy.store(false, Ordering::Relaxed);
1044    /// assert!(!pool_ready.test());
1045    /// ```
1046    #[inline]
1047    pub fn and(&self, next: &ArcTester) -> ArcTester {
1048        let self_fn = Arc::clone(&self.function);
1049        let next_fn = Arc::clone(&next.function);
1050        ArcTester {
1051            function: Arc::new(move || self_fn() && next_fn()),
1052        }
1053    }
1054
1055    /// Combines this tester with another tester using logical OR
1056    ///
1057    /// Returns a new `ArcTester` that returns `true` if either test passes.
1058    /// Borrows `&self`, so the original tester remains available.
1059    ///
1060    /// # Parameters
1061    ///
1062    /// * `next` - The tester to combine with
1063    ///
1064    /// # Return Value
1065    ///
1066    /// A new `ArcTester` representing logical OR
1067    ///
1068    /// # Examples
1069    ///
1070    /// ```rust
1071    /// use qubit_function::{ArcTester, Tester};
1072    /// use std::sync::{Arc, atomic::{AtomicUsize, AtomicBool, Ordering}};
1073    /// use std::thread;
1074    ///
1075    /// // Simulate load balancer status
1076    /// let server_load = Arc::new(AtomicUsize::new(0));
1077    /// let is_server_healthy = Arc::new(AtomicBool::new(true));
1078    /// let max_load = 80;
1079    /// let emergency_mode = Arc::new(AtomicBool::new(false));
1080    ///
1081    /// let load_clone = Arc::clone(&server_load);
1082    /// let health_clone = Arc::clone(&is_server_healthy);
1083    /// let emergency_clone = Arc::clone(&emergency_mode);
1084    ///
1085    /// // Server low load
1086    /// let low_load = ArcTester::new(move || {
1087    ///     load_clone.load(Ordering::Relaxed) < max_load
1088    /// });
1089    ///
1090    /// // Emergency mode check
1091    /// let emergency_check = ArcTester::new(move || {
1092    ///     emergency_clone.load(Ordering::Relaxed)
1093    /// });
1094    ///
1095    /// // Server health check
1096    /// let server_healthy = ArcTester::new(move || {
1097    ///     health_clone.load(Ordering::Relaxed)
1098    /// });
1099    ///
1100    /// // Emergency mode or server healthy
1101    /// let can_handle_requests = emergency_check.or(&server_healthy);
1102    ///
1103    /// // Combined condition: low load or can handle requests
1104    /// let should_route_here = low_load.or(&can_handle_requests);
1105    ///
1106    /// // Multi-threaded test
1107    /// let router_clone = should_route_here.clone();
1108    /// let handle = thread::spawn(move || {
1109    ///     router_clone.test()
1110    /// });
1111    ///
1112    /// // Initial state: low load and healthy
1113    /// assert!(handle.join().unwrap());
1114    /// assert!(should_route_here.test());
1115    ///
1116    /// // High load but server healthy
1117    /// server_load.store(90, Ordering::Relaxed);
1118    /// assert!(should_route_here.test()); // still healthy
1119    ///
1120    /// // Server unhealthy but emergency mode
1121    /// is_server_healthy.store(false, Ordering::Relaxed);
1122    /// emergency_mode.store(true, Ordering::Relaxed);
1123    /// assert!(should_route_here.test()); // emergency mode
1124    ///
1125    /// // Unhealthy and not emergency mode
1126    /// emergency_mode.store(false, Ordering::Relaxed);
1127    /// assert!(!should_route_here.test());
1128    /// ```
1129    #[inline]
1130    pub fn or(&self, next: &ArcTester) -> ArcTester {
1131        let self_fn = Arc::clone(&self.function);
1132        let next_fn = Arc::clone(&next.function);
1133        ArcTester {
1134            function: Arc::new(move || self_fn() || next_fn()),
1135        }
1136    }
1137
1138    /// Negates the result of this tester
1139    ///
1140    /// Returns a new `ArcTester` that returns the opposite value of the
1141    /// original test result. Borrows `&self`, so the original tester remains
1142    /// available.
1143    ///
1144    /// # Return Value
1145    ///
1146    /// A new `ArcTester` representing logical NOT
1147    ///
1148    /// # Examples
1149    ///
1150    /// ```rust
1151    /// use qubit_function::{ArcTester, Tester};
1152    /// use std::sync::{Arc, atomic::{AtomicUsize, Ordering}};
1153    /// use std::thread;
1154    ///
1155    /// // Simulate task queue status
1156    /// let pending_tasks = Arc::new(AtomicUsize::new(0));
1157    /// let max_queue_size = 100;
1158    ///
1159    /// let tasks_clone = Arc::clone(&pending_tasks);
1160    ///
1161    /// // Queue not full
1162    /// let queue_available = ArcTester::new(move || {
1163    ///     tasks_clone.load(Ordering::Relaxed) < max_queue_size
1164    /// });
1165    ///
1166    /// // Queue full (negated)
1167    /// let queue_full = queue_available.not();
1168    ///
1169    /// // Multi-threaded test
1170    /// let queue_full_clone = queue_full.clone();
1171    /// let handle = thread::spawn(move || {
1172    ///     queue_full_clone.test()
1173    /// });
1174    ///
1175    /// // Initial state: queue not full
1176    /// pending_tasks.store(50, Ordering::Relaxed);
1177    /// assert!(queue_available.test());
1178    /// assert!(!handle.join().unwrap());
1179    /// assert!(!queue_full.test());
1180    ///
1181    /// // Queue near full
1182    /// pending_tasks.store(95, Ordering::Relaxed);
1183    /// assert!(queue_available.test());
1184    /// assert!(!queue_full.test());
1185    ///
1186    /// // Queue full
1187    /// pending_tasks.store(120, Ordering::Relaxed);
1188    /// assert!(!queue_available.test());
1189    /// assert!(queue_full.test());
1190    /// ```
1191    #[allow(clippy::should_implement_trait)]
1192    #[inline]
1193    pub fn not(&self) -> ArcTester {
1194        let func = Arc::clone(&self.function);
1195        ArcTester {
1196            function: Arc::new(move || !func()),
1197        }
1198    }
1199
1200    /// Combines this tester with another tester using logical NAND
1201    ///
1202    /// Returns a new `ArcTester` that returns `true` unless both tests pass.
1203    /// Borrows `&self`, so the original tester remains available.
1204    ///
1205    /// # Parameters
1206    ///
1207    /// * `next` - The tester to combine with
1208    ///
1209    /// # Return Value
1210    ///
1211    /// A new `ArcTester` representing logical NAND
1212    ///
1213    /// # Examples
1214    ///
1215    /// ```rust
1216    /// use qubit_function::{ArcTester, Tester};
1217    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
1218    /// use std::thread;
1219    ///
1220    /// let flag1 = Arc::new(AtomicBool::new(true));
1221    /// let flag2 = Arc::new(AtomicBool::new(true));
1222    ///
1223    /// let flag1_clone = Arc::clone(&flag1);
1224    /// let flag2_clone = Arc::clone(&flag2);
1225    ///
1226    /// let tester1 = ArcTester::new(move || {
1227    ///     flag1_clone.load(Ordering::Relaxed)
1228    /// });
1229    ///
1230    /// let tester2 = ArcTester::new(move || {
1231    ///     flag2_clone.load(Ordering::Relaxed)
1232    /// });
1233    ///
1234    /// let nand = tester1.nand(&tester2);
1235    ///
1236    /// // Both true returns false
1237    /// assert!(!nand.test());
1238    ///
1239    /// // At least one false returns true
1240    /// flag1.store(false, Ordering::Relaxed);
1241    /// assert!(nand.test());
1242    ///
1243    /// // Original tester still available
1244    /// assert!(!tester1.test());
1245    /// assert!(tester2.test());
1246    /// ```
1247    #[inline]
1248    pub fn nand(&self, next: &ArcTester) -> ArcTester {
1249        let self_fn = Arc::clone(&self.function);
1250        let next_fn = Arc::clone(&next.function);
1251        ArcTester {
1252            function: Arc::new(move || !(self_fn() && next_fn())),
1253        }
1254    }
1255
1256    /// Combines this tester with another tester using logical XOR
1257    ///
1258    /// Returns a new `ArcTester` that returns `true` if exactly one test
1259    /// passes. Borrows `&self`, so the original tester remains available.
1260    ///
1261    /// # Parameters
1262    ///
1263    /// * `next` - The tester to combine with
1264    ///
1265    /// # Return Value
1266    ///
1267    /// A new `ArcTester` representing logical XOR
1268    ///
1269    /// # Examples
1270    ///
1271    /// ```rust
1272    /// use qubit_function::{ArcTester, Tester};
1273    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
1274    /// use std::thread;
1275    ///
1276    /// let flag1 = Arc::new(AtomicBool::new(true));
1277    /// let flag2 = Arc::new(AtomicBool::new(false));
1278    ///
1279    /// let flag1_clone = Arc::clone(&flag1);
1280    /// let flag2_clone = Arc::clone(&flag2);
1281    ///
1282    /// let tester1 = ArcTester::new(move || {
1283    ///     flag1_clone.load(Ordering::Relaxed)
1284    /// });
1285    ///
1286    /// let tester2 = ArcTester::new(move || {
1287    ///     flag2_clone.load(Ordering::Relaxed)
1288    /// });
1289    ///
1290    /// let xor = tester1.xor(&tester2);
1291    ///
1292    /// // One true one false returns true
1293    /// assert!(xor.test());
1294    ///
1295    /// // Both true returns false
1296    /// flag2.store(true, Ordering::Relaxed);
1297    /// assert!(!xor.test());
1298    ///
1299    /// // Both false returns false
1300    /// flag1.store(false, Ordering::Relaxed);
1301    /// flag2.store(false, Ordering::Relaxed);
1302    /// assert!(!xor.test());
1303    ///
1304    /// // Original tester still available
1305    /// assert!(!tester1.test());
1306    /// assert!(!tester2.test());
1307    /// ```
1308    #[inline]
1309    pub fn xor(&self, next: &ArcTester) -> ArcTester {
1310        let self_fn = Arc::clone(&self.function);
1311        let next_fn = Arc::clone(&next.function);
1312        ArcTester {
1313            function: Arc::new(move || self_fn() ^ next_fn()),
1314        }
1315    }
1316
1317    /// Combines this tester with another tester using logical NOR
1318    ///
1319    /// Returns a new `ArcTester` that returns `true` only when both tests
1320    /// fail. Borrows `&self`, so the original tester remains available.
1321    ///
1322    /// # Parameters
1323    ///
1324    /// * `next` - The tester to combine with
1325    ///
1326    /// # Return Value
1327    ///
1328    /// A new `ArcTester` representing logical NOR
1329    ///
1330    /// # Examples
1331    ///
1332    /// ```rust
1333    /// use qubit_function::{ArcTester, Tester};
1334    /// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
1335    /// use std::thread;
1336    ///
1337    /// let flag1 = Arc::new(AtomicBool::new(false));
1338    /// let flag2 = Arc::new(AtomicBool::new(false));
1339    ///
1340    /// let flag1_clone = Arc::clone(&flag1);
1341    /// let flag2_clone = Arc::clone(&flag2);
1342    ///
1343    /// let tester1 = ArcTester::new(move || {
1344    ///     flag1_clone.load(Ordering::Relaxed)
1345    /// });
1346    ///
1347    /// let tester2 = ArcTester::new(move || {
1348    ///     flag2_clone.load(Ordering::Relaxed)
1349    /// });
1350    ///
1351    /// let nor = tester1.nor(&tester2);
1352    ///
1353    /// // Both false returns true
1354    /// assert!(nor.test());
1355    ///
1356    /// // At least one true returns false
1357    /// flag1.store(true, Ordering::Relaxed);
1358    /// assert!(!nor.test());
1359    ///
1360    /// // Original tester still available
1361    /// assert!(tester1.test());
1362    /// assert!(!tester2.test());
1363    /// ```
1364    #[inline]
1365    pub fn nor(&self, next: &ArcTester) -> ArcTester {
1366        let self_fn = Arc::clone(&self.function);
1367        let next_fn = Arc::clone(&next.function);
1368        ArcTester {
1369            function: Arc::new(move || !(self_fn() || next_fn())),
1370        }
1371    }
1372}
1373
1374impl Tester for ArcTester {
1375    #[inline]
1376    fn test(&self) -> bool {
1377        (self.function)()
1378    }
1379
1380    #[inline]
1381    fn into_box(self) -> BoxTester {
1382        let func = self.function;
1383        BoxTester {
1384            function: Box::new(move || func()),
1385        }
1386    }
1387
1388    #[inline]
1389    fn into_rc(self) -> RcTester {
1390        let func = self.function;
1391        RcTester {
1392            function: Rc::new(move || func()),
1393        }
1394    }
1395
1396    #[inline]
1397    fn into_arc(self) -> ArcTester {
1398        self
1399    }
1400
1401    #[inline]
1402    fn into_fn(self) -> impl Fn() -> bool {
1403        move || (self.function)()
1404    }
1405
1406    #[inline]
1407    fn to_box(&self) -> BoxTester {
1408        let self_fn = self.function.clone();
1409        BoxTester {
1410            function: Box::new(move || self_fn()),
1411        }
1412    }
1413
1414    #[inline]
1415    fn to_rc(&self) -> RcTester {
1416        let self_fn = self.function.clone();
1417        RcTester {
1418            function: Rc::new(move || self_fn()),
1419        }
1420    }
1421
1422    #[inline]
1423    fn to_arc(&self) -> ArcTester {
1424        self.clone()
1425    }
1426
1427    #[inline]
1428    fn to_fn(&self) -> impl Fn() -> bool {
1429        let self_fn = self.function.clone();
1430        move || self_fn()
1431    }
1432}
1433
1434impl Clone for ArcTester {
1435    /// Creates a clone of this `ArcTester`.
1436    ///
1437    /// The cloned instance shares the same underlying function with
1438    /// the original, allowing multiple references to the same test
1439    /// logic.
1440    #[inline]
1441    fn clone(&self) -> Self {
1442        Self {
1443            function: Arc::clone(&self.function),
1444        }
1445    }
1446}
1447
1448// ============================================================================
1449// RcTester: Single-Threaded Shared Ownership Implementation
1450// ============================================================================
1451
1452/// Single-threaded shared ownership Tester implemented using `Rc`
1453///
1454/// `RcTester` wraps a closure in `Rc<dyn Fn() -> bool>`, allowing the tester
1455/// to be cloned and shared within a single thread. Since it doesn't use atomic
1456/// operations, it has lower overhead than `ArcTester`.
1457///
1458/// # Characteristics
1459///
1460/// - **Shared ownership**: Can be cloned
1461/// - **Single-threaded**: Cannot be sent across threads
1462/// - **Low overhead**: Uses `Fn` without needing `RefCell`
1463/// - **Borrowing combination**: `and()`/`or()`/`not()` borrow `&self`
1464///
1465/// # Use Cases
1466///
1467/// - Single-threaded testing scenarios requiring sharing
1468/// - Event-driven systems (single-threaded)
1469/// - Callback-intensive code requiring cloneable tests
1470/// - Performance-sensitive single-threaded code
1471///
1472/// # Examples
1473///
1474/// ```rust
1475/// use qubit_function::{RcTester, Tester};
1476///
1477/// let shared = RcTester::new(|| true);
1478///
1479/// // Clone for multiple uses
1480/// let clone1 = shared.clone();
1481/// let clone2 = shared.clone();
1482///
1483/// // Non-consuming combination
1484/// let combined = shared.and(&clone1);
1485/// ```
1486///
1487/// # Author
1488///
1489/// Haixing Hu
1490pub struct RcTester {
1491    function: Rc<dyn Fn() -> bool>,
1492}
1493
1494impl RcTester {
1495    /// Creates a new `RcTester` from a closure
1496    ///
1497    /// # Type Parameters
1498    ///
1499    /// * `F` - Closure type implementing `Fn() -> bool`
1500    ///
1501    /// # Parameters
1502    ///
1503    /// * `f` - The closure to wrap
1504    ///
1505    /// # Return Value
1506    ///
1507    /// A new `RcTester` instance
1508    ///
1509    /// # Examples
1510    ///
1511    /// ```rust
1512    /// use qubit_function::RcTester;
1513    ///
1514    /// let tester = RcTester::new(|| true);
1515    /// ```
1516    #[inline]
1517    pub fn new<F>(f: F) -> Self
1518    where
1519        F: Fn() -> bool + 'static,
1520    {
1521        RcTester {
1522            function: Rc::new(f),
1523        }
1524    }
1525
1526    /// Combines this tester with another tester using logical AND
1527    ///
1528    /// Returns a new `RcTester` that returns `true` only when both tests
1529    /// pass. Borrows `&self`, so the original tester remains available.
1530    ///
1531    /// # Parameters
1532    ///
1533    /// * `next` - The tester to combine with
1534    ///
1535    /// # Return Value
1536    ///
1537    /// A new `RcTester` representing logical AND
1538    ///
1539    /// # Examples
1540    ///
1541    /// ```rust
1542    /// use qubit_function::{RcTester, Tester};
1543    ///
1544    /// let first = RcTester::new(|| true);
1545    /// let second = RcTester::new(|| true);
1546    /// let combined = first.and(&second);
1547    /// // first and second are still available
1548    /// ```
1549    #[inline]
1550    pub fn and(&self, next: &RcTester) -> RcTester {
1551        let self_fn = Rc::clone(&self.function);
1552        let next_fn = Rc::clone(&next.function);
1553        RcTester {
1554            function: Rc::new(move || self_fn() && next_fn()),
1555        }
1556    }
1557
1558    /// Combines this tester with another tester using logical OR
1559    ///
1560    /// Returns a new `RcTester` that returns `true` if either test passes.
1561    /// Borrows `&self`, so the original tester remains available.
1562    ///
1563    /// # Parameters
1564    ///
1565    /// * `next` - The tester to combine with
1566    ///
1567    /// # Return Value
1568    ///
1569    /// A new `RcTester` representing logical OR
1570    ///
1571    /// # Examples
1572    ///
1573    /// ```rust
1574    /// use qubit_function::{RcTester, Tester};
1575    ///
1576    /// let first = RcTester::new(|| false);
1577    /// let second = RcTester::new(|| true);
1578    /// let combined = first.or(&second);
1579    /// // first and second are still available
1580    /// ```
1581    #[inline]
1582    pub fn or(&self, next: &RcTester) -> RcTester {
1583        let self_fn = Rc::clone(&self.function);
1584        let next_fn = Rc::clone(&next.function);
1585        RcTester {
1586            function: Rc::new(move || self_fn() || next_fn()),
1587        }
1588    }
1589
1590    /// Negates the result of this tester
1591    ///
1592    /// Returns a new `RcTester` that returns the opposite value of the
1593    /// original test result. Borrows `&self`, so the original tester remains
1594    /// available.
1595    ///
1596    /// # Return Value
1597    ///
1598    /// A new `RcTester` representing logical NOT
1599    ///
1600    /// # Examples
1601    ///
1602    /// ```rust
1603    /// use qubit_function::{RcTester, Tester};
1604    ///
1605    /// let original = RcTester::new(|| true);
1606    /// let negated = original.not();
1607    /// // original is still available
1608    /// ```
1609    #[allow(clippy::should_implement_trait)]
1610    #[inline]
1611    pub fn not(&self) -> RcTester {
1612        let self_fn = Rc::clone(&self.function);
1613        RcTester {
1614            function: Rc::new(move || !self_fn()),
1615        }
1616    }
1617
1618    /// Combines this tester with another tester using logical NAND
1619    ///
1620    /// Returns a new `RcTester` that returns `true` unless both tests pass.
1621    /// Borrows `&self`, so the original tester remains available.
1622    ///
1623    /// # Parameters
1624    ///
1625    /// * `next` - The tester to combine with
1626    ///
1627    /// # Return Value
1628    ///
1629    /// A new `RcTester` representing logical NAND
1630    ///
1631    /// # Examples
1632    ///
1633    /// ```rust
1634    /// use qubit_function::{RcTester, Tester};
1635    ///
1636    /// let first = RcTester::new(|| true);
1637    /// let second = RcTester::new(|| true);
1638    /// let nand = first.nand(&second);
1639    ///
1640    /// // Both true returns false
1641    /// assert!(!nand.test());
1642    ///
1643    /// // first and second still available
1644    /// assert!(first.test());
1645    /// assert!(second.test());
1646    /// ```
1647    #[inline]
1648    pub fn nand(&self, next: &RcTester) -> RcTester {
1649        let self_fn = Rc::clone(&self.function);
1650        let next_fn = Rc::clone(&next.function);
1651        RcTester {
1652            function: Rc::new(move || !(self_fn() && next_fn())),
1653        }
1654    }
1655
1656    /// Combines this tester with another tester using logical XOR
1657    ///
1658    /// Returns a new `RcTester` that returns `true` if exactly one test
1659    /// passes. Borrows `&self`, so the original tester remains available.
1660    ///
1661    /// # Parameters
1662    ///
1663    /// * `next` - The tester to combine with
1664    ///
1665    /// # Return Value
1666    ///
1667    /// A new `RcTester` representing logical XOR
1668    ///
1669    /// # Examples
1670    ///
1671    /// ```rust
1672    /// use qubit_function::{RcTester, Tester};
1673    ///
1674    /// let first = RcTester::new(|| true);
1675    /// let second = RcTester::new(|| false);
1676    /// let xor = first.xor(&second);
1677    ///
1678    /// // One true one false returns true
1679    /// assert!(xor.test());
1680    ///
1681    /// // first and second still available
1682    /// assert!(first.test());
1683    /// assert!(!second.test());
1684    /// ```
1685    #[inline]
1686    pub fn xor(&self, next: &RcTester) -> RcTester {
1687        let self_fn = Rc::clone(&self.function);
1688        let next_fn = Rc::clone(&next.function);
1689        RcTester {
1690            function: Rc::new(move || self_fn() ^ next_fn()),
1691        }
1692    }
1693
1694    /// Combines this tester with another tester using logical NOR
1695    ///
1696    /// Returns a new `RcTester` that returns `true` only when both tests
1697    /// fail. Borrows `&self`, so the original tester remains available.
1698    ///
1699    /// # Parameters
1700    ///
1701    /// * `next` - The tester to combine with
1702    ///
1703    /// # Return Value
1704    ///
1705    /// A new `RcTester` representing logical NOR
1706    ///
1707    /// # Examples
1708    ///
1709    /// ```rust
1710    /// use qubit_function::{RcTester, Tester};
1711    ///
1712    /// let first = RcTester::new(|| false);
1713    /// let second = RcTester::new(|| false);
1714    /// let nor = first.nor(&second);
1715    ///
1716    /// // Both false returns true
1717    /// assert!(nor.test());
1718    ///
1719    /// // first and second still available
1720    /// assert!(!first.test());
1721    /// assert!(!second.test());
1722    /// ```
1723    #[inline]
1724    pub fn nor(&self, next: &RcTester) -> RcTester {
1725        let self_fn = Rc::clone(&self.function);
1726        let next_fn = Rc::clone(&next.function);
1727        RcTester {
1728            function: Rc::new(move || !(self_fn() || next_fn())),
1729        }
1730    }
1731}
1732
1733impl Tester for RcTester {
1734    #[inline]
1735    fn test(&self) -> bool {
1736        (self.function)()
1737    }
1738
1739    #[inline]
1740    fn into_box(self) -> BoxTester {
1741        BoxTester {
1742            function: Box::new(move || (self.function)()),
1743        }
1744    }
1745
1746    #[inline]
1747    fn into_rc(self) -> RcTester {
1748        self
1749    }
1750
1751    // Note: RcTester is not Send + Sync, so into_arc() cannot be
1752    // implemented. Calling into_arc() on RcTester will result in a
1753    // compile error due to the Send + Sync trait bounds not being
1754    // satisfied. The default Tester trait implementation will be used.
1755
1756    #[inline]
1757    fn into_fn(self) -> impl Fn() -> bool {
1758        move || (self.function)()
1759    }
1760
1761    #[inline]
1762    fn to_box(&self) -> BoxTester {
1763        let self_fn = self.function.clone();
1764        BoxTester {
1765            function: Box::new(move || self_fn()),
1766        }
1767    }
1768
1769    #[inline]
1770    fn to_rc(&self) -> RcTester {
1771        self.clone()
1772    }
1773
1774    // Note: RcTester is not Send + Sync, so to_arc() cannot be
1775    // implemented. Calling to_arc() on RcTester will result in a compile
1776    // error due to the Send + Sync trait bounds not being satisfied. The
1777    // default Tester trait implementation will be used.
1778
1779    #[inline]
1780    fn to_fn(&self) -> impl Fn() -> bool {
1781        let self_fn = self.function.clone();
1782        move || self_fn()
1783    }
1784}
1785
1786impl Clone for RcTester {
1787    /// Creates a clone of this `RcTester`.
1788    ///
1789    /// The cloned instance shares the same underlying function with
1790    /// the original, allowing multiple references to the same test
1791    /// logic.
1792    #[inline]
1793    fn clone(&self) -> Self {
1794        Self {
1795            function: Rc::clone(&self.function),
1796        }
1797    }
1798}
1799
1800// ============================================================================
1801// Tester Implementation for Closures
1802// ============================================================================
1803
1804impl<F> Tester for F
1805where
1806    F: Fn() -> bool,
1807{
1808    #[inline]
1809    fn test(&self) -> bool {
1810        self()
1811    }
1812
1813    #[inline]
1814    fn into_box(self) -> BoxTester
1815    where
1816        Self: Sized + 'static,
1817    {
1818        BoxTester::new(self)
1819    }
1820
1821    #[inline]
1822    fn into_rc(self) -> RcTester
1823    where
1824        Self: Sized + 'static,
1825    {
1826        RcTester::new(self)
1827    }
1828
1829    #[inline]
1830    fn into_arc(self) -> ArcTester
1831    where
1832        Self: Sized + Send + Sync + 'static,
1833    {
1834        ArcTester::new(self)
1835    }
1836
1837    #[inline]
1838    fn into_fn(self) -> impl Fn() -> bool
1839    where
1840        Self: Sized + 'static,
1841    {
1842        self
1843    }
1844
1845    #[inline]
1846    fn to_box(&self) -> BoxTester
1847    where
1848        Self: Clone + Sized + 'static,
1849    {
1850        self.clone().into_box()
1851    }
1852
1853    #[inline]
1854    fn to_rc(&self) -> RcTester
1855    where
1856        Self: Clone + Sized + 'static,
1857    {
1858        self.clone().into_rc()
1859    }
1860
1861    #[inline]
1862    fn to_arc(&self) -> ArcTester
1863    where
1864        Self: Clone + Sized + Send + Sync + 'static,
1865    {
1866        self.clone().into_arc()
1867    }
1868
1869    #[inline]
1870    fn to_fn(&self) -> impl Fn() -> bool
1871    where
1872        Self: Clone + Sized,
1873    {
1874        self.clone()
1875    }
1876}
1877
1878// ============================================================================
1879// Extension Trait for Convenient Closure Conversion
1880// ============================================================================
1881
1882/// Extension trait providing logical composition methods for closures
1883///
1884/// This trait is automatically implemented for all closures and function
1885/// pointers that match `Fn() -> bool`, enabling method chaining starting
1886/// from a closure.
1887///
1888/// # Examples
1889///
1890/// ```rust
1891/// use qubit_function::{FnTesterOps, Tester};
1892///
1893/// let is_ready = || true;
1894/// let is_available = || true;
1895///
1896/// // Combine testers using extension methods
1897/// let combined = is_ready.and(is_available);
1898/// assert!(combined.test());
1899/// ```
1900///
1901/// # Author
1902///
1903/// Haixing Hu
1904pub trait FnTesterOps: Sized + Fn() -> bool {
1905    /// Returns a tester that represents the logical AND of this tester
1906    /// and another
1907    ///
1908    /// # Parameters
1909    ///
1910    /// * `other` - The other tester to combine with. **Note: This parameter
1911    ///   is passed by value and will transfer ownership.** If you need to
1912    ///   preserve the original tester, clone it first (if it implements
1913    ///   `Clone`). Can be:
1914    ///   - Another closure
1915    ///   - A function pointer
1916    ///   - A `BoxTester`, `RcTester`, or `ArcTester`
1917    ///
1918    /// # Return Value
1919    ///
1920    /// A `BoxTester` representing the logical AND
1921    ///
1922    /// # Examples
1923    ///
1924    /// ```rust
1925    /// use qubit_function::{FnTesterOps, Tester};
1926    ///
1927    /// let is_ready = || true;
1928    /// let is_available = || true;
1929    ///
1930    /// let combined = is_ready.and(is_available);
1931    /// assert!(combined.test());
1932    /// ```
1933    #[inline]
1934    fn and<T>(self, other: T) -> BoxTester
1935    where
1936        Self: 'static,
1937        T: Tester + 'static,
1938    {
1939        BoxTester::new(move || self.test() && other.test())
1940    }
1941
1942    /// Returns a tester that represents the logical OR of this tester
1943    /// and another
1944    ///
1945    /// # Parameters
1946    ///
1947    /// * `other` - The other tester to combine with. **Note: This parameter
1948    ///   is passed by value and will transfer ownership.** If you need to
1949    ///   preserve the original tester, clone it first (if it implements
1950    ///   `Clone`). Can be:
1951    ///   - Another closure
1952    ///   - A function pointer
1953    ///   - A `BoxTester`, `RcTester`, or `ArcTester`
1954    ///   - Any type implementing `Tester`
1955    ///
1956    /// # Return Value
1957    ///
1958    /// A `BoxTester` representing the logical OR
1959    ///
1960    /// # Examples
1961    ///
1962    /// ```rust
1963    /// use qubit_function::{FnTesterOps, Tester};
1964    ///
1965    /// let is_ready = || false;
1966    /// let is_fallback = || true;
1967    ///
1968    /// let combined = is_ready.or(is_fallback);
1969    /// assert!(combined.test());
1970    /// ```
1971    #[inline]
1972    fn or<T>(self, other: T) -> BoxTester
1973    where
1974        Self: 'static,
1975        T: Tester + 'static,
1976    {
1977        BoxTester::new(move || self.test() || other.test())
1978    }
1979
1980    /// Returns a tester that represents the logical negation of this tester
1981    ///
1982    /// # Return Value
1983    ///
1984    /// A `BoxTester` representing the logical negation
1985    ///
1986    /// # Examples
1987    ///
1988    /// ```rust
1989    /// use qubit_function::{FnTesterOps, Tester};
1990    ///
1991    /// let is_ready = || false;
1992    /// let not_ready = is_ready.not();
1993    /// assert!(not_ready.test());
1994    /// ```
1995    #[inline]
1996    fn not(self) -> BoxTester
1997    where
1998        Self: 'static,
1999    {
2000        BoxTester::new(move || !self.test())
2001    }
2002
2003    /// Returns a tester that represents the logical NAND (NOT AND) of this
2004    /// tester and another
2005    ///
2006    /// NAND returns `true` unless both testers are `true`.
2007    /// Equivalent to `!(self AND other)`.
2008    ///
2009    /// # Parameters
2010    ///
2011    /// * `other` - The other tester to combine with. **Note: This parameter
2012    ///   is passed by value and will transfer ownership.** If you need to
2013    ///   preserve the original tester, clone it first (if it implements
2014    ///   `Clone`). Accepts closures, function pointers, or any
2015    ///   `Tester` implementation.
2016    ///
2017    /// # Return Value
2018    ///
2019    /// A `BoxTester` representing the logical NAND
2020    ///
2021    /// # Examples
2022    ///
2023    /// ```rust
2024    /// use qubit_function::{FnTesterOps, Tester};
2025    ///
2026    /// let is_ready = || true;
2027    /// let is_available = || true;
2028    ///
2029    /// let nand = is_ready.nand(is_available);
2030    /// assert!(!nand.test());  // !(true && true) = false
2031    /// ```
2032    #[inline]
2033    fn nand<T>(self, other: T) -> BoxTester
2034    where
2035        Self: 'static,
2036        T: Tester + 'static,
2037    {
2038        BoxTester::new(move || !(self.test() && other.test()))
2039    }
2040
2041    /// Returns a tester that represents the logical XOR (exclusive OR) of
2042    /// this tester and another
2043    ///
2044    /// XOR returns `true` if exactly one of the testers is `true`.
2045    ///
2046    /// # Parameters
2047    ///
2048    /// * `other` - The other tester to combine with. **Note: This parameter
2049    ///   is passed by value and will transfer ownership.** If you need to
2050    ///   preserve the original tester, clone it first (if it implements
2051    ///   `Clone`). Accepts closures, function pointers, or any
2052    ///   `Tester` implementation.
2053    ///
2054    /// # Return Value
2055    ///
2056    /// A `BoxTester` representing the logical XOR
2057    ///
2058    /// # Examples
2059    ///
2060    /// ```rust
2061    /// use qubit_function::{FnTesterOps, Tester};
2062    ///
2063    /// let is_ready = || true;
2064    /// let is_available = || false;
2065    ///
2066    /// let xor = is_ready.xor(is_available);
2067    /// assert!(xor.test());  // true ^ false = true
2068    /// ```
2069    #[inline]
2070    fn xor<T>(self, other: T) -> BoxTester
2071    where
2072        Self: 'static,
2073        T: Tester + 'static,
2074    {
2075        BoxTester::new(move || self.test() ^ other.test())
2076    }
2077
2078    /// Returns a tester that represents the logical NOR (NOT OR) of this
2079    /// tester and another
2080    ///
2081    /// NOR returns `true` only when both testers are `false`. Equivalent
2082    /// to `!(self OR other)`.
2083    ///
2084    /// # Parameters
2085    ///
2086    /// * `other` - The other tester to combine with. **Note: This parameter
2087    ///   is passed by value and will transfer ownership.** If you need to
2088    ///   preserve the original tester, clone it first (if it implements
2089    ///   `Clone`). Accepts closures, function pointers, or any
2090    ///   `Tester` implementation.
2091    ///
2092    /// # Return Value
2093    ///
2094    /// A `BoxTester` representing the logical NOR
2095    ///
2096    /// # Examples
2097    ///
2098    /// ```rust
2099    /// use qubit_function::{FnTesterOps, Tester};
2100    ///
2101    /// let is_ready = || false;
2102    /// let is_available = || false;
2103    ///
2104    /// let nor = is_ready.nor(is_available);
2105    /// assert!(nor.test());  // !(false || false) = true
2106    /// ```
2107    #[inline]
2108    fn nor<T>(self, other: T) -> BoxTester
2109    where
2110        Self: 'static,
2111        T: Tester + 'static,
2112    {
2113        BoxTester::new(move || !(self.test() || other.test()))
2114    }
2115}
2116
2117// Blanket implementation for all closures
2118impl<F> FnTesterOps for F where F: Fn() -> bool {}