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;