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