qubit_function/testers/tester/rc_tester.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10// qubit-style: allow explicit-imports
11//! Defines the `RcTester` public type.
12
13use std::ops::Not;
14
15use super::{
16 Rc,
17 Tester,
18 arc_tester::ArcTester,
19 box_tester::BoxTester,
20};
21
22// ============================================================================
23// RcTester: Single-Threaded Shared Ownership Implementation
24// ============================================================================
25
26/// Single-threaded shared ownership Tester implemented using `Rc`
27///
28/// `RcTester` wraps a closure in `Rc<dyn Fn() -> bool>`, allowing the tester
29/// to be cloned and shared within a single thread. Since it doesn't use atomic
30/// operations, it has lower overhead than `ArcTester`.
31///
32/// # Characteristics
33///
34/// - **Shared ownership**: Can be cloned
35/// - **Single-threaded**: Cannot be sent across threads
36/// - **Low overhead**: Uses `Fn` without needing `RefCell`
37/// - **Borrowing combination**: `and()`/`or()` borrow `&self`
38///
39/// # Use Cases
40///
41/// - Single-threaded testing scenarios requiring sharing
42/// - Event-driven systems (single-threaded)
43/// - Callback-intensive code requiring cloneable tests
44/// - Performance-sensitive single-threaded code
45///
46/// # Examples
47///
48/// ```rust
49/// use qubit_function::{RcTester, Tester};
50///
51/// let shared = RcTester::new(|| true);
52///
53/// // Clone for multiple uses
54/// let clone1 = shared.clone();
55/// let clone2 = shared.clone();
56///
57/// // Non-consuming combination
58/// let combined = shared.and(&clone1);
59/// ```
60///
61pub struct RcTester {
62 pub(super) function: Rc<dyn Fn() -> bool>,
63}
64
65impl RcTester {
66 /// Creates a new `RcTester` from a closure
67 ///
68 /// # Type Parameters
69 ///
70 /// * `F` - Closure type implementing `Fn() -> bool`
71 ///
72 /// # Parameters
73 ///
74 /// * `f` - The closure to wrap
75 ///
76 /// # Return Value
77 ///
78 /// A new `RcTester` instance
79 ///
80 /// # Examples
81 ///
82 /// ```rust
83 /// use qubit_function::RcTester;
84 ///
85 /// let tester = RcTester::new(|| true);
86 /// ```
87 #[inline]
88 pub fn new<F>(f: F) -> Self
89 where
90 F: Fn() -> bool + 'static,
91 {
92 RcTester { function: Rc::new(f) }
93 }
94
95 /// Combines this tester with another tester using logical AND
96 ///
97 /// Returns a new `RcTester` that returns `true` only when both tests
98 /// pass. Borrows `&self`, so the original tester remains available.
99 ///
100 /// # Parameters
101 ///
102 /// * `next` - The tester to combine with
103 ///
104 /// # Return Value
105 ///
106 /// A new `RcTester` representing logical AND
107 ///
108 /// # Examples
109 ///
110 /// ```rust
111 /// use qubit_function::{RcTester, Tester};
112 ///
113 /// let first = RcTester::new(|| true);
114 /// let second = RcTester::new(|| true);
115 /// let combined = first.and(&second);
116 /// // first and second are still available
117 /// ```
118 #[inline]
119 pub fn and(&self, next: &RcTester) -> RcTester {
120 let self_fn = Rc::clone(&self.function);
121 let next_fn = Rc::clone(&next.function);
122 RcTester {
123 function: Rc::new(move || self_fn() && next_fn()),
124 }
125 }
126
127 /// Combines this tester with another tester using logical OR
128 ///
129 /// Returns a new `RcTester` that returns `true` if either test passes.
130 /// Borrows `&self`, so the original tester remains available.
131 ///
132 /// # Parameters
133 ///
134 /// * `next` - The tester to combine with
135 ///
136 /// # Return Value
137 ///
138 /// A new `RcTester` representing logical OR
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// use qubit_function::{RcTester, Tester};
144 ///
145 /// let first = RcTester::new(|| false);
146 /// let second = RcTester::new(|| true);
147 /// let combined = first.or(&second);
148 /// // first and second are still available
149 /// ```
150 #[inline]
151 pub fn or(&self, next: &RcTester) -> RcTester {
152 let self_fn = Rc::clone(&self.function);
153 let next_fn = Rc::clone(&next.function);
154 RcTester {
155 function: Rc::new(move || self_fn() || next_fn()),
156 }
157 }
158
159 /// Combines this tester with another tester using logical NAND
160 ///
161 /// Returns a new `RcTester` that returns `true` unless both tests pass.
162 /// Borrows `&self`, so the original tester remains available.
163 ///
164 /// # Parameters
165 ///
166 /// * `next` - The tester to combine with
167 ///
168 /// # Return Value
169 ///
170 /// A new `RcTester` representing logical NAND
171 ///
172 /// # Examples
173 ///
174 /// ```rust
175 /// use qubit_function::{RcTester, Tester};
176 ///
177 /// let first = RcTester::new(|| true);
178 /// let second = RcTester::new(|| true);
179 /// let nand = first.nand(&second);
180 ///
181 /// // Both true returns false
182 /// assert!(!nand.test());
183 ///
184 /// // first and second still available
185 /// assert!(first.test());
186 /// assert!(second.test());
187 /// ```
188 #[inline]
189 pub fn nand(&self, next: &RcTester) -> RcTester {
190 let self_fn = Rc::clone(&self.function);
191 let next_fn = Rc::clone(&next.function);
192 RcTester {
193 function: Rc::new(move || !(self_fn() && next_fn())),
194 }
195 }
196
197 /// Combines this tester with another tester using logical XOR
198 ///
199 /// Returns a new `RcTester` that returns `true` if exactly one test
200 /// passes. Borrows `&self`, so the original tester remains available.
201 ///
202 /// # Parameters
203 ///
204 /// * `next` - The tester to combine with
205 ///
206 /// # Return Value
207 ///
208 /// A new `RcTester` representing logical XOR
209 ///
210 /// # Examples
211 ///
212 /// ```rust
213 /// use qubit_function::{RcTester, Tester};
214 ///
215 /// let first = RcTester::new(|| true);
216 /// let second = RcTester::new(|| false);
217 /// let xor = first.xor(&second);
218 ///
219 /// // One true one false returns true
220 /// assert!(xor.test());
221 ///
222 /// // first and second still available
223 /// assert!(first.test());
224 /// assert!(!second.test());
225 /// ```
226 #[inline]
227 pub fn xor(&self, next: &RcTester) -> RcTester {
228 let self_fn = Rc::clone(&self.function);
229 let next_fn = Rc::clone(&next.function);
230 RcTester {
231 function: Rc::new(move || self_fn() ^ next_fn()),
232 }
233 }
234
235 /// Combines this tester with another tester using logical NOR
236 ///
237 /// Returns a new `RcTester` that returns `true` only when both tests
238 /// fail. Borrows `&self`, so the original tester remains available.
239 ///
240 /// # Parameters
241 ///
242 /// * `next` - The tester to combine with
243 ///
244 /// # Return Value
245 ///
246 /// A new `RcTester` representing logical NOR
247 ///
248 /// # Examples
249 ///
250 /// ```rust
251 /// use qubit_function::{RcTester, Tester};
252 ///
253 /// let first = RcTester::new(|| false);
254 /// let second = RcTester::new(|| false);
255 /// let nor = first.nor(&second);
256 ///
257 /// // Both false returns true
258 /// assert!(nor.test());
259 ///
260 /// // first and second still available
261 /// assert!(!first.test());
262 /// assert!(!second.test());
263 /// ```
264 #[inline]
265 pub fn nor(&self, next: &RcTester) -> RcTester {
266 let self_fn = Rc::clone(&self.function);
267 let next_fn = Rc::clone(&next.function);
268 RcTester {
269 function: Rc::new(move || !(self_fn() || next_fn())),
270 }
271 }
272}
273
274impl Not for RcTester {
275 type Output = RcTester;
276
277 #[inline]
278 fn not(self) -> Self::Output {
279 let func = self.function;
280 RcTester {
281 function: Rc::new(move || !func()),
282 }
283 }
284}
285
286impl Not for &RcTester {
287 type Output = RcTester;
288
289 #[inline]
290 fn not(self) -> Self::Output {
291 let func = Rc::clone(&self.function);
292 RcTester {
293 function: Rc::new(move || !func()),
294 }
295 }
296}
297
298impl Tester for RcTester {
299 #[inline]
300 fn test(&self) -> bool {
301 (self.function)()
302 }
303
304 #[inline]
305 fn into_box(self) -> BoxTester {
306 BoxTester {
307 function: Box::new(move || (self.function)()),
308 }
309 }
310
311 #[inline]
312 fn into_rc(self) -> RcTester {
313 self
314 }
315
316 // Note: RcTester is not Send + Sync, so into_arc() cannot be
317 // implemented. Calling into_arc() on RcTester will result in a
318 // compile error due to the Send + Sync trait bounds not being
319 // satisfied. The default Tester trait implementation will be used.
320
321 #[inline]
322 fn into_fn(self) -> impl Fn() -> bool {
323 move || (self.function)()
324 }
325
326 #[inline]
327 fn to_box(&self) -> BoxTester {
328 let self_fn = self.function.clone();
329 BoxTester {
330 function: Box::new(move || self_fn()),
331 }
332 }
333
334 #[inline]
335 fn to_rc(&self) -> RcTester {
336 self.clone()
337 }
338
339 // Note: RcTester is not Send + Sync, so to_arc() cannot be
340 // implemented. Calling to_arc() on RcTester will result in a compile
341 // error due to the Send + Sync trait bounds not being satisfied. The
342 // default Tester trait implementation will be used.
343
344 #[inline]
345 fn to_fn(&self) -> impl Fn() -> bool {
346 let self_fn = self.function.clone();
347 move || self_fn()
348 }
349}
350
351impl Clone for RcTester {
352 /// Creates a clone of this `RcTester`.
353 ///
354 /// The cloned instance shares the same underlying function with
355 /// the original, allowing multiple references to the same test
356 /// logic.
357 #[inline]
358 fn clone(&self) -> Self {
359 Self {
360 function: Rc::clone(&self.function),
361 }
362 }
363}
364
365// ============================================================================
366// Tester Implementation for Closures
367// ============================================================================
368
369impl<F> Tester for F
370where
371 F: Fn() -> bool,
372{
373 #[inline]
374 fn test(&self) -> bool {
375 self()
376 }
377
378 #[inline]
379 fn into_box(self) -> BoxTester
380 where
381 Self: Sized + 'static,
382 {
383 BoxTester::new(self)
384 }
385
386 #[inline]
387 fn into_rc(self) -> RcTester
388 where
389 Self: Sized + 'static,
390 {
391 RcTester::new(self)
392 }
393
394 #[inline]
395 fn into_arc(self) -> ArcTester
396 where
397 Self: Sized + Send + Sync + 'static,
398 {
399 ArcTester::new(self)
400 }
401
402 #[inline]
403 fn into_fn(self) -> impl Fn() -> bool
404 where
405 Self: Sized + 'static,
406 {
407 self
408 }
409
410 #[inline]
411 fn to_box(&self) -> BoxTester
412 where
413 Self: Clone + Sized + 'static,
414 {
415 self.clone().into_box()
416 }
417
418 #[inline]
419 fn to_rc(&self) -> RcTester
420 where
421 Self: Clone + Sized + 'static,
422 {
423 self.clone().into_rc()
424 }
425
426 #[inline]
427 fn to_arc(&self) -> ArcTester
428 where
429 Self: Clone + Sized + Send + Sync + 'static,
430 {
431 self.clone().into_arc()
432 }
433
434 #[inline]
435 fn to_fn(&self) -> impl Fn() -> bool
436 where
437 Self: Clone + Sized,
438 {
439 self.clone()
440 }
441}