prism3_function/macros/
rc_conversions.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism 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        fn $method_name(self) -> $target_type<$($generics),*>
105        where
106            $($generics: 'static),*
107        {
108            $target_type::new_with_optional_name(
109                impl_rc_conversions!(@make_closure $call_mode, self.function, $($arg),*),
110                self.name
111            )
112        }
113    };
114
115    // Helper: Generate a single conversion method (borrowing &self)
116    (
117        @method_to
118        $method_name:ident,                              // Method name: to_box, to_once
119        $rc_type:ident < $($generics:ident),* >,        // Rc type with generics
120        $target_type:ident,                              // Target type: BoxType or OnceType
121        $call_mode:ident,                                // direct or borrow_mut
122        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?   // Function signature
123    ) => {
124        fn $method_name(&self) -> $target_type<$($generics),*>
125        where
126            $($generics: 'static),*
127        {
128            let self_fn = self.function.clone();
129            let self_name = self.name.clone();
130            $target_type::new_with_optional_name(
131                impl_rc_conversions!(@make_closure $call_mode, self_fn, $($arg),*),
132                self_name
133            )
134        }
135    };
136
137    // Helper: Generate into_fn method (consuming self, no return type, direct)
138    (
139        @fn_method_into
140        direct,
141        ($($arg:ident : $arg_ty:ty),*)
142    ) => {
143        fn into_fn(self) -> impl Fn($($arg_ty),*)
144        {
145            move |$($arg),*| (self.function)($($arg),*)
146        }
147    };
148
149    // Helper: Generate into_fn method (consuming self, with return type, direct)
150    (
151        @fn_method_into
152        direct,
153        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
154    ) => {
155        fn into_fn(self) -> impl Fn($($arg_ty),*) -> $ret
156        {
157            move |$($arg),*| (self.function)($($arg),*)
158        }
159    };
160
161    // Helper: Generate into_fn method (consuming self, no return type, borrow_mut)
162    (
163        @fn_method_into
164        borrow_mut,
165        ($($arg:ident : $arg_ty:ty),*)
166    ) => {
167        fn into_fn(self) -> impl FnMut($($arg_ty),*)
168        {
169            move |$($arg),*| (self.function.borrow_mut())($($arg),*)
170        }
171    };
172
173    // Helper: Generate into_fn method (consuming self, with return type, borrow_mut)
174    (
175        @fn_method_into
176        borrow_mut,
177        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
178    ) => {
179        fn into_fn(self) -> impl FnMut($($arg_ty),*) -> $ret
180        {
181            move |$($arg),*| (self.function.borrow_mut())($($arg),*)
182        }
183    };
184
185    // Helper: Generate to_fn method (borrowing &self, no return type, direct)
186    (
187        @fn_method_to
188        direct,
189        ($($arg:ident : $arg_ty:ty),*)
190    ) => {
191        fn to_fn(&self) -> impl Fn($($arg_ty),*)
192        {
193            let self_fn = self.function.clone();
194            move |$($arg),*| (self_fn)($($arg),*)
195        }
196    };
197
198    // Helper: Generate to_fn method (borrowing &self, with return type, direct)
199    (
200        @fn_method_to
201        direct,
202        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
203    ) => {
204        fn to_fn(&self) -> impl Fn($($arg_ty),*) -> $ret
205        {
206            let self_fn = self.function.clone();
207            move |$($arg),*| (self_fn)($($arg),*)
208        }
209    };
210
211    // Helper: Generate to_fn method (borrowing &self, no return type, borrow_mut)
212    (
213        @fn_method_to
214        borrow_mut,
215        ($($arg:ident : $arg_ty:ty),*)
216    ) => {
217        fn to_fn(&self) -> impl FnMut($($arg_ty),*)
218        {
219            let self_fn = self.function.clone();
220            move |$($arg),*| (self_fn.borrow_mut())($($arg),*)
221        }
222    };
223
224    // Helper: Generate to_fn method (borrowing &self, with return type, borrow_mut)
225    (
226        @fn_method_to
227        borrow_mut,
228        ($($arg:ident : $arg_ty:ty),*) -> $ret:ty
229    ) => {
230        fn to_fn(&self) -> impl FnMut($($arg_ty),*) -> $ret
231        {
232            let self_fn = self.function.clone();
233            move |$($arg),*| (self_fn.borrow_mut())($($arg),*)
234        }
235    };
236
237    // Helper: Make closure based on call mode
238    (@make_closure direct, $fn_call:expr, $($arg:ident),*) => {
239        move |$($arg),*| ($fn_call)($($arg),*)
240    };
241    (@make_closure borrow_mut, $fn_call:expr, $($arg:ident),*) => {
242        move |$($arg),*| ($fn_call.borrow_mut())($($arg),*)
243    };
244
245    // ==================== Main Implementation ====================
246
247    // Internal implementation: Generate common methods (shared by both variants)
248    (
249        @impl_common
250        $rc_type:ident < $($generics:ident),* >,
251        $box_type:ident,
252        $call_mode:ident,
253        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
254    ) => {
255        // into_box: consumes self, returns Box
256        impl_rc_conversions!(
257            @method_into into_box,
258            $rc_type<$($generics),*>, $box_type,
259            $call_mode,
260            ($($arg : $arg_ty),*) $(-> $ret)?
261        );
262
263        // into_rc: consumes self, returns self (zero-cost)
264        fn into_rc(self) -> $rc_type<$($generics),*>
265        where
266            $($generics: 'static),*
267        {
268            self
269        }
270
271        // into_fn: consumes self, returns impl Fn/FnMut
272        impl_rc_conversions!(
273            @fn_method_into
274            $call_mode,
275            ($($arg : $arg_ty),*) $(-> $ret)?
276        );
277
278        // to_box: borrows self, clones and returns Box
279        impl_rc_conversions!(
280            @method_to to_box,
281            $rc_type<$($generics),*>, $box_type,
282            $call_mode,
283            ($($arg : $arg_ty),*) $(-> $ret)?
284        );
285
286        // to_rc: borrows self, returns clone (cheap Rc clone)
287        fn to_rc(&self) -> $rc_type<$($generics),*>
288        where
289            $($generics: 'static),*
290        {
291            self.clone()
292        }
293
294        // to_fn: borrows self, clones and returns impl Fn/FnMut
295        impl_rc_conversions!(
296            @fn_method_to
297            $call_mode,
298            ($($arg : $arg_ty),*) $(-> $ret)?
299        );
300    };
301
302    // Internal implementation: Generate all methods (with once type)
303    (
304        @impl
305        $rc_type:ident < $($generics:ident),* >,
306        $box_type:ident,
307        $once_type:ident,
308        $call_mode:ident,
309        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
310    ) => {
311        // Generate common methods
312        impl_rc_conversions!(
313            @impl_common
314            $rc_type<$($generics),*>,
315            $box_type,
316            $call_mode,
317            ($($arg : $arg_ty),*) $(-> $ret)?
318        );
319
320        // into_once: consumes self, returns Once
321        impl_rc_conversions!(
322            @method_into into_once,
323            $rc_type<$($generics),*>,
324            $once_type,
325            $call_mode,
326            ($($arg : $arg_ty),*) $(-> $ret)?
327        );
328
329        // to_once: borrows self, clones and returns Once
330        impl_rc_conversions!(
331            @method_to to_once,
332            $rc_type<$($generics),*>,
333            $once_type,
334            $call_mode,
335            ($($arg : $arg_ty),*) $(-> $ret)?
336        );
337    };
338
339    // Internal implementation: Generate methods without once type
340    (
341        @impl_no_once
342        $rc_type:ident < $($generics:ident),* >,
343        $box_type:ident,
344        $call_mode:ident,
345        ($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
346    ) => {
347        // Generate common methods only
348        impl_rc_conversions!(
349            @impl_common
350            $rc_type<$($generics),*>,
351            $box_type,
352            $call_mode,
353            ($($arg : $arg_ty),*) $(-> $ret)?
354        );
355    };
356
357    // ==================== Public Interface ====================
358
359    // Fn(...) → direct call mode (immutable, no interior mutability) - no once type
360    (
361        $rc_type:ident < $($generics:ident),* >,
362        $box_type:ident,
363        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
364    ) => {
365        impl_rc_conversions!(
366            @impl_no_once
367            $rc_type<$($generics),*>,
368            $box_type,
369            direct,
370            ($($arg : $arg_ty),*) $(-> $ret)?
371        );
372    };
373
374    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - no once type
375    (
376        $rc_type:ident < $($generics:ident),* >,
377        $box_type:ident,
378        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
379    ) => {
380        impl_rc_conversions!(
381            @impl_no_once
382            $rc_type<$($generics),*>,
383            $box_type,
384            borrow_mut,
385            ($($arg : $arg_ty),*) $(-> $ret)?
386        );
387    };
388
389    // Fn(...) → direct call mode (immutable, no interior mutability) - with once type
390    (
391        $rc_type:ident < $($generics:ident),* >,
392        $box_type:ident,
393        $once_type:ident,
394        Fn($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
395    ) => {
396        impl_rc_conversions!(
397            @impl
398            $rc_type<$($generics),*>,
399            $box_type,
400            $once_type,
401            direct,
402            ($($arg : $arg_ty),*) $(-> $ret)?
403        );
404    };
405
406    // FnMut(...) → borrow_mut call mode (mutable, needs RefCell/Mutex) - with once type
407    (
408        $rc_type:ident < $($generics:ident),* >,
409        $box_type:ident,
410        $once_type:ident,
411        FnMut($($arg:ident : $arg_ty:ty),*) $(-> $ret:ty)?
412    ) => {
413        impl_rc_conversions!(
414            @impl
415            $rc_type<$($generics),*>,
416            $box_type,
417            $once_type,
418            borrow_mut,
419            ($($arg : $arg_ty),*) $(-> $ret)?
420        );
421    };
422}
423
424pub(crate) use impl_rc_conversions;