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