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}