Skip to main content

qubit_function/consumers/
consumer_once.rs

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