Skip to main content

qubit_function/consumers/bi_consumer/
rc_bi_consumer.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 `RcBiConsumer` public type.
12
13#![allow(unused_imports)]
14
15use super::*;
16
17// =======================================================================
18// 3. RcBiConsumer - Single-Threaded Shared Ownership
19// =======================================================================
20
21/// RcBiConsumer struct
22///
23/// A non-mutating bi-consumer implementation based on `Rc<dyn Fn(&T, &U)>`
24/// for single-threaded shared ownership scenarios. The wrapper does not need
25/// `RefCell` because it only invokes a shared `Fn`.
26///
27/// # Features
28///
29/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
30/// - **Single-Threaded**: Not thread-safe, cannot send across threads
31/// - **No Wrapper Interior Mutability Overhead**: No RefCell needed by the
32///   wrapper
33/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
34///   usable
35///
36/// # Use Cases
37///
38/// Choose `RcBiConsumer` when:
39/// - Need to share non-mutating bi-consumer within a single thread
40/// - Pure observation operations, performance critical
41/// - Single-threaded UI framework event handling
42///
43/// # Performance Advantages
44///
45/// `RcBiConsumer` has neither Arc's atomic operation overhead nor
46/// RefCell's runtime borrow checking overhead, making it the best
47/// performing among the three non-mutating bi-consumer types.
48///
49/// # Examples
50///
51/// ```rust
52/// use qubit_function::{BiConsumer, RcBiConsumer};
53///
54/// let consumer: RcBiConsumer<i32, i32> = RcBiConsumer::new(|x: &i32, y: &i32| {
55///     println!("Sum: {}", x + y);
56/// });
57/// let clone = consumer.clone();
58///
59/// consumer.accept(&5, &3);
60/// clone.accept(&10, &20);
61/// ```
62///
63pub struct RcBiConsumer<T, U> {
64    pub(super) function: Rc<BiConsumerFn<T, U>>,
65    pub(super) name: Option<String>,
66}
67
68impl<T, U> RcBiConsumer<T, U> {
69    // Generates: new(), new_with_name(), name(), set_name(), noop()
70    impl_consumer_common_methods!(
71        RcBiConsumer<T, U>,
72        (Fn(&T, &U) + 'static),
73        |f| Rc::new(f)
74    );
75
76    // Generates: when() and and_then() methods that borrow &self (Rc can clone)
77    impl_shared_consumer_methods!(
78        RcBiConsumer<T, U>,
79        RcConditionalBiConsumer,
80        into_rc,
81        BiConsumer,
82        'static
83    );
84}
85
86impl<T, U> BiConsumer<T, U> for RcBiConsumer<T, U> {
87    fn accept(&self, first: &T, second: &U) {
88        (self.function)(first, second)
89    }
90
91    // Use macro to implement conversion methods
92    impl_rc_conversions!(
93        RcBiConsumer<T, U>,
94        BoxBiConsumer,
95        BoxBiConsumerOnce,
96        Fn(t: &T, u: &U)
97    );
98}
99
100// Use macro to generate Clone implementation
101impl_consumer_clone!(RcBiConsumer<T, U>);
102
103// Use macro to generate Debug and Display implementations
104impl_consumer_debug_display!(RcBiConsumer<T, U>);