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        /// let to_string_reuse = BoxFunction::new(|x: &i32| x.to_string());
241        ///
242        /// // Clone to preserve original
243        /// let composed = double.and_then(to_string);
244        /// assert_eq!(composed.apply(&21), "42");
245        ///
246        /// // Original still usable
247        /// assert_eq!(to_string_reuse.apply(&5), "5");
248        /// ```
249            #[allow(unused_mut)]
250            #[inline]
251            fn and_then<S, F>(mut self, mut after: F) -> $box_type<T, S>
252            where
253                Self: 'static,
254                S: 'static,
255                F: $chained_function_trait<R, S> + 'static,
256                T: 'static,
257                R: 'static,
258            {
259                $box_type::new(move |x| {
260                  let mut r = self(x);
261                  after.apply(&mut r)
262                })
263            }
264
265            /// Creates a conditional function
266            ///
267            /// Returns a function that only executes when a predicate is satisfied.
268            /// You must call `or_else()` to provide an alternative function for when
269            /// the condition is not satisfied.
270            ///
271            /// # Parameters
272            ///
273            /// * `predicate` - The condition to check. **Note: This parameter is passed
274            ///   by value and will transfer ownership.** If you need to preserve the
275            ///   original predicate, clone it first (if it implements `Clone`). Can be:
276            ///   - A closure: `|x: &T| -> bool`
277            ///   - A function pointer: `fn(&T) -> bool`
278            ///   - A `BoxPredicate<T>`
279            ///   - An `RcPredicate<T>`
280            ///   - An `ArcPredicate<T>`
281            ///   - Any type implementing `Predicate<T>`
282            ///
283            /// # Returns
284            ///
285            /// Returns the appropriate conditional function type
286            ///
287            /// # Examples
288            ///
289        /// ## Basic usage with or_else
290        ///
291        /// ```rust
292        /// use qubit_function::{Function, FnFunctionOps};
293        ///
294        /// let double = |x: &i32| x * 2;
295        /// let conditional = double.when(|x: &i32| *x > 0).or_else(|x: &i32| -x);
296        ///
297        /// assert_eq!(conditional.apply(&5), 10);
298        /// assert_eq!(conditional.apply(&-5), 5);
299        /// ```
300            ///
301        /// ## Preserving predicate with clone
302        ///
303        /// ```rust
304        /// use qubit_function::{Function, FnFunctionOps, BoxPredicate};
305        ///
306        /// let double = |x: &i32| x * 2;
307        /// let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
308        ///
309        /// // Clone to preserve original predicate
310        /// let conditional = double.when(is_positive)
311        ///     .or_else(|x: &i32| -x);
312        ///
313        /// assert_eq!(conditional.apply(&5), 10);
314        ///
315        /// // Original predicate still usable
316        /// let still_positive = double.when(|x: &i32| *x > 0)
317        ///     .or_else(|x: &i32| -x);
318        /// assert_eq!(still_positive.apply(&5), 10);
319        /// ```
320            #[inline]
321            fn when<P>(self, predicate: P) -> $conditional_type<T, R>
322            where
323                Self: 'static,
324                P: Predicate<T> + 'static,
325                T: 'static,
326                R: 'static,
327            {
328                $box_type::new(self).when(predicate)
329            }
330        }
331
332        /// Blanket implementation for all closures
333        ///
334        /// Automatically implements the extension trait for any type that
335        /// implements the base function trait.
336        ///
337        /// # Author
338        ///
339        /// Haixing Hu
340        impl<T, R, F> $trait_name<T, R> for F where F: $($fn_signature)+ {}
341    };
342}
343
344pub(crate) use impl_fn_ops_trait;