Skip to main content

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