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;