Skip to main content

qubit_function/consumers/stateful_bi_consumer/
arc_stateful_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 `ArcStatefulBiConsumer` public type.
12
13use super::{
14    Arc,
15    ArcConditionalStatefulBiConsumer,
16    BiPredicate,
17    BoxBiConsumerOnce,
18    BoxStatefulBiConsumer,
19    Mutex,
20    RcStatefulBiConsumer,
21    StatefulBiConsumer,
22    impl_arc_conversions,
23    impl_closure_trait,
24    impl_consumer_clone,
25    impl_consumer_common_methods,
26    impl_consumer_debug_display,
27    impl_shared_consumer_methods,
28};
29
30type ArcStatefulBiConsumerFn<T, U> = Arc<Mutex<dyn FnMut(&T, &U) + Send>>;
31
32// =======================================================================
33// 4. ArcStatefulBiConsumer - Thread-Safe Shared Ownership Implementation
34// =======================================================================
35
36/// ArcStatefulBiConsumer struct
37///
38/// A bi-consumer implementation based on
39/// `Arc<Mutex<dyn FnMut(&T, &U) + Send>>` for thread-safe shared
40/// ownership scenarios. This consumer can be safely cloned and shared
41/// across multiple threads.
42///
43/// # Features
44///
45/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
46/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
47/// - **Interior Mutability**: Uses `Mutex` for safe mutable access
48/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
49///   usable
50/// - **Cross-Thread Sharing**: Can be sent to and used by other threads
51///
52/// # Use Cases
53///
54/// Choose `ArcStatefulBiConsumer` when:
55/// - Need to share bi-consumer across multiple threads
56/// - Concurrent task processing (e.g., thread pools)
57/// - Using the same consumer in multiple places simultaneously
58/// - Thread safety (Send + Sync) is required
59///
60/// # Performance Considerations
61///
62/// `ArcStatefulBiConsumer` has some overhead compared to `BoxStatefulBiConsumer`:
63/// - **Reference Counting**: Atomic operations on clone/drop
64/// - **Mutex Locking**: Each `accept` call requires lock acquisition
65/// - **Lock Contention**: High concurrency may cause contention
66///
67/// These overheads are necessary for safe concurrent access. If thread
68/// safety is not needed, consider using `RcStatefulBiConsumer` for lower
69/// overhead in single-threaded sharing.
70///
71/// # Examples
72///
73/// ```rust
74/// use qubit_function::{BiConsumer, ArcStatefulBiConsumer, StatefulBiConsumer};
75/// use std::sync::{Arc, Mutex};
76///
77/// let log = Arc::new(Mutex::new(Vec::new()));
78/// let l = log.clone();
79/// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
80///     l.lock().expect("mutex should not be poisoned").push(*x + *y);
81/// });
82/// let mut clone = consumer.clone();
83///
84/// consumer.accept(&5, &3);
85/// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![8]);
86/// ```
87///
88pub struct ArcStatefulBiConsumer<T, U> {
89    pub(super) function: ArcStatefulBiConsumerFn<T, U>,
90    pub(super) name: Option<String>,
91}
92
93impl<T, U> ArcStatefulBiConsumer<T, U> {
94    // Generates: new(), new_with_name(), name(), set_name(), noop()
95    impl_consumer_common_methods!(
96        ArcStatefulBiConsumer<T, U>,
97        (FnMut(&T, &U) + Send + 'static),
98        |f| Arc::new(Mutex::new(f))
99    );
100
101    // Generates: when() and and_then() methods that borrow &self (Arc can clone)
102    impl_shared_consumer_methods!(
103        ArcStatefulBiConsumer<T, U>,
104        ArcConditionalStatefulBiConsumer,
105        into_arc,
106        StatefulBiConsumer,
107        Send + Sync + 'static
108    );
109}
110
111impl<T, U> StatefulBiConsumer<T, U> for ArcStatefulBiConsumer<T, U> {
112    fn accept(&mut self, first: &T, second: &U) {
113        (self.function.lock())(first, second)
114    }
115
116    // Use macro to implement conversion methods
117    impl_arc_conversions!(
118        ArcStatefulBiConsumer<T, U>,
119        BoxStatefulBiConsumer,
120        RcStatefulBiConsumer,
121        BoxBiConsumerOnce,
122        FnMut(t: &T, u: &U)
123    );
124}
125
126// Use macro to generate Clone implementation
127impl_consumer_clone!(ArcStatefulBiConsumer<T, U>);
128
129// Use macro to generate Debug and Display implementations
130impl_consumer_debug_display!(ArcStatefulBiConsumer<T, U>);
131
132// =======================================================================
133// 5. Implement BiConsumer trait for closures
134// =======================================================================
135
136// Implements BiConsumer for all FnMut(&T, &U)
137impl_closure_trait!(
138    StatefulBiConsumer<T, U>,
139    accept,
140    BoxBiConsumerOnce,
141    FnMut(first: &T, second: &U)
142);