Skip to main content

qubit_function/consumers/
bi_consumer_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # BiConsumerOnce Types
10//!
11//! Provides one-time bi-consumer interface implementations for operations
12//! accepting two input parameters without returning a result.
13//!
14//! It is similar to the `FnOnce(&T, &U)` trait in the standard library.
15//!
16//! This module provides a unified `BiConsumerOnce` trait and one concrete
17//! implementation:
18//!
19//! - **`BoxBiConsumerOnce<T, U>`**: Box-based single ownership
20//!   implementation
21//!
22//! # Why No Arc/Rc Variants?
23//!
24//! Unlike reusable [`BiConsumer`](crate::consumers::BiConsumer)
25//! implementations, this module does **not** provide `ArcBiConsumerOnce` or
26//! `RcBiConsumerOnce` implementations. This is a design decision based on the
27//! fundamental incompatibility between `FnOnce` semantics and shared ownership.
28//! See the design documentation for details.
29//!
30//! # Design Philosophy
31//!
32//! BiConsumerOnce uses `FnOnce(&T, &U)` semantics: for truly one-time
33//! consumption operations.
34//!
35//! Unlike BiConsumer, BiConsumerOnce consumes itself on first call. Suitable
36//! for initialization callbacks, cleanup callbacks, etc.
37//!
38//! # Author
39//!
40//! Haixing Hu
41use crate::{
42    consumers::macros::{
43        impl_box_conditional_consumer,
44        impl_box_consumer_methods,
45        impl_conditional_consumer_debug_display,
46        impl_consumer_common_methods,
47        impl_consumer_debug_display,
48    },
49    macros::{
50        impl_box_once_conversions,
51        impl_closure_once_trait,
52    },
53    predicates::bi_predicate::{
54        BiPredicate,
55        BoxBiPredicate,
56    },
57};
58
59// ==========================================================================
60// Type Aliases
61// ==========================================================================
62
63/// Type alias for bi-consumer once function signature.
64type BiConsumerOnceFn<T, U> = dyn FnOnce(&T, &U);
65
66mod box_bi_consumer_once;
67pub use box_bi_consumer_once::BoxBiConsumerOnce;
68mod fn_bi_consumer_once_ops;
69pub use fn_bi_consumer_once_ops::FnBiConsumerOnceOps;
70mod box_conditional_bi_consumer_once;
71pub use box_conditional_bi_consumer_once::BoxConditionalBiConsumerOnce;
72
73// =======================================================================
74// 1. BiConsumerOnce Trait - Unified Interface
75// =======================================================================
76
77/// BiConsumerOnce trait - Unified one-time bi-consumer interface
78///
79/// It is similar to the `FnOnce(&T, &U)` trait in the standard library.
80///
81/// Defines core behavior for all one-time bi-consumer types. Similar to a
82/// bi-consumer implementing `FnOnce(&T, &U)`, performs operations
83/// accepting two value references but returning no result (side effects
84/// only), consuming itself in the process.
85///
86/// # Automatic Implementations
87///
88/// - All closures implementing `FnOnce(&T, &U)`
89/// - `BoxBiConsumerOnce<T, U>`
90///
91/// # Features
92///
93/// - **Unified Interface**: All bi-consumer types share the same `accept`
94///   method signature
95/// - **Automatic Implementation**: Closures automatically implement this
96///   trait with zero overhead
97/// - **Type Conversions**: Can convert to BoxBiConsumerOnce
98/// - **Generic Programming**: Write functions accepting any one-time
99///   bi-consumer type
100///
101/// # Examples
102///
103/// ```rust
104/// use qubit_function::{BiConsumerOnce, BoxBiConsumerOnce};
105/// use std::sync::{Arc, Mutex};
106///
107/// fn apply_consumer<C: BiConsumerOnce<i32, i32>>(
108///     consumer: C,
109///     a: &i32,
110///     b: &i32
111/// ) {
112///     consumer.accept(a, b);
113/// }
114///
115/// let log = Arc::new(Mutex::new(Vec::new()));
116/// let l = log.clone();
117/// let box_con = BoxBiConsumerOnce::new(move |x: &i32, y: &i32| {
118///     l.lock().unwrap().push(*x + *y);
119/// });
120/// apply_consumer(box_con, &5, &3);
121/// assert_eq!(*log.lock().unwrap(), vec![8]);
122/// ```
123///
124/// # Author
125///
126/// Haixing Hu
127pub trait BiConsumerOnce<T, U> {
128    /// Performs the one-time consumption operation
129    ///
130    /// Executes an operation on the given two references. The operation
131    /// typically reads input values or produces side effects, but does not
132    /// modify the input values themselves. Consumes self.
133    ///
134    /// # Parameters
135    ///
136    /// * `first` - Reference to the first value to consume
137    /// * `second` - Reference to the second value to consume
138    ///
139    /// # Examples
140    ///
141    /// ```rust
142    /// use qubit_function::{BiConsumerOnce, BoxBiConsumerOnce};
143    ///
144    /// let consumer = BoxBiConsumerOnce::new(|x: &i32, y: &i32| {
145    ///     println!("Sum: {}", x + y);
146    /// });
147    /// consumer.accept(&5, &3);
148    /// ```
149    fn accept(self, first: &T, second: &U);
150
151    /// Converts to BoxBiConsumerOnce
152    ///
153    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
154    /// calling this method.
155    ///
156    /// # Returns
157    ///
158    /// Returns the wrapped `BoxBiConsumerOnce<T, U>`
159    ///
160    /// # Examples
161    ///
162    /// ```rust
163    /// use qubit_function::BiConsumerOnce;
164    /// use std::sync::{Arc, Mutex};
165    ///
166    /// let log = Arc::new(Mutex::new(Vec::new()));
167    /// let l = log.clone();
168    /// let closure = move |x: &i32, y: &i32| {
169    ///     l.lock().unwrap().push(*x + *y);
170    /// };
171    /// let box_consumer = closure.into_box();
172    /// box_consumer.accept(&5, &3);
173    /// assert_eq!(*log.lock().unwrap(), vec![8]);
174    /// ```
175    fn into_box(self) -> BoxBiConsumerOnce<T, U>
176    where
177        Self: Sized + 'static,
178    {
179        BoxBiConsumerOnce::new(move |t, u| self.accept(t, u))
180    }
181
182    /// Converts to a closure
183    ///
184    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
185    /// calling this method.
186    ///
187    /// Converts the one-time bi-consumer to a closure usable with standard
188    /// library methods requiring `FnOnce`.
189    ///
190    /// # Returns
191    ///
192    /// Returns a closure implementing `FnOnce(&T, &U)`
193    fn into_fn(self) -> impl FnOnce(&T, &U)
194    where
195        Self: Sized + 'static,
196    {
197        move |t, u| self.accept(t, u)
198    }
199
200    /// Convert to BoxBiConsumerOnce without consuming self
201    ///
202    /// **⚠️ Requires Clone**: This method requires `Self` to implement
203    /// `Clone`. Clones the current bi-consumer and then converts the clone
204    /// to a `BoxBiConsumerOnce`.
205    ///
206    /// # Returns
207    ///
208    /// Returns the wrapped `BoxBiConsumerOnce<T, U>`
209    ///
210    /// # Examples
211    ///
212    /// ```rust
213    /// use qubit_function::BiConsumerOnce;
214    /// use std::sync::{Arc, Mutex};
215    ///
216    /// let log = Arc::new(Mutex::new(Vec::new()));
217    /// let l = log.clone();
218    /// let closure = move |x: &i32, y: &i32| {
219    ///     l.lock().unwrap().push(*x + *y);
220    /// };
221    /// let box_consumer = closure.to_box();
222    /// box_consumer.accept(&5, &3);
223    /// assert_eq!(*log.lock().unwrap(), vec![8]);
224    /// ```
225    fn to_box(&self) -> BoxBiConsumerOnce<T, U>
226    where
227        Self: Sized + Clone + 'static,
228    {
229        self.clone().into_box()
230    }
231
232    /// Convert to closure without consuming self
233    ///
234    /// **⚠️ Requires Clone**: This method requires `Self` to implement
235    /// `Clone`. Clones the current bi-consumer and then converts the clone
236    /// to a closure.
237    ///
238    /// # Returns
239    ///
240    /// Returns a closure implementing `FnOnce(&T, &U)`
241    ///
242    /// # Examples
243    ///
244    /// ```rust
245    /// use qubit_function::BiConsumerOnce;
246    /// use std::sync::{Arc, Mutex};
247    ///
248    /// let log = Arc::new(Mutex::new(Vec::new()));
249    /// let l = log.clone();
250    /// let closure = move |x: &i32, y: &i32| {
251    ///     l.lock().unwrap().push(*x + *y);
252    /// };
253    /// let func = closure.to_fn();
254    /// func(&5, &3);
255    /// assert_eq!(*log.lock().unwrap(), vec![8]);
256    /// ```
257    fn to_fn(&self) -> impl FnOnce(&T, &U)
258    where
259        Self: Sized + Clone + 'static,
260    {
261        self.clone().into_fn()
262    }
263}