Skip to main content

qubit_function/functions/macros/
fn_ops_trait.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Fn Ops Trait Macro
10//!
11//! Generate extension traits and implementations for closure types
12//!
13//! This macro generates extension traits for closure types that implement
14//! `Fn` or `FnMut`, providing `and_then` and `when` methods without requiring
15//! explicit wrapping as `BoxFunction`, `RcFunction`, or `ArcFunction`.
16//!
17//! # Parameters
18//!
19//! * `$fn_signature` - Closure signature (in parentheses, without constraints)
20//!   Examples: `(Fn(&T) -> R)`, `(FnMut(&T) -> R)`, `(FnMut(&mut T) -> R)`
21//! * `$trait_name` - Name of the extension trait (e.g., `FnFunctionOps`,
22//!   `FnStatefulFunctionOps`)
23//! * `$box_type` - Box wrapper type (e.g., `BoxFunction`, `BoxStatefulFunction`)
24//! * `$chained_function_trait` - The name of the function trait that chained
25//!   after the execution of this function (e.g., Function, BiFunction)
26//! * `$conditional_type` - Conditional function type (e.g., `BoxConditionalFunction`)
27//!
28//! # Implementation Notes
29//!
30//! The macro uses mutable references (`&mut`) uniformly because in Rust,
31//! `&mut T` can be automatically dereferenced to `&T`. This allows both `Fn`
32//! and `FnMut` closures to use the same implementation logic, simplifying
33//! the code and improving performance (avoiding additional boxing operations).
34//!
35//! # Usage Examples
36//!
37//! ```ignore
38//! // Generate extension trait for Fn(&T) -> R
39//! impl_fn_ops_trait!(
40//!     (Fn(&T) -> R),
41//!     FnFunctionOps,
42//!     BoxFunction,
43//!     Function,
44//!     BoxConditionalFunction
45//! );
46//!
47//! // Generate extension trait for FnMut(&T) -> R
48//! impl_fn_ops_trait!(
49//!     (FnMut(&T) -> R),
50//!     FnStatefulFunctionOps,
51//!     BoxStatefulFunction,
52//!     StatefulFunction,
53//!     BoxConditionalStatefulFunction
54//! );
55//!
56//! // Generate extension trait for FnMut(&mut T) -> R (consuming functions)
57//! impl_fn_ops_trait!(
58//!     (FnMut(&mut T) -> R),
59//!     FnMutatingFunctionOps,
60//!     BoxMutatingFunction,
61//!     MutatingFunction,
62//!     BoxConditionalMutatingFunction
63//! );
64//! ```
65//!
66//! # Author
67//!
68//! Haixing Hu
69
70/// Generate extension traits and implementations for closure types
71///
72/// This macro generates an extension trait that provides composition methods
73/// (`and_then`, `when`) for closures implementing the specified
74/// closure trait, without requiring explicit wrapping.
75///
76/// # Unified Implementation Strategy
77///
78/// The macro uses a unified implementation approach, passing intermediate
79/// results using mutable references (`&mut`). This is because:
80/// 1. In Rust, `&mut T` can be automatically dereferenced to `&T`
81/// 2. Avoids code duplication and simplifies the macro implementation
82/// 3. Better performance by avoiding additional boxing operations
83/// 4. Uses `#[allow(unused_mut)]` to suppress unnecessary mutability warnings
84///
85/// # Parameters
86///
87/// * `$fn_signature` - Closure signature (in parentheses, without constraints)
88/// * `$trait_name` - Name of the extension trait
89/// * `$box_type` - Box wrapper type
90/// * `$chained_function_trait` - The name of the function trait that chained
91///   after the execution of this function (e.g., Function, BiFunction)
92/// * `$conditional_type` - Conditional function type
93///
94/// # Generated Code
95///
96/// Generates a trait definition and a blanket implementation, containing:
97/// - `and_then<S, F>` - Chain composition method
98/// - `when<P>` - Conditional execution method
99///
100/// # Examples
101///
102/// ```ignore
103/// // Fn(&T) -> R version
104/// impl_fn_ops_trait!(
105///     (Fn(&T) -> R),
106///     FnFunctionOps,
107///     BoxFunction,
108///     Function,
109///     BoxConditionalFunction
110/// );
111///
112/// // FnMut(&T) -> R version
113/// impl_fn_ops_trait!(
114///     (FnMut(&T) -> R),
115///     FnStatefulFunctionOps,
116///     BoxStatefulFunction,
117///     StatefulFunction,
118///     BoxConditionalStatefulFunction
119/// );
120///
121/// // FnMut(&mut T) -> R version (consuming functions)
122/// impl_fn_ops_trait!(
123///     (FnMut(&mut T) -> R),
124///     FnMutatingFunctionOps,
125///     BoxMutatingFunction,
126///     MutatingFunction,
127///     BoxConditionalMutatingFunction
128/// );
129/// ```
130///
131/// # Author
132///
133/// Haixing Hu
134#[macro_export]
135macro_rules! impl_fn_ops_trait {
136    // Unified implementation - accepts closure signature (without constraints)
137    (
138        ($($fn_signature:tt)+),
139        $trait_name:ident,
140        $box_type:ident,
141        $chained_function_trait:ident,
142        $conditional_type:ident
143    ) => {
144        /// Extension trait for closures implementing the base function trait
145        ///
146        /// Provides composition methods (`and_then`, `when`) for closures
147        /// and function pointers without requiring explicit wrapping.
148        ///
149        /// This trait is automatically implemented for all closures and function
150        /// pointers that implement the base function trait.
151        ///
152        /// # Design Rationale
153        ///
154        /// While closures automatically implement the base function trait through blanket
155        /// implementation, they don't have access to instance methods like `and_then`,
156        /// and `when`. This extension trait provides those methods,
157        /// returning the appropriate Box-based function type for maximum flexibility.
158        ///
159        /// # Examples
160        ///
161        /// ## Chain composition with and_then
162        ///
163        /// ```rust
164        /// use qubit_function::{Function, FnFunctionOps};
165        ///
166        /// let double = |x: i32| x * 2;
167        /// let to_string = |x: i32| x.to_string();
168        ///
169        /// let composed = double.and_then(to_string);
170        /// assert_eq!(composed.apply(21), "42");
171        /// ```
172        ///
173        /// ## Conditional transformation with when
174        ///
175        /// ```rust
176        /// use qubit_function::{Function, FnFunctionOps};
177        ///
178        /// let double = |x: i32| x * 2;
179        /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
180        ///
181        /// assert_eq!(conditional.apply(5), 10);
182        /// assert_eq!(conditional.apply(-5), 5);
183        /// ```
184        ///
185        /// # Author
186        ///
187        /// Haixing Hu
188        pub trait $trait_name<T, R>: $($fn_signature)+ + Sized {
189            /// Chain composition - applies self first, then after
190            ///
191            /// Creates a new function that applies this function first, then
192            /// applies the after function to the result. Consumes self and returns
193            /// a Box-based function.
194            ///
195            /// # Type Parameters
196            ///
197            /// * `S` - The output type of the after function
198            /// * `F` - The type of the after function (must implement the function trait)
199            ///
200            /// # Parameters
201            ///
202            /// * `after` - The function to apply after self. **Note: This parameter
203            ///   is passed by value and will transfer ownership.** If you need to
204            ///   preserve the original function, clone it first (if it implements
205            ///   `Clone`). Can be:
206            ///   - A closure
207            ///   - A function pointer
208            ///   - A Box-based function
209            ///   - An Rc-based function
210            ///   - An Arc-based function
211            ///   - Any type implementing the function trait
212            ///
213            /// # Returns
214            ///
215            /// A new Box-based function representing the composition
216            ///
217            /// # Examples
218            ///
219            /// ## Direct value passing (ownership transfer)
220            ///
221            /// ```rust
222            /// use qubit_function::{Function, FnFunctionOps, BoxFunction};
223            ///
224            /// let double = |x: i32| x * 2;
225            /// let to_string = BoxFunction::new(|x: i32| x.to_string());
226            ///
227            /// // to_string is moved here
228            /// let composed = double.and_then(to_string);
229            /// assert_eq!(composed.apply(21), "42");
230            /// // to_string.apply(5); // Would not compile - moved
231            /// ```
232            ///
233            /// ## Preserving original with clone
234            ///
235            /// ```rust
236            /// use qubit_function::{Function, FnFunctionOps, BoxFunction};
237            ///
238            /// let double = |x: i32| x * 2;
239            /// let to_string = BoxFunction::new(|x: i32| x.to_string());
240            ///
241            /// // Clone to preserve original
242            /// let composed = double.and_then(to_string.clone());
243            /// assert_eq!(composed.apply(21), "42");
244            ///
245            /// // Original still usable
246            /// assert_eq!(to_string.apply(5), "5");
247            /// ```
248            #[allow(unused_mut)]
249            #[inline]
250            fn and_then<S, F>(mut self, mut after: F) -> $box_type<T, S>
251            where
252                Self: 'static,
253                S: 'static,
254                F: $chained_function_trait<R, S> + 'static,
255                T: 'static,
256                R: 'static,
257            {
258                $box_type::new(move |x| {
259                  let mut r = self(x);
260                  after.apply(&mut r)
261                })
262            }
263
264            /// Creates a conditional function
265            ///
266            /// Returns a function that only executes when a predicate is satisfied.
267            /// You must call `or_else()` to provide an alternative function for when
268            /// the condition is not satisfied.
269            ///
270            /// # Parameters
271            ///
272            /// * `predicate` - The condition to check. **Note: This parameter is passed
273            ///   by value and will transfer ownership.** If you need to preserve the
274            ///   original predicate, clone it first (if it implements `Clone`). Can be:
275            ///   - A closure: `|x: &T| -> bool`
276            ///   - A function pointer: `fn(&T) -> bool`
277            ///   - A `BoxPredicate<T>`
278            ///   - An `RcPredicate<T>`
279            ///   - An `ArcPredicate<T>`
280            ///   - Any type implementing `Predicate<T>`
281            ///
282            /// # Returns
283            ///
284            /// Returns the appropriate conditional function type
285            ///
286            /// # Examples
287            ///
288            /// ## Basic usage with or_else
289            ///
290            /// ```rust
291            /// use qubit_function::{Function, FnFunctionOps};
292            ///
293            /// let double = |x: i32| x * 2;
294            /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: i32| -x);
295            ///
296            /// assert_eq!(conditional.apply(5), 10);
297            /// assert_eq!(conditional.apply(-5), 5);
298            /// ```
299            ///
300            /// ## Preserving predicate with clone
301            ///
302            /// ```rust
303            /// use qubit_function::{Function, FnFunctionOps, BoxPredicate};
304            ///
305            /// let double = |x: i32| x * 2;
306            /// let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
307            ///
308            /// // Clone to preserve original predicate
309            /// let conditional = double.when(is_positive.clone())
310            ///     .or_else(|x: i32| -x);
311            ///
312            /// assert_eq!(conditional.apply(5), 10);
313            ///
314            /// // Original predicate still usable
315            /// assert!(is_positive.test(&3));
316            /// ```
317            #[inline]
318            fn when<P>(self, predicate: P) -> $conditional_type<T, R>
319            where
320                Self: 'static,
321                P: Predicate<T> + 'static,
322                T: 'static,
323                R: 'static,
324            {
325                $box_type::new(self).when(predicate)
326            }
327        }
328
329        /// Blanket implementation for all closures
330        ///
331        /// Automatically implements the extension trait for any type that
332        /// implements the base function trait.
333        ///
334        /// # Author
335        ///
336        /// Haixing Hu
337        impl<T, R, F> $trait_name<T, R> for F where F: $($fn_signature)+ {}
338    };
339}
340
341pub(crate) use impl_fn_ops_trait;