Skip to main content

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