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
55// ============================================================================
56// 1. ConsumerOnce Trait - Unified ConsumerOnce Interface
57// ============================================================================
58
59/// ConsumerOnce trait - Unified one-time consumer interface
60///
61/// It is similar to the `FnOnce(&T)` trait in the standard library.
62///
63/// Defines the core behavior of all one-time consumer types. Similar to consumers
64/// implementing `FnOnce(&T)`, executes operations that accept a value reference but
65/// return no result (only side effects), consuming itself in the process.
66///
67/// # Automatic Implementation
68///
69/// - All closures implementing `FnOnce(&T)`
70/// - `BoxConsumerOnce<T>`
71///
72/// # Features
73///
74/// - **Unified Interface**: All consumer types share the same `accept` method signature
75/// - **Automatic Implementation**: Closures automatically implement this trait with zero overhead
76/// - **Type Conversion**: Can be converted to BoxConsumerOnce
77/// - **Generic Programming**: Write functions that work with any one-time consumer type
78///
79/// # Examples
80///
81/// ```rust
82/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
83/// use std::sync::{Arc, Mutex};
84///
85/// fn apply_consumer<C: ConsumerOnce<i32>>(consumer: C, value: &i32) {
86///     consumer.accept(value);
87/// }
88///
89/// let log = Arc::new(Mutex::new(Vec::new()));
90/// let l = log.clone();
91/// let box_con = BoxConsumerOnce::new(move |x: &i32| {
92///     l.lock().unwrap().push(*x);
93/// });
94/// apply_consumer(box_con, &5);
95/// assert_eq!(*log.lock().unwrap(), vec![5]);
96/// ```
97///
98/// # Author
99///
100/// Haixing Hu
101pub trait ConsumerOnce<T> {
102    /// Execute one-time consumption operation
103    ///
104    /// Executes an operation on the given reference. The operation typically reads
105    /// the input value or produces side effects, but does not modify the input
106    /// value itself. Consumes self.
107    ///
108    /// # Parameters
109    ///
110    /// * `value` - Reference to the value to be consumed
111    ///
112    /// # Examples
113    ///
114    /// ```rust
115    /// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
116    ///
117    /// let consumer = BoxConsumerOnce::new(|x: &i32| println!("{}", x));
118    /// consumer.accept(&5);
119    /// ```
120    fn accept(self, value: &T);
121
122    /// Convert to BoxConsumerOnce
123    ///
124    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
125    ///
126    /// # Default Implementation
127    ///
128    /// The default implementation wraps `self` in a `BoxConsumerOnce` by calling
129    /// `accept` on the consumer. Types can override this method to provide more
130    /// efficient conversions.
131    ///
132    /// # Returns
133    ///
134    /// Returns the wrapped `BoxConsumerOnce<T>`
135    ///
136    /// # Examples
137    ///
138    /// ```rust
139    /// use qubit_function::ConsumerOnce;
140    /// use std::sync::{Arc, Mutex};
141    ///
142    /// let log = Arc::new(Mutex::new(Vec::new()));
143    /// let l = log.clone();
144    /// let closure = move |x: &i32| {
145    ///     l.lock().unwrap().push(*x);
146    /// };
147    /// let box_consumer = closure.into_box();
148    /// box_consumer.accept(&5);
149    /// assert_eq!(*log.lock().unwrap(), vec![5]);
150    /// ```
151    fn into_box(self) -> BoxConsumerOnce<T>
152    where
153        Self: Sized + 'static,
154    {
155        BoxConsumerOnce::new(move |t| self.accept(t))
156    }
157
158    /// Convert to closure
159    ///
160    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
161    ///
162    /// Converts a one-time consumer to a closure that can be used directly in places
163    /// where the standard library requires `FnOnce`.
164    ///
165    /// # Default Implementation
166    ///
167    /// The default implementation creates a closure that captures `self` and calls
168    /// its `accept` method. Types can override this method to provide more efficient
169    /// conversions.
170    ///
171    /// # Returns
172    ///
173    /// Returns a closure implementing `FnOnce(&T)`
174    ///
175    /// # Examples
176    ///
177    /// ```rust
178    /// use qubit_function::ConsumerOnce;
179    /// use std::sync::{Arc, Mutex};
180    ///
181    /// let log = Arc::new(Mutex::new(Vec::new()));
182    /// let l = log.clone();
183    /// let closure = move |x: &i32| {
184    ///     l.lock().unwrap().push(*x * 2);
185    /// };
186    /// let func = closure.into_fn();
187    /// func(&5);
188    /// assert_eq!(*log.lock().unwrap(), vec![10]);
189    /// ```
190    fn into_fn(self) -> impl FnOnce(&T)
191    where
192        Self: Sized + 'static,
193    {
194        move |t| self.accept(t)
195    }
196
197    /// Convert to BoxConsumerOnce without consuming self
198    ///
199    /// **⚠️ Requires Clone**: This method requires `Self` to implement
200    /// `Clone`. Clones the current consumer and wraps it in a
201    /// `BoxConsumerOnce`.
202    ///
203    /// # Default Implementation
204    ///
205    /// The default implementation clones `self` and then calls
206    /// `into_box()` on the clone. Types can override this method to
207    /// provide more efficient conversions.
208    ///
209    /// # Returns
210    ///
211    /// Returns the wrapped `BoxConsumerOnce<T>`
212    ///
213    /// # Examples
214    ///
215    /// ```rust
216    /// use qubit_function::ConsumerOnce;
217    /// use std::sync::{Arc, Mutex};
218    ///
219    /// let log = Arc::new(Mutex::new(Vec::new()));
220    /// let l = log.clone();
221    /// let closure = move |x: &i32| {
222    ///     l.lock().unwrap().push(*x);
223    /// };
224    /// let box_consumer = closure.to_box();
225    /// box_consumer.accept(&5);
226    /// assert_eq!(*log.lock().unwrap(), vec![5]);
227    /// ```
228    fn to_box(&self) -> BoxConsumerOnce<T>
229    where
230        Self: Sized + Clone + 'static,
231    {
232        self.clone().into_box()
233    }
234
235    /// Convert to closure without consuming self
236    ///
237    /// **⚠️ Requires Clone**: This method requires `Self` to implement
238    /// `Clone`. Clones the current consumer and then converts the clone
239    /// to a closure.
240    ///
241    /// # Default Implementation
242    ///
243    /// The default implementation clones `self` and then calls
244    /// `into_fn()` on the clone. Types can override this method to
245    /// provide more efficient conversions.
246    ///
247    /// # Returns
248    ///
249    /// Returns a closure implementing `FnOnce(&T)`
250    ///
251    /// # Examples
252    ///
253    /// ```rust
254    /// use qubit_function::ConsumerOnce;
255    /// use std::sync::{Arc, Mutex};
256    ///
257    /// let log = Arc::new(Mutex::new(Vec::new()));
258    /// let l = log.clone();
259    /// let closure = move |x: &i32| {
260    ///     l.lock().unwrap().push(*x * 2);
261    /// };
262    /// let func = closure.to_fn();
263    /// func(&5);
264    /// assert_eq!(*log.lock().unwrap(), vec![10]);
265    /// ```
266    fn to_fn(&self) -> impl FnOnce(&T)
267    where
268        Self: Sized + Clone + 'static,
269    {
270        self.clone().into_fn()
271    }
272}
273
274// ============================================================================
275// 2. BoxConsumerOnce - Single Ownership Implementation
276// ============================================================================
277
278/// BoxConsumerOnce struct
279///
280/// One-time consumer implementation based on `Box<dyn FnOnce(&T)>` for single ownership scenarios.
281/// This is the simplest consumer type for truly one-time use.
282///
283/// # Features
284///
285/// - **Single Ownership**: Not cloneable, transfers ownership on use
286/// - **Zero Overhead**: No reference counting or lock overhead
287/// - **One-time Use**: Consumes self on first call
288/// - **Builder Pattern**: Method chaining naturally consumes `self`
289///
290/// # Use Cases
291///
292/// Choose `BoxConsumerOnce` when:
293/// - Consumer is truly used only once
294/// - Building pipelines where ownership flows naturally
295/// - Consumer captures values that should be consumed
296/// - Performance critical and cannot accept shared overhead
297///
298/// # Performance
299///
300/// `BoxConsumerOnce` has the best performance:
301/// - No reference counting overhead
302/// - No lock acquisition or runtime borrow checking
303/// - Direct function call through vtable
304/// - Minimal memory footprint (single pointer)
305///
306/// # Examples
307///
308/// ```rust
309/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
310///
311/// let consumer = BoxConsumerOnce::new(|x: &i32| {
312///     println!("Value: {}", x);
313/// });
314/// consumer.accept(&5);
315/// ```
316///
317/// # Author
318///
319/// Haixing Hu
320pub struct BoxConsumerOnce<T> {
321    function: Box<dyn FnOnce(&T)>,
322    name: Option<String>,
323}
324
325// All methods require T: 'static because Box<dyn FnOnce(&T)> requires it
326impl<T> BoxConsumerOnce<T> {
327    // Generates: new(), new_with_name(), name(), set_name(), noop()
328    impl_consumer_common_methods!(BoxConsumerOnce<T>, (FnOnce(&T) + 'static), |f| Box::new(f));
329
330    // Generates: when() and and_then() methods that consume self
331    impl_box_consumer_methods!(BoxConsumerOnce<T>, BoxConditionalConsumerOnce, ConsumerOnce);
332}
333
334impl<T> ConsumerOnce<T> for BoxConsumerOnce<T> {
335    fn accept(self, value: &T) {
336        (self.function)(value)
337    }
338
339    impl_box_once_conversions!(BoxConsumerOnce<T>, ConsumerOnce, FnOnce(&T));
340}
341
342// Use macro to generate Debug and Display implementations
343impl_consumer_debug_display!(BoxConsumerOnce<T>);
344
345// ============================================================================
346// 3. Implement ConsumerOnce trait for closures
347// ============================================================================
348
349// Implement ConsumerOnce for all FnOnce(&T) using macro
350impl_closure_once_trait!(
351    ConsumerOnce<T>,
352    accept,
353    BoxConsumerOnce,
354    FnOnce(value: &T)
355);
356
357// ============================================================================
358// 4. Extension methods for closures
359// ============================================================================
360
361/// Extension trait providing one-time consumer composition methods for closures
362///
363/// Provides `and_then` and other composition methods for all closures implementing `FnOnce(&T)`,
364/// allowing closures to chain methods directly without explicit wrapper types.
365///
366/// # Features
367///
368/// - **Natural Syntax**: Chain operations directly on closures
369/// - **Returns BoxConsumerOnce**: Composed results can continue chaining
370/// - **Zero Cost**: No overhead when composing closures
371/// - **Automatic Implementation**: All `FnOnce(&T)` closures automatically get these methods
372///
373/// # Examples
374///
375/// ```rust
376/// use qubit_function::{ConsumerOnce, FnConsumerOnceOps};
377/// use std::sync::{Arc, Mutex};
378///
379/// let log = Arc::new(Mutex::new(Vec::new()));
380/// let l1 = log.clone();
381/// let l2 = log.clone();
382/// let chained = (move |x: &i32| {
383///     l1.lock().unwrap().push(*x * 2);
384/// }).and_then(move |x: &i32| {
385///     l2.lock().unwrap().push(*x + 10);
386/// });
387/// chained.accept(&5);
388/// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
389/// ```
390///
391/// # Author
392///
393/// Haixing Hu
394pub trait FnConsumerOnceOps<T>: FnOnce(&T) + Sized {
395    /// Sequentially chain another one-time consumer
396    ///
397    /// Returns a new consumer that executes the current operation first, then the next operation.
398    /// Consumes the current closure and returns `BoxConsumerOnce<T>`.
399    ///
400    /// # Type Parameters
401    ///
402    /// * `C` - Type of the next consumer
403    ///
404    /// # Parameters
405    ///
406    /// * `next` - Consumer to execute after the current operation. **Note: This
407    ///   parameter is passed by value and will transfer ownership.** Since
408    ///   `BoxConsumerOnce` cannot be cloned, the parameter will be consumed.
409    ///   Can be:
410    ///   - A closure: `|x: &T|`
411    ///   - A `BoxConsumerOnce<T>`
412    ///   - Any type implementing `ConsumerOnce<T>`
413    ///
414    /// # Returns
415    ///
416    /// Returns a combined `BoxConsumerOnce<T>`
417    ///
418    /// # Examples
419    ///
420    /// ```rust
421    /// use qubit_function::{ConsumerOnce, FnConsumerOnceOps};
422    /// use std::sync::{Arc, Mutex};
423    ///
424    /// let log = Arc::new(Mutex::new(Vec::new()));
425    /// let l1 = log.clone();
426    /// let l2 = log.clone();
427    /// let chained = (move |x: &i32| {
428    ///     l1.lock().unwrap().push(*x * 2);
429    /// }).and_then(move |x: &i32| {
430    ///     l2.lock().unwrap().push(*x + 10);
431    /// }).and_then(|x: &i32| println!("Result: {}", x));
432    ///
433    /// chained.accept(&5);
434    /// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
435    /// ```
436    fn and_then<C>(self, next: C) -> BoxConsumerOnce<T>
437    where
438        Self: 'static,
439        C: ConsumerOnce<T> + 'static,
440        T: 'static,
441    {
442        let first = self;
443        let second = next;
444        BoxConsumerOnce::new(move |t| {
445            first(t);
446            second.accept(t);
447        })
448    }
449}
450
451/// Implement FnConsumerOnceOps for all closure types
452impl<T, F> FnConsumerOnceOps<T> for F where F: FnOnce(&T) {}
453
454// ============================================================================
455// 5. BoxConditionalConsumerOnce - Box-based Conditional Consumer
456// ============================================================================
457
458/// BoxConditionalConsumerOnce struct
459///
460/// A conditional one-time consumer that only executes when a predicate is satisfied.
461/// Uses `BoxConsumerOnce` and `BoxPredicate` for single ownership semantics.
462///
463/// This type is typically created by calling `BoxConsumerOnce::when()` and is
464/// designed to work with the `or_else()` method to create if-then-else logic.
465///
466/// # Features
467///
468/// - **Single Ownership**: Not cloneable, consumes `self` on use
469/// - **Conditional Execution**: Only consumes when predicate returns `true`
470/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
471/// - **Implements ConsumerOnce**: Can be used anywhere a `ConsumerOnce` is expected
472///
473/// # Examples
474///
475/// ## Basic Conditional Execution
476///
477/// ```rust
478/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
479/// use std::sync::{Arc, Mutex};
480///
481/// let log = Arc::new(Mutex::new(Vec::new()));
482/// let l = log.clone();
483/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
484///     l.lock().unwrap().push(*x);
485/// });
486/// let conditional = consumer.when(|x: &i32| *x > 0);
487///
488/// conditional.accept(&5);
489/// assert_eq!(*log.lock().unwrap(), vec![5]); // Executed
490/// ```
491///
492/// ## With or_else Branch
493///
494/// ```rust
495/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
496/// use std::sync::{Arc, Mutex};
497///
498/// let log = Arc::new(Mutex::new(Vec::new()));
499/// let l1 = log.clone();
500/// let l2 = log.clone();
501/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
502///     l1.lock().unwrap().push(*x);
503/// })
504/// .when(|x: &i32| *x > 0)
505/// .or_else(move |x: &i32| {
506///     l2.lock().unwrap().push(-*x);
507/// });
508///
509/// consumer.accept(&5);
510/// assert_eq!(*log.lock().unwrap(), vec![5]); // when branch executed
511/// ```
512///
513/// # Author
514///
515/// Haixing Hu
516pub struct BoxConditionalConsumerOnce<T> {
517    consumer: BoxConsumerOnce<T>,
518    predicate: BoxPredicate<T>,
519}
520
521// Generate and_then and or_else methods using macro
522impl_box_conditional_consumer!(BoxConditionalConsumerOnce<T>, BoxConsumerOnce, ConsumerOnce);
523
524impl<T> ConsumerOnce<T> for BoxConditionalConsumerOnce<T> {
525    fn accept(self, value: &T) {
526        if self.predicate.test(value) {
527            self.consumer.accept(value);
528        }
529    }
530
531    fn into_fn(self) -> impl FnOnce(&T) {
532        let pred = self.predicate;
533        let consumer = self.consumer;
534        move |t: &T| {
535            if pred.test(t) {
536                consumer.accept(t);
537            }
538        }
539    }
540
541    // do NOT override ConsumerOnce::to_xxxx() because BoxConditionalConsumerOnce is not Clone
542    // and calling BoxConditionalConsumerOnce::to_xxxx() will cause a compile error
543}
544
545// Use macro to generate Debug and Display implementations
546impl_conditional_consumer_debug_display!(BoxConditionalConsumerOnce<T>);