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