Skip to main content

qubit_function/macros/
rc_conversions.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # Rc Conversions Macro
11//!
12//! Generates common into_xxx() conversion methods for all Rc-based function
13//! wrappers.
14//!
15//! This macro generates the standard conversion methods (`into_box`, `into_rc`,
16//! `into_fn`, `into_once`) for all Rc-based function wrapper types using a
17//! single unified pattern.
18//!
19//! # Author
20//!
21//! Haixing Hu
22
23/// Public interface macro for Rc-based conversions.
24///
25/// This macro automatically infers everything from the function signature:
26/// - Number of parameters
27/// - Parameter types
28/// - Return type
29/// - Call mode (Fn → direct, FnMut → borrow_mut)
30///
31/// # Syntax
32///
33/// ```ignore
34/// // 2-parameter version (no once type, for predicates and similar pure functions)
35/// impl_rc_conversions!(
36///     RcType<Generics>,           // Rc wrapper type with all generic parameters
37///     BoxType,                     // Corresponding Box wrapper type
38///     Fn(args) [-> RetType]        // Fn or FnMut signature (auto-infers everything!)
39/// );
40///
41/// // 3-parameter version (with once type, for consumers, functions, etc.)
42/// impl_rc_conversions!(
43///     RcType<Generics>,           // Rc wrapper type with all generic parameters
44///     BoxType,                     // Corresponding Box wrapper type
45///     OnceType,                    // Corresponding once wrapper type
46///     Fn(args) [-> RetType]        // Fn or FnMut signature (auto-infers everything!)
47/// );
48/// ```
49///
50/// # Generated methods
51///
52/// * `into_box(self) -> BoxType` - Converts to Box-based wrapper
53/// * `into_rc(self) -> RcType` - Converts to Rc-based wrapper
54/// * `into_fn(self) -> impl FnTrait` - Converts to function pointer
55/// * `into_once(self) -> OnceType` - Converts to once wrapper
56/// * `to_box(&self) -> BoxType` - Converts to Box-based wrapper
57/// * `to_rc(&self) -> RcType` - Converts to Rc-based wrapper
58/// * `to_fn(&self) -> impl FnTrait` - Converts to function pointer
59/// * `to_once(&self) -> OnceType` - Converts to once wrapper
60///
61/// # Examples
62///
63/// ```ignore
64/// // Predicate: Fn(&T) -> bool → direct call mode (no once type)
65/// impl_rc_conversions!(RcPredicate<T>, BoxPredicate, Fn(t: &T) -> bool);
66///
67/// // BiPredicate: Fn(&T, &U) -> bool → direct call mode (no once type)
68/// impl_rc_conversions!(RcBiPredicate<T, U>, BoxBiPredicate, Fn(t: &T, u: &U) -> bool);
69///
70/// // Consumer: Fn(&T) → direct call mode (with once type)
71/// impl_rc_conversions!(RcConsumer<T>, BoxConsumer, BoxConsumerOnce, Fn(t: &T));
72///
73/// // StatefulConsumer: FnMut(&T) → borrow_mut call mode (with once type)
74/// impl_rc_conversions!(RcStatefulConsumer<T>, BoxStatefulConsumer, BoxConsumerOnce, FnMut(t: &T));
75///
76/// // BiConsumer: Fn(&T, &U) → direct call mode (with once type)
77/// impl_rc_conversions!(RcBiConsumer<T, U>, BoxBiConsumer, BoxBiConsumerOnce, Fn(t: &T, u: &U));
78///
79/// // Function: Fn(&T) -> R → direct call mode (with once type)
80/// impl_rc_conversions!(RcFunction<T, R>, BoxFunction, BoxFunctionOnce, Fn(t: &T) -> R);
81///
82/// // StatefulFunction: FnMut(&T) -> R → borrow_mut call mode (with once type)
83/// impl_rc_conversions!(RcStatefulFunction<T, R>, BoxStatefulFunction, BoxFunctionOnce, FnMut(t: &T) -> R);
84///
85/// // MutatingFunction: Fn(&mut T) -> R → direct call mode (with once type)
86/// impl_rc_conversions!(RcMutatingFunction<T, R>, BoxMutatingFunction, BoxMutatingFunctionOnce, Fn(input: &mut T) -> R);
87/// ```
88///
89/// # Author
90///
91/// Haixing Hu
92macro_rules! impl_rc_conversions {
93    // ==================== Core Macro: Generate Single Method ====================
94
95    // Helper: Generate a single conversion method (consuming self)
96    (
97        @method_into
98        $method_name:ident,                              // Method name: into_box, into_once
99        $rc_type:ident < $($generics:ident),* >,        // Rc type with generics
100        $target_type:ident,                              // Target type: BoxType or OnceType
101        $call_mode:ident,                                // direct or borrow_mut
102        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?   // Function signature
103    ) => {
104        #[inline]
105        fn $method_name(self) -> $target_type<$($generics),*>
106        where
107            $($generics: 'static),*
108        {
109            $target_type::new_with_optional_name(
110                impl_rc_conversions!(@make_closure $call_mode, self.function, $($arg),*),
111                self.name
112            )
113        }
114    };
115
116    // Helper: Generate a single conversion method (borrowing &self)
117    (
118        @method_to
119        $method_name:ident,                              // Method name: to_box, to_once
120        $rc_type:ident < $($generics:ident),* >,        // Rc type with generics
121        $target_type:ident,                              // Target type: BoxType or OnceType
122        $call_mode:ident,                                // direct or borrow_mut
123        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?   // Function signature
124    ) => {
125        #[inline]
126        fn $method_name(&self) -> $target_type<$($generics),*>
127        where
128            $($generics: 'static),*
129        {
130            let self_fn = self.function.clone();
131            let self_name = self.name.clone();
132            $target_type::new_with_optional_name(
133                impl_rc_conversions!(@make_closure $call_mode, self_fn, $($arg),*),
134                self_name
135            )
136        }
137    };
138
139    // Helper: Generate into_fn method (consuming self, no return type, direct)
140    (
141        @fn_method_into
142        direct,
143        ($($arg:ident : $arg_ty:ty),*)
144    ) => {
145        #[inline]
146        fn into_fn(self) -> impl Fn($($arg_ty),*)
147        {
148            move |$($arg),*| (self.function)($($arg),*)
149        }
150    };
151
152    // Helper: Generate into_fn method (consuming self, with return type, direct)
153    (
154        @fn_method_into
155        direct,
156        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
157    ) => {
158        #[inline]
159        fn into_fn(self) -> impl Fn($($arg_ty),*) -> $ret
160        {
161            move |$($arg),*| (self.function)($($arg),*)
162        }
163    };
164
165    // Helper: Generate into_fn method (consuming self, no return type, borrow_mut)
166    (
167        @fn_method_into
168        borrow_mut,
169        ($($arg:ident : $arg_ty:ty),*)
170    ) => {
171        #[inline]
172        fn into_fn(self) -> impl FnMut($($arg_ty),*)
173        {
174            move |$($arg),*| (self.function.borrow_mut())($($arg),*)
175        }
176    };
177
178    // Helper: Generate into_fn method (consuming self, with return type, borrow_mut)
179    (
180        @fn_method_into
181        borrow_mut,
182        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
183    ) => {
184        #[inline]
185        fn into_fn(self) -> impl FnMut($($arg_ty),*) -> $ret
186        {
187            move |$($arg),*| (self.function.borrow_mut())($($arg),*)
188        }
189    };
190
191    // Helper: Generate to_fn method (borrowing &self, no return type, direct)
192    (
193        @fn_method_to
194        direct,
195        ($($arg:ident : $arg_ty:ty),*)
196    ) => {
197        #[inline]
198        fn to_fn(&self) -> impl Fn($($arg_ty),*)
199        {
200            let self_fn = self.function.clone();
201            move |$($arg),*| (self_fn)($($arg),*)
202        }
203    };
204
205    // Helper: Generate to_fn method (borrowing &self, with return type, direct)
206    (
207        @fn_method_to
208        direct,
209        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
210    ) => {
211        #[inline]
212        fn to_fn(&self) -> impl Fn($($arg_ty),*) -> $ret
213        {
214            let self_fn = self.function.clone();
215            move |$($arg),*| (self_fn)($($arg),*)
216        }
217    };
218
219    // Helper: Generate to_fn method (borrowing &self, no return type, borrow_mut)
220    (
221        @fn_method_to
222        borrow_mut,
223        ($($arg:ident : $arg_ty:ty),*)
224    ) => {
225        #[inline]
226        fn to_fn(&self) -> impl FnMut($($arg_ty),*)
227        {
228            let self_fn = self.function.clone();
229            move |$($arg),*| (self_fn.borrow_mut())($($arg),*)
230        }
231    };
232
233    // Helper: Generate to_fn method (borrowing &self, with return type, borrow_mut)
234    (
235        @fn_method_to
236        borrow_mut,
237        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
238    ) => {
239        #[inline]
240        fn to_fn(&self) -> impl FnMut($($arg_ty),*) -> $ret
241        {
242            let self_fn = self.function.clone();
243            move |$($arg),*| (self_fn.borrow_mut())($($arg),*)
244        }
245    };
246
247    // Helper: Make closure based on call mode
248    (@make_closure direct, $fn_call:expr, $($arg:ident),*) => {
249        move |$($arg),*| ($fn_call)($($arg),*)
250    };
251    (@make_closure borrow_mut, $fn_call:expr, $($arg:ident),*) => {
252        move |$($arg),*| ($fn_call.borrow_mut())($($arg),*)
253    };
254
255    // ==================== Main Implementation ====================
256
257    // Internal implementation: Generate common methods (shared by both variants)
258    (
259        @impl_common
260        $rc_type:ident < $($generics:ident),* >,
261        $box_type:ident,
262        $call_mode:ident,
263        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
264    ) => {
265        // into_box: consumes self, returns Box
266        impl_rc_conversions!(
267            @method_into into_box,
268            $rc_type<$($generics),*>, $box_type,
269            $call_mode,
270            ($($arg : $arg_ty),*) $(-> $ret)?
271        );
272
273        // into_rc: consumes self, returns self (zero-cost)
274        #[inline]
275        fn into_rc(self) -> $rc_type<$($generics),*>
276        {
277            self
278        }
279
280        // into_fn: consumes self, returns impl Fn/FnMut
281        impl_rc_conversions!(
282            @fn_method_into
283            $call_mode,
284            ($($arg : $arg_ty),*) $(-> $ret)?
285        );
286
287        // to_box: borrows self, clones and returns Box
288        impl_rc_conversions!(
289            @method_to to_box,
290            $rc_type<$($generics),*>, $box_type,
291            $call_mode,
292            ($($arg : $arg_ty),*) $(-> $ret)?
293        );
294
295        // to_rc: borrows self, returns clone (cheap Rc clone)
296        #[inline]
297        fn to_rc(&self) -> $rc_type<$($generics),*>
298        {
299            self.clone()
300        }
301
302        // to_fn: borrows self, clones and returns impl Fn/FnMut
303        impl_rc_conversions!(
304            @fn_method_to
305            $call_mode,
306            ($($arg : $arg_ty),*) $(-> $ret)?
307        );
308    };
309
310    // Internal implementation: Generate all methods (with once type)
311    (
312        @impl
313        $rc_type:ident < $($generics:ident),* >,
314        $box_type:ident,
315        $once_type:ident,
316        $call_mode:ident,
317        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
318    ) => {
319        // Generate common methods
320        impl_rc_conversions!(
321            @impl_common
322            $rc_type<$($generics),*>,
323            $box_type,
324            $call_mode,
325            ($($arg : $arg_ty),*) $(-> $ret)?
326        );
327
328        // into_once: consumes self, returns Once
329        impl_rc_conversions!(
330            @method_into into_once,
331            $rc_type<$($generics),*>,
332            $once_type,
333            $call_mode,
334            ($($arg : $arg_ty),*) $(-> $ret)?
335        );
336
337        // to_once: borrows self, clones and returns Once
338        impl_rc_conversions!(
339            @method_to to_once,
340            $rc_type<$($generics),*>,
341            $once_type,
342            $call_mode,
343            ($($arg : $arg_ty),*) $(-> $ret)?
344        );
345    };
346
347    // Internal implementation: Generate methods without once type
348    (
349        @impl_no_once
350        $rc_type:ident < $($generics:ident),* >,
351        $box_type:ident,
352        $call_mode:ident,
353        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
354    ) => {
355        // Generate common methods only
356        impl_rc_conversions!(
357            @impl_common
358            $rc_type<$($generics),*>,
359            $box_type,
360            $call_mode,
361            ($($arg : $arg_ty),*) $(-> $ret)?
362        );
363    };
364
365    // ==================== Public Interface ====================
366
367    // Fn(...) → direct call mode (immutable, no interior mutability) - no once type
368    (
369        $rc_type:ident < $($generics:ident),* >,
370        $box_type:ident,
371        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
372    ) => {
373        impl_rc_conversions!(
374            @impl_no_once
375            $rc_type<$($generics),*>,
376            $box_type,
377            direct,
378            ($($arg : $arg_ty),*) $(-> $ret)?
379        );
380    };
381
382    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - no once type
383    (
384        $rc_type:ident < $($generics:ident),* >,
385        $box_type:ident,
386        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
387    ) => {
388        impl_rc_conversions!(
389            @impl_no_once
390            $rc_type<$($generics),*>,
391            $box_type,
392            borrow_mut,
393            ($($arg : $arg_ty),*) $(-> $ret)?
394        );
395    };
396
397    // Fn(...) → direct call mode (immutable, no interior mutability) - with once type
398    (
399        $rc_type:ident < $($generics:ident),* >,
400        $box_type:ident,
401        $once_type:ident,
402        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
403    ) => {
404        impl_rc_conversions!(
405            @impl
406            $rc_type<$($generics),*>,
407            $box_type,
408            $once_type,
409            direct,
410            ($($arg : $arg_ty),*) $(-> $ret)?
411        );
412    };
413
414    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - with once type
415    (
416        $rc_type:ident < $($generics:ident),* >,
417        $box_type:ident,
418        $once_type:ident,
419        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
420    ) => {
421        impl_rc_conversions!(
422            @impl
423            $rc_type<$($generics),*>,
424            $box_type,
425            $once_type,
426            borrow_mut,
427            ($($arg : $arg_ty),*) $(-> $ret)?
428        );
429    };
430}
431
432pub(crate) use impl_rc_conversions;