qubit_function/consumers/bi_consumer_once/fn_bi_consumer_once_ops.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `FnBiConsumerOnceOps` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15// =======================================================================
16// 4. Provide extension methods for closures
17// =======================================================================
18
19/// Extension trait providing one-time bi-consumer composition methods for
20/// closures
21///
22/// Provides `and_then` and other composition methods for all closures
23/// implementing `FnOnce(&T, &U)`, enabling direct method chaining on
24/// closures without explicit wrapper types.
25///
26/// # Features
27///
28/// - **Natural Syntax**: Chain operations directly on closures
29/// - **Returns BoxBiConsumerOnce**: Composition results can be further
30/// chained
31/// - **Zero Cost**: No overhead when composing closures
32/// - **Automatic Implementation**: All `FnOnce(&T, &U)` closures get
33/// these methods automatically
34///
35/// # Examples
36///
37/// ```rust
38/// use qubit_function::{BiConsumerOnce, FnBiConsumerOnceOps};
39/// use std::sync::{Arc, Mutex};
40///
41/// let log = Arc::new(Mutex::new(Vec::new()));
42/// let l1 = log.clone();
43/// let l2 = log.clone();
44/// let chained = (move |x: &i32, y: &i32| {
45/// l1.lock().unwrap().push(*x + *y);
46/// }).and_then(move |x: &i32, y: &i32| {
47/// l2.lock().unwrap().push(*x * *y);
48/// });
49/// chained.accept(&5, &3);
50/// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
51/// ```
52///
53/// # Author
54///
55/// Haixing Hu
56pub trait FnBiConsumerOnceOps<T, U>: FnOnce(&T, &U) + Sized {
57 /// Chains another one-time bi-consumer in sequence
58 ///
59 /// Returns a new consumer executing the current operation first, then
60 /// the next operation. Consumes the current closure and returns
61 /// `BoxBiConsumerOnce<T, U>`.
62 ///
63 /// # Type Parameters
64 ///
65 /// * `C` - The type of the next consumer
66 ///
67 /// # Parameters
68 ///
69 /// * `next` - The consumer to execute after the current operation. **Note:
70 /// This parameter is passed by value and will transfer ownership.** Since
71 /// `BoxBiConsumerOnce` cannot be cloned, the parameter will be consumed.
72 /// Can be:
73 /// - A closure: `|x: &T, y: &U|`
74 /// - A `BoxBiConsumerOnce<T, U>`
75 /// - Any type implementing `BiConsumerOnce<T, U>`
76 ///
77 /// # Returns
78 ///
79 /// Returns the composed `BoxBiConsumerOnce<T, U>`
80 ///
81 /// # Examples
82 ///
83 /// ```rust
84 /// use qubit_function::{BiConsumerOnce, FnBiConsumerOnceOps};
85 /// use std::sync::{Arc, Mutex};
86 ///
87 /// let log = Arc::new(Mutex::new(Vec::new()));
88 /// let l1 = log.clone();
89 /// let l2 = log.clone();
90 /// let chained = (move |x: &i32, y: &i32| {
91 /// l1.lock().unwrap().push(*x + *y);
92 /// }).and_then(move |x: &i32, y: &i32| {
93 /// l2.lock().unwrap().push(*x * *y);
94 /// }).and_then(|x: &i32, y: &i32| {
95 /// println!("Result: {}, {}", x, y);
96 /// });
97 ///
98 /// chained.accept(&5, &3);
99 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
100 /// ```
101 fn and_then<C>(self, next: C) -> BoxBiConsumerOnce<T, U>
102 where
103 Self: 'static,
104 C: BiConsumerOnce<T, U> + 'static,
105 T: 'static,
106 U: 'static,
107 {
108 let first = self;
109 let second = next;
110 BoxBiConsumerOnce::new(move |t, u| {
111 first(t, u);
112 second.accept(t, u);
113 })
114 }
115}
116
117/// Implements FnBiConsumerOnceOps for all closure types
118impl<T, U, F> FnBiConsumerOnceOps<T, U> for F where F: FnOnce(&T, &U) {}