qubit_function/consumers/stateful_bi_consumer/fn_stateful_bi_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 `FnStatefulBiConsumerOps` public type.
12
13use super::{
14 BoxStatefulBiConsumer,
15 StatefulBiConsumer,
16};
17
18// =======================================================================
19// 6. Provide extension methods for closures
20// =======================================================================
21
22/// Extension trait providing bi-consumer composition methods for closures
23///
24/// Provides `and_then` and other composition methods for all closures
25/// implementing `FnMut(&T, &U)`, enabling direct method chaining on
26/// closures without explicit wrapper types.
27///
28/// # Design Rationale
29///
30/// This trait allows closures to be composed naturally using method
31/// syntax, similar to iterator combinators. Composition methods consume
32/// the closure and return `BoxStatefulBiConsumer<T, U>`, which can be further
33/// chained.
34///
35/// # Features
36///
37/// - **Natural Syntax**: Chain operations directly on closures
38/// - **Returns BoxStatefulBiConsumer**: Composition results are
39/// `BoxStatefulBiConsumer<T, U>` for continued chaining
40/// - **Zero Cost**: No overhead when composing closures
41/// - **Automatic Implementation**: All `FnMut(&T, &U)` closures get
42/// these methods automatically
43///
44/// # Examples
45///
46/// ```rust
47/// use qubit_function::{BiConsumer, FnStatefulBiConsumerOps, StatefulBiConsumer};
48/// use std::sync::{Arc, Mutex};
49///
50/// let log = Arc::new(Mutex::new(Vec::new()));
51/// let l1 = log.clone();
52/// let l2 = log.clone();
53/// let mut chained = (move |x: &i32, y: &i32| {
54/// l1.lock().expect("mutex should not be poisoned").push(*x + *y);
55/// }).and_then(move |x: &i32, y: &i32| {
56/// l2.lock().expect("mutex should not be poisoned").push(*x * *y);
57/// });
58/// chained.accept(&5, &3);
59/// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![8, 15]);
60/// ```
61///
62pub trait FnStatefulBiConsumerOps<T, U>: FnMut(&T, &U) + Sized {
63 /// Chains another consumer in sequence
64 ///
65 /// Returns a new consumer executing the current operation first, then
66 /// the next operation. Consumes the current closure and returns
67 /// `BoxStatefulBiConsumer<T, U>`.
68 ///
69 /// # Type Parameters
70 ///
71 /// * `C` - The type of the next consumer
72 ///
73 /// # Parameters
74 ///
75 /// * `next` - The consumer to execute after the current operation. **Note:
76 /// This parameter is passed by value and will transfer ownership.** If you
77 /// need to preserve the original consumer, clone it first (if it implements
78 /// `Clone`). Can be:
79 /// - A closure: `|x: &T, y: &U|`
80 /// - A `BoxStatefulBiConsumer<T, U>`
81 /// - An `ArcStatefulBiConsumer<T, U>`
82 /// - An `RcStatefulBiConsumer<T, U>`
83 /// - Any type implementing `BiConsumer<T, U>`
84 ///
85 /// # Returns
86 ///
87 /// Returns the composed `BoxStatefulBiConsumer<T, U>`
88 ///
89 /// # Examples
90 ///
91 /// ```rust
92 /// use qubit_function::{BiConsumer, FnStatefulBiConsumerOps, StatefulBiConsumer};
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 mut chained = (move |x: &i32, y: &i32| {
99 /// l1.lock().expect("mutex should not be poisoned").push(*x + *y);
100 /// }).and_then(move |x: &i32, y: &i32| {
101 /// l2.lock().expect("mutex should not be poisoned").push(*x * *y);
102 /// }).and_then(|x: &i32, y: &i32| println!("Result: {}, {}", x, y));
103 ///
104 /// chained.accept(&5, &3); // Prints: Result: 5, 3
105 /// assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![8, 15]);
106 /// ```
107 fn and_then<C>(self, next: C) -> BoxStatefulBiConsumer<T, U>
108 where
109 Self: 'static,
110 C: StatefulBiConsumer<T, U> + 'static,
111 T: 'static,
112 U: 'static,
113 {
114 let mut first = self;
115 let mut second = next;
116 BoxStatefulBiConsumer::new(move |t, u| {
117 first(t, u);
118 second.accept(t, u);
119 })
120 }
121}
122
123/// Implements FnStatefulBiConsumerOps for all closure types
124impl<T, U, F> FnStatefulBiConsumerOps<T, U> for F where F: FnMut(&T, &U) {}