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