qubit_function/mutators/mutator/fn_mutator_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 `FnMutatorOps` public type.
12
13#![allow(unused_imports)]
14
15use super::*;
16
17// ============================================================================
18// 7. Provide extension methods for closures
19// ============================================================================
20
21/// Extension trait providing mutator composition methods for closures
22///
23/// Provides `and_then` and other composition methods for all closures that
24/// implement `Fn(&mut T)`, enabling direct method chaining on closures
25/// without explicit wrapper types.
26///
27/// # Features
28///
29/// - **Natural Syntax**: Chain operations directly on closures
30/// - **Returns BoxMutator**: Composition results are `BoxMutator<T>` for
31/// continued chaining
32/// - **Zero Cost**: No overhead when composing closures
33/// - **Automatic Implementation**: All `Fn(&mut T)` closures get these
34/// methods automatically
35///
36/// # Examples
37///
38/// ```rust
39/// use qubit_function::{Mutator, FnMutatorOps};
40///
41/// let chained = (|x: &mut i32| *x *= 2)
42/// .and_then(|x: &mut i32| *x += 10);
43/// let mut value = 5;
44/// chained.apply(&mut value);
45/// assert_eq!(value, 20); // (5 * 2) + 10
46/// ```
47///
48pub trait FnMutatorOps<T>: Fn(&mut T) + Sized {
49 /// Chains another mutator in sequence
50 ///
51 /// Returns a new mutator that first executes the current operation, then
52 /// executes the next operation. Consumes the current closure and returns
53 /// `BoxMutator<T>`.
54 ///
55 /// # Parameters
56 ///
57 /// * `next` - The mutator to execute after the current operation. **Note:
58 /// This parameter is passed by value and will transfer ownership.** If you
59 /// need to preserve the original mutator, clone it first (if it implements
60 /// `Clone`). Can be:
61 /// - A closure: `|x: &mut T|`
62 /// - A `BoxMutator<T>`
63 /// - An `ArcMutator<T>`
64 /// - An `RcMutator<T>`
65 /// - Any type implementing `Mutator<T>`
66 ///
67 /// # Returns
68 ///
69 /// Returns the composed `BoxMutator<T>`
70 ///
71 /// # Examples
72 ///
73 /// ```rust
74 /// use qubit_function::{Mutator, FnMutatorOps};
75 ///
76 /// let chained = (|x: &mut i32| *x *= 2)
77 /// .and_then(|x: &mut i32| *x += 10);
78 ///
79 /// let mut value = 5;
80 /// chained.apply(&mut value);
81 /// assert_eq!(value, 20);
82 /// ```
83 fn and_then<C>(self, next: C) -> BoxMutator<T>
84 where
85 Self: 'static,
86 C: Mutator<T> + 'static,
87 T: 'static,
88 {
89 let first = self;
90 let second = next.into_fn();
91 BoxMutator::new(move |t| {
92 (first)(t);
93 (second)(t);
94 })
95 }
96}
97
98/// Implements FnMutatorOps for all closure types
99impl<T, F> FnMutatorOps<T> for F where F: Fn(&mut T) {}