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