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>);