zng_clone_move/
lib.rs

1#![doc(html_favicon_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo-icon.png")]
2#![doc(html_logo_url = "https://raw.githubusercontent.com/zng-ui/zng/main/examples/image/res/zng-logo.png")]
3//!
4//! Macros for declaring clone-move closures and async blocks.
5//!
6//! # Crate
7//!
8#![doc = include_str!(concat!("../", std::env!("CARGO_PKG_README")))]
9#![warn(unused_extern_crates)]
10#![warn(missing_docs)]
11
12///<span data-del-macro-root></span> Clone move closure.
13///
14/// A common pattern when creating `'static` closures is to capture clones by `move`, this way the closure is `'static`
15/// and the cloned values are still available after creating the closure. This macro facilitates this pattern.
16///
17/// # Examples
18///
19/// In the example `bar` is *clone-moved* into the `'static` closure given to `foo`.
20///
21/// ```
22/// # use zng_clone_move::clmv;
23/// fn foo(mut f: impl FnMut(bool) + 'static) {
24///     f(true);
25/// }
26///
27/// let bar = "Cool!".to_owned();
28/// foo(clmv!(bar, |p| {
29///     if p { println!("cloned: {bar}") }
30/// }));
31///
32/// println!("original: {bar}");
33/// ```
34///
35/// Expands to:
36///
37/// ```
38/// # use zng_clone_move::clmv;
39/// # fn foo(mut f: impl FnMut(bool) + 'static) {
40/// #     f(true);
41/// # }
42/// # let bar = "Cool!".to_owned();
43/// foo({
44///     let bar = bar.clone();
45///     move |p| {
46///         if p { println!("cloned: {bar}") }
47///     }
48/// });
49/// # println!("original: {bar}");
50/// ```
51///
52/// # Other Patterns
53///
54/// Sometimes you want to clone an *inner deref* of the value, or you want the clone to be `mut`, you can annotate the
55/// variables cloned to achieve these effects.
56///
57/// ```
58/// # use zng_clone_move::clmv;
59/// # use std::sync::Arc;
60/// fn foo(mut f: impl FnMut(bool) + 'static) {
61///     f(true);
62/// }
63///
64/// let bar = Arc::new("Cool!".to_string());
65/// foo(clmv!(mut *bar, |p| {
66///     bar.push_str("!");
67///     if p { println!("cloned String not Arc: {bar}") }
68/// }));
69///
70/// println!("original: {bar}");
71/// ```
72///
73/// Expands to:
74///
75/// ```
76/// # use zng_clone_move::clmv;
77/// # use std::sync::Arc;
78/// # fn foo(mut f: impl FnMut(bool) + 'static) {
79/// #     f(true);
80/// # }
81/// # let bar = Arc::new("Cool!".to_string());
82/// foo({
83///     let mut bar = (*bar).clone();
84///     move |p| {
85///         bar.push_str("!");
86///         if p { println!("cloned String not Arc: {bar}") }
87///     }
88/// });
89/// # println!("original: {bar}");
90/// ```
91///
92/// # Async
93///
94/// See [`async_clmv_fn!`] for creating `async` closures or [`async_clmv!`] for creating clone move futures.
95#[macro_export]
96macro_rules! clmv {
97    ($($tt:tt)+) => { $crate::__clmv! { [][][] $($tt)+ } }
98}
99
100#[doc(hidden)]
101#[macro_export]
102macro_rules! __clmv {
103    // match start of mut var
104    ([$($done:tt)*][][] mut $($rest:tt)+) => {
105        $crate::__clmv! {
106            [$($done)*]
107            [mut]
108            []
109            $($rest)+
110        }
111    };
112
113    // match one var deref (*)
114    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] * $($rest:tt)+) => {
115        $crate::__clmv! {
116            [$($done)*]
117            [$($mut)?]
118            [$($deref)* *]
119            $($rest)+
120        }
121    };
122
123    // match end of a variable
124    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] $var:ident, $($rest:tt)+) => {
125        $crate::__clmv! {
126            [
127                $($done)*
128                let $($mut)? $var = ( $($deref)* $var ).clone();
129            ]
130            []
131            []
132            $($rest)+
133        }
134    };
135
136    // match start of closure
137    ([$($done:tt)*][][] | $($rest:tt)+) => {
138        {
139            $($done)*
140            move | $($rest)+
141        }
142    };
143
144    // match start of closure without input
145    ([$($done:tt)*][][] || $($rest:tt)+) => {
146        {
147            $($done)*
148            move || $($rest)+
149        }
150    };
151}
152
153/// <span data-del-macro-root></span> Async clone move block.
154///
155/// This macro is similar to [`clmv!`], but creates a future instead of a closure.
156///
157/// A common pattern when creating `'static` futures is to capture clones by `move`, this way the future is `'static`
158/// and the cloned values are still available after creating the future. This macro facilitates this pattern.
159///
160/// # Examples
161///
162/// In the example `bar` is *clone-moved* into the `'static` future given to `foo`.
163///
164/// ```
165/// # use std::{time::Duration};
166/// # use zng_clone_move::*;
167/// # trait TimeUnits { fn ms(self) -> Duration; }
168/// # impl TimeUnits for u64 { fn ms(self) -> Duration { Duration::from_millis(self) } }
169/// # async fn deadline(_d: Duration) { }
170/// async fn foo(mut f: impl Future<Output=()> + 'static) {
171///     f.await;
172/// }
173///
174/// let bar = "Cool!".to_owned();
175/// foo(async_clmv!(bar, {
176///     deadline(100.ms()).await;
177///     println!("cloned: {bar}")
178/// }));
179///
180/// println!("original: {bar}");
181/// ```
182///
183/// Expands to:
184///
185/// ```
186/// # use std::{time::Duration};
187/// # use zng_clone_move::*;
188/// # async fn foo(mut f: impl Future<Output=()> + 'static) {
189/// #     f.await;
190/// # }
191/// # let bar = "Cool!".to_owned();
192/// # trait TimeUnits { fn ms(self) -> Duration; }
193/// # impl TimeUnits for u64 { fn ms(self) -> Duration { Duration::from_millis(self) } }
194/// # async fn deadline(_d: Duration) { }
195/// foo({
196///     let bar = bar.clone();
197///     async move {
198///         deadline(100.ms()).await;
199///         println!("cloned: {bar}")
200///     }
201/// });
202/// # println!("original: {bar}");
203/// ```
204///
205/// # Other Patterns
206///
207/// Sometimes you want to clone an *inner deref* of the value, or you want the clone to be `mut`, you can annotate the
208/// variables cloned to achieve these effects.
209///
210/// ```
211/// # use std::{sync::Arc};
212/// # use zng_clone_move::*;
213/// async fn foo(mut f: impl Future<Output=()> + 'static) {
214///     f.await;
215/// }
216///
217/// let bar = Arc::new("Cool!".to_string());
218/// foo(async_clmv!(mut *bar, {
219///     bar.push_str("!");
220///     println!("cloned String not Arc: {bar}");
221/// }));
222///
223/// println!("original: {bar}");
224/// ```
225///
226/// Expands to:
227///
228/// ```
229/// # use std::{sync::Arc};
230/// # use zng_clone_move::*;
231/// # async fn foo(mut f: impl Future<Output=()> + 'static) {
232/// #     f.await;
233/// # }
234/// # let bar = Arc::new("Cool!".to_string());
235/// foo({
236///     let mut bar = (*bar).clone();
237///     async move {
238///         bar.push_str("!");
239///         println!("cloned String not Arc: {bar}")
240///     }
241/// });
242/// # println!("original: {bar}");
243/// ```
244#[macro_export]
245macro_rules! async_clmv {
246    ($($tt:tt)+) => {
247        $crate::__async_clmv! { [][][] $($tt)+ }
248    }
249}
250
251#[doc(hidden)]
252#[macro_export]
253macro_rules! __async_clmv {
254    // match start of mut var
255    ([$($done:tt)*][][] mut $($rest:tt)+) => {
256        $crate::__async_clmv! {
257            [$($done)*]
258            [mut]
259            []
260            $($rest)+
261        }
262    };
263
264    // match one var deref (*)
265    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] * $($rest:tt)+) => {
266        $crate::__async_clmv! {
267            [$($done)*]
268            [$($mut)?]
269            [$($deref)* *]
270            $($rest)+
271        }
272    };
273
274    // match end of a variable
275    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] $var:ident, $($rest:tt)+) => {
276        $crate::__async_clmv! {
277            [
278                $($done)*
279                let $($mut)? $var = ( $($deref)* $var ).clone();
280            ]
281            []
282            []
283            $($rest)+
284        }
285    };
286
287    // match block
288    ([$($done:tt)*][][] { $($block:tt)* }) => {
289        {
290            $($done)*
291            async move { $($block)* }
292        }
293    };
294}
295
296///<span data-del-macro-root></span> Async clone move closure.
297///
298/// The macro syntax is exactly the same as [`clmv!`](macro@crate::clmv), but it expands to an *async closure* that
299/// captures a clone of zero or more variables and moves another clone of these variables into the returned future for each call.
300///
301/// # Examples
302///
303/// In the example `bar` is cloned into the closure and then it is cloned again for each future generated by the closure.
304///
305/// ```
306/// # use zng_clone_move::async_clmv_fn;
307/// async fn foo<F: Future<Output=()>, H: FnMut(bool) -> F + 'static>(mut f: H) {
308///     f(true).await;
309/// }
310///
311/// let bar = "Cool!".to_owned();
312/// foo(async_clmv_fn!(bar, |p| {
313///     std::future::ready(()).await;
314///     if p { println!("cloned: {bar}") }
315/// }));
316///
317/// println!("original: {bar}");
318/// ```
319///
320/// Expands to:
321///
322/// ```
323/// # use zng_clone_move::async_clmv_fn;
324/// # async fn foo<F: Future<Output=()>, H: FnMut(bool) -> F + 'static>(mut f: H) {
325/// #     f(true).await;
326/// # }
327/// # let bar = "Cool!".to_owned();
328/// foo({
329///     let bar = bar.clone();
330///     move |p| {
331///         let bar = bar.clone();
332///         async move {
333///             std::future::ready(()).await;
334///             if p { println!("cloned: {bar}") }
335///         }
336///     }
337/// });
338/// # println!("original: {bar}");
339/// ```
340///
341/// Note that this is different from an async closure, it returns `'static` futures that do not borrow the closure.
342///
343/// # Once
344///
345/// See [`async_clmv_fn_once!`] for creating `FnOnce` closures.
346#[macro_export]
347macro_rules! async_clmv_fn {
348    ($($tt:tt)+) => { $crate::__async_clmv_fn! { [{}{}][][] $($tt)+ } }
349}
350
351#[doc(hidden)]
352#[macro_export]
353macro_rules! __async_clmv_fn {
354    // match start of mut var
355    ([$($done:tt)*][][] mut $($rest:tt)+) => {
356        $crate::__async_clmv_fn! {
357            [$($done)*]
358            [mut]
359            []
360            $($rest)+
361        }
362    };
363
364    // match one var deref (*)
365    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] * $($rest:tt)+) => {
366        $crate::__async_clmv_fn! {
367            [$($done)*]
368            [$($mut)?]
369            [$($deref)* *]
370            $($rest)+
371        }
372    };
373
374    // match end of a variable
375    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] $var:ident, $($rest:tt)+) => {
376        $crate::__async_clmv_fn! {
377            @var
378            [$($done)*]
379            [$($mut)?]
380            [$($deref)*]
381            $var,
382            $($rest)+
383        }
384    };
385
386    // include one var
387    (@var [ { $($closure_clones:tt)* }{ $($async_clones:tt)* } ][$($mut:tt)?][$($deref:tt)*] $var:ident, $($rest:tt)+) => {
388        $crate::__async_clmv_fn! {
389            [
390                {
391                    $($closure_clones)*
392                    let $var = ( $($deref)* $var ).clone();
393                }
394                {
395                    $($async_clones)*
396                    let $($mut)? $var = $var.clone();
397                }
398            ]
399            []
400            []
401            $($rest)+
402        }
403    };
404
405    // match start of closure inputs
406    ([$($done:tt)*][][] | $($rest:tt)+) => {
407        $crate::__async_clmv_fn! {
408            @args
409            [$($done)*]
410            []
411            $($rest)+
412        }
413    };
414
415    // match start of closure without input, the closure body is in a block
416    ([ { $($closure_clones:tt)* }{ $($async_clones:tt)* } ][][] || { $($rest:tt)+ }) => {
417        {
418            $($closure_clones)*
419            move || {
420                $($async_clones)*
421                async move {
422                    $($rest)+
423                }
424            }
425        }
426    };
427    // match start of closure without input, the closure body is **not** in a block
428    ([ { $($closure_clones:tt)* }{ $($async_clones:tt)* } ][][] || $($rest:tt)+ ) => {
429        {
430            $($closure_clones)*
431            move || {
432                $($async_clones)*
433                async move {
434                    $($rest)+
435                }
436            }
437        }
438    };
439
440    // match end of closure inputs, the closure body is in a block
441    (@args [ { $($closure_clones:tt)* }{ $($async_clones:tt)* } ] [$($args:tt)*] | { $($rest:tt)+ }) => {
442        {
443            $($closure_clones)*
444            move |$($args)*| {
445                $($async_clones)*
446                async move {
447                    $($rest)+
448                }
449            }
450        }
451    };
452    // match end of closure inputs, the closure body is in a block
453    (@args [ { $($closure_clones:tt)* }{ $($async_clones:tt)* } ] [$($args:tt)*] | $($rest:tt)+) => {
454        {
455            $($closure_clones)*
456            move |$($args)*| {
457                $($async_clones)*
458                async move {
459                    $($rest)+
460                }
461            }
462        }
463    };
464
465    // match a token in closure inputs
466    (@args [$($done:tt)*] [$($args:tt)*] $arg_tt:tt $($rest:tt)+) => {
467        $crate::__async_clmv_fn! {
468            @args
469            [$($done)*]
470            [$($args)* $arg_tt]
471            $($rest)+
472        }
473    };
474}
475
476///<span data-del-macro-root></span> Async clone move closure that can only be called once.
477///
478/// The macro syntax is exactly the same as [`async_clmv_fn!`], but it does not clone variables
479/// again inside the call to move to the returned future. Because it moves the captured variables to the returned `Future`,
480/// the closure can only be `FnOnce`.
481///
482/// # Examples
483///
484/// In the example `bar` is cloned into the closure and then moved to the future generated by the closure.
485///
486/// ```
487/// # use zng_clone_move::async_clmv_fn;
488/// async fn foo<F: Future<Output=()>, H: FnOnce(bool) -> F + 'static>(mut f: H) {
489///     f(true).await;
490/// }
491///
492/// let bar = "Cool!".to_owned();
493/// foo(async_clmv_fn!(bar, |p| {
494///     std::future::ready(()).await;
495///     if p { println!("cloned: {bar}") }
496/// }));
497///
498/// println!("original: {bar}");
499/// ```
500///
501/// Expands to:
502///
503/// ```
504/// # use zng_clone_move::async_clmv_fn;
505/// # async fn foo<F: Future<Output=()>, H: FnOnce(bool) -> F + 'static>(mut f: H) {
506/// #     f(true).await;
507/// # }
508/// # let bar = "Cool!".to_owned();
509/// foo({
510///     let bar = bar.clone();
511///     move |p| async move {
512///         std::future::ready(()).await;
513///         if p { println!("cloned: {bar}") }
514///     }
515/// });
516/// # println!("original: {bar}");
517/// ```
518///
519/// Note that this is different from an async once closure, it is an once closure that returns a future, this is so it is more similar with
520/// [`async_clmv_fn!`], that macro cannot be implemented an async closure.
521///
522/// [`async_clmv_fn!`]: macro@crate::async_clmv_fn
523#[macro_export]
524macro_rules! async_clmv_fn_once {
525    ($($tt:tt)+) => { $crate::__async_clmv_fn_once! { [][][] $($tt)+ } }
526}
527
528#[doc(hidden)]
529#[macro_export]
530macro_rules! __async_clmv_fn_once {
531    // match start of mut var
532    ([$($done:tt)*][][] mut $($rest:tt)+) => {
533        $crate::__async_clmv_fn_once! {
534            [$($done)*]
535            [mut]
536            []
537            $($rest)+
538        }
539    };
540
541    // match one var deref (*)
542    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] * $($rest:tt)+) => {
543        $crate::__async_clmv_fn_once! {
544            [$($done)*]
545            [$($mut)?]
546            [$($deref)* *]
547            $($rest)+
548        }
549    };
550
551    // match end of a variable
552    ([$($done:tt)*][$($mut:tt)?][$($deref:tt)*] $var:ident, $($rest:tt)+) => {
553        $crate::__async_clmv_fn_once! {
554            [
555                $($done)*
556                let $($mut)? $var = ( $($deref)* $var ).clone();
557            ]
558            []
559            []
560            $($rest)+
561        }
562    };
563
564    // match start of closure inputs
565    ([$($done:tt)*][][] | $($rest:tt)+) => {
566        $crate::__async_clmv_fn_once! {
567            @args
568            [$($done)*]
569            []
570            $($rest)+
571        }
572    };
573
574    // match start of closure without input, the closure body is in a block
575    ([$($done:tt)*][][] || { $($rest:tt)+ }) => {
576        {
577            $($done)*
578            move || {
579                async move {
580                    $($rest)+
581                }
582            }
583        }
584    };
585    // match start of closure without input, the closure body is **not** in a block
586    ([$($done:tt)*][][] || $($rest:tt)+ ) => {
587        {
588            $($done)*
589            move || {
590                async move {
591                    $($rest)+
592                }
593            }
594        }
595    };
596
597    // match end of closure inputs, the closure body is in a block
598    (@args [$($done:tt)*] [$($args:tt)*] | { $($rest:tt)+ }) => {
599        {
600            $($done)*
601            move |$($args)*| {
602                async move {
603                    $($rest)+
604                }
605            }
606        }
607    };
608    // match end of closure inputs, the closure body is in a block
609    (@args [$($done:tt)*] [$($args:tt)*] | $($rest:tt)+) => {
610        {
611            $($done)*
612            move |$($args)*| {
613                async move {
614                    $($rest)+
615                }
616            }
617        }
618    };
619
620    // match a token in closure inputs
621    (@args [$($done:tt)*] [$($args:tt)*] $arg_tt:tt $($rest:tt)+) => {
622        $crate::__async_clmv_fn_once! {
623            @args
624            [$($done)*]
625            [$($args)* $arg_tt]
626            $($rest)+
627        }
628    };
629}
630
631#[cfg(test)]
632#[allow(dead_code)]
633#[allow(clippy::ptr_arg)]
634mod async_clmv_fn_tests {
635    // if it build it passes
636
637    use std::{future::ready, sync::Arc};
638
639    fn no_clones_no_input() {
640        let _ = async_clmv_fn!(|| ready(true).await);
641    }
642
643    fn one_clone_no_input(a: &String) {
644        let _ = async_clmv_fn!(a, || {
645            let _: String = a;
646            ready(true).await
647        });
648        let _ = a;
649    }
650
651    fn one_clone_with_derefs_no_input(a: &Arc<String>) {
652        let _ = async_clmv_fn!(**a, || {
653            let _: String = a;
654            ready(true).await
655        });
656        let _ = a;
657    }
658
659    fn two_derefs_no_input(a: &String, b: Arc<String>) {
660        let _ = async_clmv_fn!(a, b, || {
661            let _: String = a;
662            let _: Arc<String> = b;
663            ready(true).await
664        });
665        let _ = (a, b);
666    }
667
668    fn one_input(a: &String) {
669        let _ = async_clmv_fn!(a, |_args: u32| {
670            let _: String = a;
671            ready(true).await
672        });
673        let _ = a;
674    }
675
676    fn two_inputs(a: &String) {
677        let _ = async_clmv_fn!(a, |_b: u32, _c: Box<dyn std::fmt::Debug>| {
678            let _: String = a;
679            ready(true).await
680        });
681        let _ = a;
682    }
683}
684
685#[cfg(test)]
686#[allow(dead_code)]
687#[allow(clippy::ptr_arg)]
688mod async_clmv_fn_once_tests {
689    // if it build it passes
690
691    use std::{future::ready, sync::Arc};
692
693    fn no_clones_no_input() {
694        let _ = async_clmv_fn_once!(|| ready(true).await);
695    }
696
697    fn one_clone_no_input(a: &String) {
698        let _ = async_clmv_fn_once!(a, || {
699            let _: String = a;
700            ready(true).await
701        });
702        let _ = a;
703    }
704
705    fn one_clone_with_derefs_no_input(a: &Arc<String>) {
706        let _ = async_clmv_fn_once!(**a, || {
707            let _: String = a;
708            ready(true).await
709        });
710        let _ = a;
711    }
712
713    fn two_derefs_no_input(a: &String, b: Arc<String>) {
714        let _ = async_clmv_fn_once!(a, b, || {
715            let _: String = a;
716            let _: Arc<String> = b;
717            ready(true).await
718        });
719        let _ = (a, b);
720    }
721
722    fn one_input(a: &String) {
723        let _ = async_clmv_fn_once!(a, |_args: u32| {
724            let _: String = a;
725            ready(true).await
726        });
727        let _ = a;
728    }
729
730    fn two_inputs(a: &String) {
731        let _ = async_clmv_fn_once!(a, |_b: u32, _c: Box<dyn std::fmt::Debug>| {
732            let _: String = a;
733            ready(true).await
734        });
735        let _ = a;
736    }
737}