Skip to main content

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