Skip to main content

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