Skip to main content

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