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