Skip to main content

qubit_function/testers/
tester.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! Defines the `Tester` public trait.
11
12use super::{
13    Arc,
14    Rc,
15};
16
17use self::{
18    arc_tester::ArcTester,
19    box_tester::BoxTester,
20    rc_tester::RcTester,
21};
22
23pub mod arc_tester;
24pub mod box_tester;
25pub mod fn_tester_ops;
26pub mod rc_tester;
27
28/// Tests whether a zero-argument condition holds.
29///
30/// `Tester` is a functional abstraction equivalent to `Fn() -> bool`. It
31/// accepts no parameters, uses `&self`, and returns a boolean value indicating
32/// the test result of some state or condition.
33///
34/// # Core Characteristics
35///
36/// - **No input parameters**: Captures context through closures
37/// - **Returns boolean**: Indicates test results
38/// - **Uses `&self`**: Matches `Fn() -> bool` and does not require mutable
39///   access to its own state
40/// - **Repeatable calls**: The same Tester can call `test()` multiple times
41/// - **Stateless closure shape**: For `FnMut() -> bool`, use
42///   [`StatefulTester`](super::stateful_tester::StatefulTester)
43///
44/// # Use Cases
45///
46/// - **State checking**: Check system or service status
47/// - **Condition waiting**: Repeatedly check until conditions are met
48/// - **Health monitoring**: Check system health status
49/// - **Precondition validation**: Verify conditions before operations
50///
51/// # Design Philosophy
52///
53/// Tester's responsibility is "test judgment", not "state management".
54/// State management is the caller's responsibility. Tester only reads state
55/// and returns judgment results.
56///
57/// # Examples
58///
59/// ```rust
60/// use qubit_function::{BoxTester, Tester};
61/// use std::sync::{Arc, atomic::{AtomicBool, Ordering}};
62///
63/// // State managed externally
64/// let ready = Arc::new(AtomicBool::new(false));
65/// let ready_clone = Arc::clone(&ready);
66///
67/// // Tester only responsible for reading state
68/// let tester = BoxTester::new(move || {
69///     ready_clone.load(Ordering::Acquire)
70/// });
71///
72/// // Can be called multiple times
73/// assert!(!tester.test());
74/// ready.store(true, Ordering::Release);
75/// assert!(tester.test());
76/// ```
77pub trait Tester {
78    /// Executes the test and returns the test result
79    ///
80    /// This method can be called multiple times without modifying the Tester's
81    /// own state.
82    ///
83    /// # Return Value
84    ///
85    /// Returns `true` if the condition holds, otherwise returns `false`
86    ///
87    /// # Examples
88    ///
89    /// ```rust
90    /// use qubit_function::{BoxTester, Tester};
91    ///
92    /// let tester = BoxTester::new(|| true);
93    /// assert!(tester.test());
94    /// ```
95    fn test(&self) -> bool;
96
97    /// Converts this tester to `BoxTester`
98    ///
99    /// # Return Value
100    ///
101    /// A `BoxTester` that wraps this tester
102    ///
103    /// # Examples
104    ///
105    /// ```rust
106    /// use qubit_function::{Tester, BoxTester};
107    ///
108    /// let closure = || true;
109    /// let boxed: BoxTester = closure.into_box();
110    /// ```
111    #[inline]
112    fn into_box(self) -> BoxTester
113    where
114        Self: Sized + 'static,
115    {
116        BoxTester {
117            function: Box::new(move || self.test()),
118        }
119    }
120
121    /// Converts this tester to `RcTester`
122    ///
123    /// # Return Value
124    ///
125    /// A `RcTester` that wraps this tester
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use qubit_function::{Tester, RcTester};
131    ///
132    /// let closure = || true;
133    /// let rc: RcTester = closure.into_rc();
134    /// ```
135    #[inline]
136    fn into_rc(self) -> RcTester
137    where
138        Self: Sized + 'static,
139    {
140        RcTester {
141            function: Rc::new(move || self.test()),
142        }
143    }
144
145    /// Converts this tester to `ArcTester`
146    ///
147    /// # Return Value
148    ///
149    /// An `ArcTester` that wraps this tester
150    ///
151    /// # Examples
152    ///
153    /// ```rust
154    /// use qubit_function::{Tester, ArcTester};
155    ///
156    /// let closure = || true;
157    /// let arc: ArcTester = closure.into_arc();
158    /// ```
159    #[inline]
160    fn into_arc(self) -> ArcTester
161    where
162        Self: Sized + Send + Sync + 'static,
163    {
164        ArcTester {
165            function: Arc::new(move || self.test()),
166        }
167    }
168
169    /// Converts this tester to a boxed function pointer
170    ///
171    /// # Return Value
172    ///
173    /// A `Box<dyn Fn() -> bool>` that wraps this tester
174    ///
175    /// # Examples
176    ///
177    /// ```rust
178    /// use qubit_function::Tester;
179    ///
180    /// let closure = || true;
181    /// let func = closure.into_fn();
182    /// assert!(func());
183    /// ```
184    #[inline]
185    fn into_fn(self) -> impl Fn() -> bool
186    where
187        Self: Sized + 'static,
188    {
189        Box::new(move || self.test())
190    }
191
192    /// Clones and converts this tester to `BoxTester`
193    ///
194    /// # Return Value
195    ///
196    /// A `BoxTester` that wraps a clone of this tester
197    ///
198    /// # Examples
199    ///
200    /// ```rust
201    /// use qubit_function::{Tester, BoxTester, ArcTester};
202    ///
203    /// let arc = ArcTester::new(|| true);
204    /// let boxed: BoxTester = arc.to_box();
205    /// // arc is still available
206    /// ```
207    #[inline]
208    fn to_box(&self) -> BoxTester
209    where
210        Self: Clone + 'static,
211    {
212        self.clone().into_box()
213    }
214
215    /// Clones and converts this tester to `RcTester`
216    ///
217    /// # Return Value
218    ///
219    /// A `RcTester` that wraps a clone of this tester
220    ///
221    /// # Examples
222    ///
223    /// ```rust
224    /// use qubit_function::{Tester, RcTester, ArcTester};
225    ///
226    /// let arc = ArcTester::new(|| true);
227    /// let rc: RcTester = arc.to_rc();
228    /// // arc is still available
229    /// ```
230    #[inline]
231    fn to_rc(&self) -> RcTester
232    where
233        Self: Clone + 'static,
234    {
235        self.clone().into_rc()
236    }
237
238    /// Clones and converts this tester to `ArcTester`
239    ///
240    /// # Return Value
241    ///
242    /// An `ArcTester` that wraps a clone of this tester
243    ///
244    /// # Examples
245    ///
246    /// ```rust
247    /// use qubit_function::{Tester, ArcTester, RcTester};
248    ///
249    /// let rc = RcTester::new(|| true);
250    /// // Note: This will panic for RcTester as it's not Send + Sync
251    /// // let arc: ArcTester = rc.to_arc();
252    /// ```
253    #[inline]
254    fn to_arc(&self) -> ArcTester
255    where
256        Self: Clone + Send + Sync + 'static,
257    {
258        self.clone().into_arc()
259    }
260
261    /// Clones and converts this tester to a boxed function pointer
262    ///
263    /// # Return Value
264    ///
265    /// A `Box<dyn Fn() -> bool>` that wraps a clone of this tester
266    ///
267    /// # Examples
268    ///
269    /// ```rust
270    /// use qubit_function::{Tester, ArcTester};
271    ///
272    /// let arc = ArcTester::new(|| true);
273    /// let func = arc.to_fn();
274    /// // arc is still available
275    /// assert!(func());
276    /// ```
277    #[inline]
278    fn to_fn(&self) -> impl Fn() -> bool
279    where
280        Self: Clone + 'static,
281    {
282        self.clone().into_fn()
283    }
284}