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        where
277            $($generics: 'static),*
278        {
279            self
280        }
281
282        // into_fn: consumes self, returns impl Fn/FnMut
283        impl_rc_conversions!(
284            @fn_method_into
285            $call_mode,
286            ($($arg : $arg_ty),*) $(-> $ret)?
287        );
288
289        // to_box: borrows self, clones and returns Box
290        impl_rc_conversions!(
291            @method_to to_box,
292            $rc_type<$($generics),*>, $box_type,
293            $call_mode,
294            ($($arg : $arg_ty),*) $(-> $ret)?
295        );
296
297        // to_rc: borrows self, returns clone (cheap Rc clone)
298        #[inline]
299        fn to_rc(&self) -> $rc_type<$($generics),*>
300        where
301            $($generics: 'static),*
302        {
303            self.clone()
304        }
305
306        // to_fn: borrows self, clones and returns impl Fn/FnMut
307        impl_rc_conversions!(
308            @fn_method_to
309            $call_mode,
310            ($($arg : $arg_ty),*) $(-> $ret)?
311        );
312    };
313
314    // Internal implementation: Generate all methods (with once type)
315    (
316        @impl
317        $rc_type:ident < $($generics:ident),* >,
318        $box_type:ident,
319        $once_type:ident,
320        $call_mode:ident,
321        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
322    ) => {
323        // Generate common methods
324        impl_rc_conversions!(
325            @impl_common
326            $rc_type<$($generics),*>,
327            $box_type,
328            $call_mode,
329            ($($arg : $arg_ty),*) $(-> $ret)?
330        );
331
332        // into_once: consumes self, returns Once
333        impl_rc_conversions!(
334            @method_into into_once,
335            $rc_type<$($generics),*>,
336            $once_type,
337            $call_mode,
338            ($($arg : $arg_ty),*) $(-> $ret)?
339        );
340
341        // to_once: borrows self, clones and returns Once
342        impl_rc_conversions!(
343            @method_to to_once,
344            $rc_type<$($generics),*>,
345            $once_type,
346            $call_mode,
347            ($($arg : $arg_ty),*) $(-> $ret)?
348        );
349    };
350
351    // Internal implementation: Generate methods without once type
352    (
353        @impl_no_once
354        $rc_type:ident < $($generics:ident),* >,
355        $box_type:ident,
356        $call_mode:ident,
357        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
358    ) => {
359        // Generate common methods only
360        impl_rc_conversions!(
361            @impl_common
362            $rc_type<$($generics),*>,
363            $box_type,
364            $call_mode,
365            ($($arg : $arg_ty),*) $(-> $ret)?
366        );
367    };
368
369    // ==================== Public Interface ====================
370
371    // Fn(...) → direct call mode (immutable, no interior mutability) - no once type
372    (
373        $rc_type:ident < $($generics:ident),* >,
374        $box_type:ident,
375        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
376    ) => {
377        impl_rc_conversions!(
378            @impl_no_once
379            $rc_type<$($generics),*>,
380            $box_type,
381            direct,
382            ($($arg : $arg_ty),*) $(-> $ret)?
383        );
384    };
385
386    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - no once type
387    (
388        $rc_type:ident < $($generics:ident),* >,
389        $box_type:ident,
390        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
391    ) => {
392        impl_rc_conversions!(
393            @impl_no_once
394            $rc_type<$($generics),*>,
395            $box_type,
396            borrow_mut,
397            ($($arg : $arg_ty),*) $(-> $ret)?
398        );
399    };
400
401    // Fn(...) → direct call mode (immutable, no interior mutability) - with once type
402    (
403        $rc_type:ident < $($generics:ident),* >,
404        $box_type:ident,
405        $once_type:ident,
406        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
407    ) => {
408        impl_rc_conversions!(
409            @impl
410            $rc_type<$($generics),*>,
411            $box_type,
412            $once_type,
413            direct,
414            ($($arg : $arg_ty),*) $(-> $ret)?
415        );
416    };
417
418    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - with once type
419    (
420        $rc_type:ident < $($generics:ident),* >,
421        $box_type:ident,
422        $once_type:ident,
423        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
424    ) => {
425        impl_rc_conversions!(
426            @impl
427            $rc_type<$($generics),*>,
428            $box_type,
429            $once_type,
430            borrow_mut,
431            ($($arg : $arg_ty),*) $(-> $ret)?
432        );
433    };
434}
435
436pub(crate) use impl_rc_conversions;