Skip to main content

qubit_function/consumers/bi_consumer/
arc_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 `ArcBiConsumer` public type.
12
13use super::{
14    Arc,
15    ArcConditionalBiConsumer,
16    BiConsumer,
17    BiPredicate,
18    BoxBiConsumer,
19    BoxBiConsumerOnce,
20    RcBiConsumer,
21    ThreadSafeBiConsumerFn,
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
30// =======================================================================
31// 4. ArcBiConsumer - Thread-Safe Shared Ownership
32// =======================================================================
33
34/// ArcBiConsumer struct
35///
36/// A non-mutating bi-consumer implementation based on
37/// `Arc<dyn Fn(&T, &U) + Send + Sync>` for thread-safe shared ownership
38/// scenarios. The wrapper does not need `Mutex` because it only invokes a
39/// shared `Fn`.
40///
41/// # Features
42///
43/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
44/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
45/// - **Lock-free Wrapper**: No Mutex protection needed by the wrapper
46/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
47///   usable
48///
49/// # Use Cases
50///
51/// Choose `ArcBiConsumer` when:
52/// - Need to share non-mutating bi-consumer across multiple threads
53/// - Pure observation operations like logging, monitoring, notifications
54/// - Need high-concurrency reads without lock overhead
55///
56/// # Performance Advantages
57///
58/// Compared to `ArcStatefulBiConsumer`, `ArcBiConsumer` has no Mutex locking
59/// overhead, resulting in better performance in high-concurrency observation
60/// scenarios.
61///
62/// # Examples
63///
64/// ```rust
65/// use qubit_function::{BiConsumer, ArcBiConsumer};
66///
67/// let consumer = ArcBiConsumer::new(|x: &i32, y: &i32| {
68///     println!("Sum: {}", x + y);
69/// });
70/// let clone = consumer.clone();
71///
72/// consumer.accept(&5, &3);
73/// clone.accept(&10, &20);
74/// ```
75///
76pub struct ArcBiConsumer<T, U> {
77    pub(super) function: Arc<ThreadSafeBiConsumerFn<T, U>>,
78    pub(super) name: Option<String>,
79}
80
81impl<T, U> ArcBiConsumer<T, U> {
82    // Generates: new(), new_with_name(), name(), set_name(), noop()
83    impl_consumer_common_methods!(
84        ArcBiConsumer<T, U>,
85        (Fn(&T, &U) + Send + Sync + 'static),
86        |f| Arc::new(f)
87    );
88
89    // Generates: when() and and_then() methods that borrow &self (Arc can clone)
90    impl_shared_consumer_methods!(
91        ArcBiConsumer<T, U>,
92        ArcConditionalBiConsumer,
93        into_arc,
94        BiConsumer,
95        Send + Sync + 'static
96    );
97}
98
99impl<T, U> BiConsumer<T, U> for ArcBiConsumer<T, U> {
100    fn accept(&self, first: &T, second: &U) {
101        (self.function)(first, second)
102    }
103
104    // Use macro to implement conversion methods
105    impl_arc_conversions!(
106        ArcBiConsumer<T, U>,
107        BoxBiConsumer,
108        RcBiConsumer,
109        BoxBiConsumerOnce,
110        Fn(t: &T, u: &U)
111    );
112}
113
114// Use macro to generate Clone implementation
115impl_consumer_clone!(ArcBiConsumer<T, U>);
116
117// Use macro to generate Debug and Display implementations
118impl_consumer_debug_display!(ArcBiConsumer<T, U>);
119
120// =======================================================================
121// 5. Implement BiConsumer trait for closures
122// =======================================================================
123
124// Implements BiConsumer for all Fn(&T, &U)
125impl_closure_trait!(
126    BiConsumer<T, U>,
127    accept,
128    BoxBiConsumerOnce,
129    Fn(first: &T, second: &U)
130);