prism3_function/
tester.rs

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