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) {}