Skip to main content

qubit_function/consumers/stateful_consumer/
fn_stateful_consumer_ops.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// qubit-style: allow explicit-imports
11//! Defines the `FnStatefulConsumerOps` public type.
12
13use super::{
14    BoxStatefulConsumer,
15    StatefulConsumer,
16};
17
18// ============================================================================
19// 6. Extension methods for closures
20// ============================================================================
21
22/// Extension trait providing consumer composition methods for closures
23///
24/// Provides `and_then` and other composition methods for all closures
25/// implementing `FnMut(&T)`, allowing direct method chaining on closures
26/// without explicit wrapper types.
27///
28/// # Design Philosophy
29///
30/// This trait allows closures to be naturally composed using method syntax,
31/// similar to iterator combinators. Composition methods consume the closure and
32/// return `BoxStatefulConsumer<T>`, which can continue chaining.
33///
34/// # Features
35///
36/// - **Natural Syntax**: Direct method chaining on closures
37/// - **Returns BoxStatefulConsumer**: Composition results in `BoxStatefulConsumer<T>`, can
38///   continue chaining
39/// - **Zero Cost**: No overhead when composing closures
40/// - **Automatic Implementation**: All `FnMut(&T)` closures automatically get
41///   these methods
42///
43/// # Examples
44///
45/// ```rust
46/// use qubit_function::{Consumer, StatefulConsumer, FnStatefulConsumerOps};
47/// use std::sync::{Arc, Mutex};
48///
49/// let log = Arc::new(Mutex::new(Vec::new()));
50/// let l1 = log.clone();
51/// let l2 = log.clone();
52/// let mut chained = (move |x: &i32| {
53///     l1.lock().expect("mutex should not be poisoned").push(*x * 2);
54/// }).and_then(move |x: &i32| {
55///     l2.lock().expect("mutex should not be poisoned").push(*x + 10);
56/// });
57/// chained.accept(&5);
58/// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![10, 15]);
59/// // (5 * 2), (5 + 10)
60/// ```
61///
62pub trait FnStatefulConsumerOps<T>: FnMut(&T) + Sized {
63    /// Sequentially chain another consumer
64    ///
65    /// Returns a new consumer that executes the current operation first, then the
66    /// next operation. Consumes the current closure and returns `BoxStatefulConsumer<T>`.
67    ///
68    /// # Type Parameters
69    ///
70    /// * `C` - Type of the next consumer
71    ///
72    /// # Parameters
73    ///
74    /// * `next` - Consumer to execute after the current operation. **Note: This
75    ///   parameter is passed by value and will transfer ownership.** If you need
76    ///   to preserve the original consumer, clone it first (if it implements
77    ///   `Clone`). Can be:
78    ///   - A closure: `|x: &T|`
79    ///   - A `BoxStatefulConsumer<T>`
80    ///   - An `RcStatefulConsumer<T>`
81    ///   - An `ArcStatefulConsumer<T>`
82    ///   - Any type implementing `Consumer<T>`
83    ///
84    /// # Return Value
85    ///
86    /// Returns a combined `BoxStatefulConsumer<T>`
87    ///
88    /// # Examples
89    ///
90    /// ## Direct value passing (ownership transfer)
91    ///
92    /// ```rust
93    /// use qubit_function::{Consumer, StatefulConsumer, FnStatefulConsumerOps, BoxStatefulConsumer};
94    /// use std::sync::{Arc, Mutex};
95    ///
96    /// let log = Arc::new(Mutex::new(Vec::new()));
97    /// let l1 = log.clone();
98    /// let l2 = log.clone();
99    /// let second = BoxStatefulConsumer::new(move |x: &i32| {
100    ///     l2.lock().expect("mutex should not be poisoned").push(*x + 10);
101    /// });
102    ///
103    /// // second is moved here
104    /// let mut chained = (move |x: &i32| {
105    ///     l1.lock().expect("mutex should not be poisoned").push(*x * 2);
106    /// }).and_then(second);
107    ///
108    /// chained.accept(&5);
109    /// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![10, 15]);
110    /// // second.accept(&3); // Would not compile - moved
111    /// ```
112    ///
113    /// ## Preserving original with clone
114    ///
115    /// ```rust
116    /// use qubit_function::{Consumer, StatefulConsumer, FnStatefulConsumerOps, RcStatefulConsumer};
117    /// use std::sync::{Arc, Mutex};
118    ///
119    /// let log = Arc::new(Mutex::new(Vec::new()));
120    /// let l1 = log.clone();
121    /// let l2 = log.clone();
122    /// let mut second = RcStatefulConsumer::new(move |x: &i32| {
123    ///     l2.lock().expect("mutex should not be poisoned").push(*x + 10);
124    /// });
125    ///
126    /// // Clone to preserve original
127    /// let mut chained = (move |x: &i32| {
128    ///     l1.lock().expect("mutex should not be poisoned").push(*x * 2);
129    /// }).and_then(second.clone());
130    ///
131    /// chained.accept(&5);
132    /// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![10, 15]);
133    ///
134    /// // Original still usable
135    /// second.accept(&3);
136    /// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![10, 15, 13]);
137    /// ```
138    fn and_then<C>(self, next: C) -> BoxStatefulConsumer<T>
139    where
140        Self: 'static,
141        C: StatefulConsumer<T> + 'static,
142        T: 'static,
143    {
144        let mut first = self;
145        let mut second = next;
146        BoxStatefulConsumer::new(move |t| {
147            first(t);
148            second.accept(t);
149        })
150    }
151}
152
153/// Implement FnStatefulConsumerOps for all closure types
154impl<T, F> FnStatefulConsumerOps<T> for F where F: FnMut(&T) {}