zng_clone_move/
lib.rs

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