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