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
13use std::ops::Not;
14
15use super::{
16 ArcTester,
17 BoxTester,
18 Rc,
19 Tester,
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 {
93 function: Rc::new(f),
94 }
95 }
96
97 /// Combines this tester with another tester using logical AND
98 ///
99 /// Returns a new `RcTester` that returns `true` only when both tests
100 /// pass. Borrows `&self`, so the original tester remains available.
101 ///
102 /// # Parameters
103 ///
104 /// * `next` - The tester to combine with
105 ///
106 /// # Return Value
107 ///
108 /// A new `RcTester` representing logical AND
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use qubit_function::{RcTester, Tester};
114 ///
115 /// let first = RcTester::new(|| true);
116 /// let second = RcTester::new(|| true);
117 /// let combined = first.and(&second);
118 /// // first and second are still available
119 /// ```
120 #[inline]
121 pub fn and(&self, next: &RcTester) -> RcTester {
122 let self_fn = Rc::clone(&self.function);
123 let next_fn = Rc::clone(&next.function);
124 RcTester {
125 function: Rc::new(move || self_fn() && next_fn()),
126 }
127 }
128
129 /// Combines this tester with another tester using logical OR
130 ///
131 /// Returns a new `RcTester` that returns `true` if either test passes.
132 /// Borrows `&self`, so the original tester remains available.
133 ///
134 /// # Parameters
135 ///
136 /// * `next` - The tester to combine with
137 ///
138 /// # Return Value
139 ///
140 /// A new `RcTester` representing logical OR
141 ///
142 /// # Examples
143 ///
144 /// ```rust
145 /// use qubit_function::{RcTester, Tester};
146 ///
147 /// let first = RcTester::new(|| false);
148 /// let second = RcTester::new(|| true);
149 /// let combined = first.or(&second);
150 /// // first and second are still available
151 /// ```
152 #[inline]
153 pub fn or(&self, next: &RcTester) -> RcTester {
154 let self_fn = Rc::clone(&self.function);
155 let next_fn = Rc::clone(&next.function);
156 RcTester {
157 function: Rc::new(move || self_fn() || next_fn()),
158 }
159 }
160
161 /// Combines this tester with another tester using logical NAND
162 ///
163 /// Returns a new `RcTester` that returns `true` unless both tests pass.
164 /// Borrows `&self`, so the original tester remains available.
165 ///
166 /// # Parameters
167 ///
168 /// * `next` - The tester to combine with
169 ///
170 /// # Return Value
171 ///
172 /// A new `RcTester` representing logical NAND
173 ///
174 /// # Examples
175 ///
176 /// ```rust
177 /// use qubit_function::{RcTester, Tester};
178 ///
179 /// let first = RcTester::new(|| true);
180 /// let second = RcTester::new(|| true);
181 /// let nand = first.nand(&second);
182 ///
183 /// // Both true returns false
184 /// assert!(!nand.test());
185 ///
186 /// // first and second still available
187 /// assert!(first.test());
188 /// assert!(second.test());
189 /// ```
190 #[inline]
191 pub fn nand(&self, next: &RcTester) -> RcTester {
192 let self_fn = Rc::clone(&self.function);
193 let next_fn = Rc::clone(&next.function);
194 RcTester {
195 function: Rc::new(move || !(self_fn() && next_fn())),
196 }
197 }
198
199 /// Combines this tester with another tester using logical XOR
200 ///
201 /// Returns a new `RcTester` that returns `true` if exactly one test
202 /// passes. Borrows `&self`, so the original tester remains available.
203 ///
204 /// # Parameters
205 ///
206 /// * `next` - The tester to combine with
207 ///
208 /// # Return Value
209 ///
210 /// A new `RcTester` representing logical XOR
211 ///
212 /// # Examples
213 ///
214 /// ```rust
215 /// use qubit_function::{RcTester, Tester};
216 ///
217 /// let first = RcTester::new(|| true);
218 /// let second = RcTester::new(|| false);
219 /// let xor = first.xor(&second);
220 ///
221 /// // One true one false returns true
222 /// assert!(xor.test());
223 ///
224 /// // first and second still available
225 /// assert!(first.test());
226 /// assert!(!second.test());
227 /// ```
228 #[inline]
229 pub fn xor(&self, next: &RcTester) -> RcTester {
230 let self_fn = Rc::clone(&self.function);
231 let next_fn = Rc::clone(&next.function);
232 RcTester {
233 function: Rc::new(move || self_fn() ^ next_fn()),
234 }
235 }
236
237 /// Combines this tester with another tester using logical NOR
238 ///
239 /// Returns a new `RcTester` that returns `true` only when both tests
240 /// fail. Borrows `&self`, so the original tester remains available.
241 ///
242 /// # Parameters
243 ///
244 /// * `next` - The tester to combine with
245 ///
246 /// # Return Value
247 ///
248 /// A new `RcTester` representing logical NOR
249 ///
250 /// # Examples
251 ///
252 /// ```rust
253 /// use qubit_function::{RcTester, Tester};
254 ///
255 /// let first = RcTester::new(|| false);
256 /// let second = RcTester::new(|| false);
257 /// let nor = first.nor(&second);
258 ///
259 /// // Both false returns true
260 /// assert!(nor.test());
261 ///
262 /// // first and second still available
263 /// assert!(!first.test());
264 /// assert!(!second.test());
265 /// ```
266 #[inline]
267 pub fn nor(&self, next: &RcTester) -> RcTester {
268 let self_fn = Rc::clone(&self.function);
269 let next_fn = Rc::clone(&next.function);
270 RcTester {
271 function: Rc::new(move || !(self_fn() || next_fn())),
272 }
273 }
274}
275
276impl Not for RcTester {
277 type Output = RcTester;
278
279 #[inline]
280 fn not(self) -> Self::Output {
281 let func = self.function;
282 RcTester {
283 function: Rc::new(move || !func()),
284 }
285 }
286}
287
288impl Not for &RcTester {
289 type Output = RcTester;
290
291 #[inline]
292 fn not(self) -> Self::Output {
293 let func = Rc::clone(&self.function);
294 RcTester {
295 function: Rc::new(move || !func()),
296 }
297 }
298}
299
300impl Tester for RcTester {
301 #[inline]
302 fn test(&self) -> bool {
303 (self.function)()
304 }
305
306 #[inline]
307 fn into_box(self) -> BoxTester {
308 BoxTester {
309 function: Box::new(move || (self.function)()),
310 }
311 }
312
313 #[inline]
314 fn into_rc(self) -> RcTester {
315 self
316 }
317
318 // Note: RcTester is not Send + Sync, so into_arc() cannot be
319 // implemented. Calling into_arc() on RcTester will result in a
320 // compile error due to the Send + Sync trait bounds not being
321 // satisfied. The default Tester trait implementation will be used.
322
323 #[inline]
324 fn into_fn(self) -> impl Fn() -> bool {
325 move || (self.function)()
326 }
327
328 #[inline]
329 fn to_box(&self) -> BoxTester {
330 let self_fn = self.function.clone();
331 BoxTester {
332 function: Box::new(move || self_fn()),
333 }
334 }
335
336 #[inline]
337 fn to_rc(&self) -> RcTester {
338 self.clone()
339 }
340
341 // Note: RcTester is not Send + Sync, so to_arc() cannot be
342 // implemented. Calling to_arc() on RcTester will result in a compile
343 // error due to the Send + Sync trait bounds not being satisfied. The
344 // default Tester trait implementation will be used.
345
346 #[inline]
347 fn to_fn(&self) -> impl Fn() -> bool {
348 let self_fn = self.function.clone();
349 move || self_fn()
350 }
351}
352
353impl Clone for RcTester {
354 /// Creates a clone of this `RcTester`.
355 ///
356 /// The cloned instance shares the same underlying function with
357 /// the original, allowing multiple references to the same test
358 /// logic.
359 #[inline]
360 fn clone(&self) -> Self {
361 Self {
362 function: Rc::clone(&self.function),
363 }
364 }
365}
366
367// ============================================================================
368// Tester Implementation for Closures
369// ============================================================================
370
371impl<F> Tester for F
372where
373 F: Fn() -> bool,
374{
375 #[inline]
376 fn test(&self) -> bool {
377 self()
378 }
379
380 #[inline]
381 fn into_box(self) -> BoxTester
382 where
383 Self: Sized + 'static,
384 {
385 BoxTester::new(self)
386 }
387
388 #[inline]
389 fn into_rc(self) -> RcTester
390 where
391 Self: Sized + 'static,
392 {
393 RcTester::new(self)
394 }
395
396 #[inline]
397 fn into_arc(self) -> ArcTester
398 where
399 Self: Sized + Send + Sync + 'static,
400 {
401 ArcTester::new(self)
402 }
403
404 #[inline]
405 fn into_fn(self) -> impl Fn() -> bool
406 where
407 Self: Sized + 'static,
408 {
409 self
410 }
411
412 #[inline]
413 fn to_box(&self) -> BoxTester
414 where
415 Self: Clone + Sized + 'static,
416 {
417 self.clone().into_box()
418 }
419
420 #[inline]
421 fn to_rc(&self) -> RcTester
422 where
423 Self: Clone + Sized + 'static,
424 {
425 self.clone().into_rc()
426 }
427
428 #[inline]
429 fn to_arc(&self) -> ArcTester
430 where
431 Self: Clone + Sized + Send + Sync + 'static,
432 {
433 self.clone().into_arc()
434 }
435
436 #[inline]
437 fn to_fn(&self) -> impl Fn() -> bool
438 where
439 Self: Clone + Sized,
440 {
441 self.clone()
442 }
443}