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}