Skip to main content

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