Skip to main content

qubit_function/consumers/bi_consumer/
fn_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 `FnBiConsumerOps` public type.
12
13use super::{
14    BiConsumer,
15    BoxBiConsumer,
16};
17
18// =======================================================================
19// 6. Provide extension methods for closures
20// =======================================================================
21
22/// Extension trait providing non-mutating bi-consumer composition methods for
23/// closures
24///
25/// Provides `and_then` and other composition methods for all closures
26/// implementing `Fn(&T, &U)`, enabling direct method chaining on closures
27/// without explicit wrapper types.
28///
29/// # Features
30///
31/// - **Natural Syntax**: Chain operations directly on closures
32/// - **Returns BoxBiConsumer**: Composition results can be
33///   further chained
34/// - **Zero Cost**: No overhead when composing closures
35/// - **Automatic Implementation**: All `Fn(&T, &U)` closures get these
36///   methods automatically
37///
38/// # Examples
39///
40/// ```rust
41/// use qubit_function::{BiConsumer, FnBiConsumerOps};
42///
43/// let chained = (|x: &i32, y: &i32| {
44///     println!("First: {}, {}", x, y);
45/// }).and_then(|x: &i32, y: &i32| {
46///     println!("Second: sum = {}", x + y);
47/// });
48/// chained.accept(&5, &3);
49/// ```
50///
51pub trait FnBiConsumerOps<T, U>: Fn(&T, &U) + Sized {
52    /// Chains another non-mutating bi-consumer in sequence
53    ///
54    /// Returns a new consumer executing the current operation first, then
55    /// the next operation. Consumes the current closure and returns
56    /// `BoxBiConsumer<T, U>`.
57    ///
58    /// # Type Parameters
59    ///
60    /// * `C` - The type of the next consumer
61    ///
62    /// # Parameters
63    ///
64    /// * `next` - The consumer to execute after the current operation
65    ///
66    /// # Returns
67    ///
68    /// Returns the composed `BoxBiConsumer<T, U>`
69    ///
70    /// # Examples
71    ///
72    /// ```rust
73    /// use qubit_function::{BiConsumer, FnBiConsumerOps};
74    ///
75    /// let chained = (|x: &i32, y: &i32| {
76    ///     println!("First: {}, {}", x, y);
77    /// }).and_then(|x: &i32, y: &i32| {
78    ///     println!("Second: sum = {}", x + y);
79    /// }).and_then(|x: &i32, y: &i32| {
80    ///     println!("Third: product = {}", x * y);
81    /// });
82    ///
83    /// chained.accept(&5, &3);
84    /// ```
85    fn and_then<C>(self, next: C) -> BoxBiConsumer<T, U>
86    where
87        Self: 'static,
88        C: BiConsumer<T, U> + 'static,
89        T: 'static,
90        U: 'static,
91    {
92        let first = self;
93        let second = next;
94        BoxBiConsumer::new(move |t, u| {
95            first(t, u);
96            second.accept(t, u);
97        })
98    }
99}
100
101/// Implements FnBiConsumerOps for all closure types
102impl<T, U, F> FnBiConsumerOps<T, U> for F where F: Fn(&T, &U) {}