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