1#![cfg_attr(all(feature = "no-std", not(test)), no_std)]
13
14#[macro_export]
158macro_rules! capture {
159 ([$($args:tt)*], $($closure:tt)*) => {{
160 $crate::__capture!($($args)*,);
161 $crate::__wrap_touched!([$($args)*] $($closure)*)
162 }};
163
164 ([$($args:tt)*]..$($closure:tt)*) => {{
165 $crate::__capture!($($args)*,);
166 $crate::__wrap_touched_v2!([$($args)*] $($closure)*)
167 }};
168
169}
170
171#[macro_export(local_inner_macros)]
174#[doc(hidden)]
175macro_rules! __wrap_touched {
176 ([$($args:tt)*] move |$($params:tt $(:$param_type:ty)?),*| $expr:expr) => {
178 move |$($params $(:$param_type)?),*| {
179 $crate::__touch_all!($($args)*,);
180 $expr
181 }
182 };
183
184 ([$($args:tt)*] move |$($params:tt $(:$param_type:ty)?),*| -> $rt:ty { $($content:tt)* }) => {
185 move |$($params $(:$param_type)?),*| -> $rt {
186 $crate::__touch_all!($($args)*,);
187 $($content)*
188 }
189 };
190
191 ([$($args:tt)*] move || $content:expr) => {
193 move || {
194 $crate::__touch_all!($($args)*,);
195 $content
196 }
197 };
198
199 ([$($args:tt)*] move || -> $rt:ty { $($content:tt)* }) => {
200 move || -> $rt {
201 $crate::__touch_all!($($args)*,);
202 $($content)*
203 }
204 };
205
206 ([$($args:tt)*] async move {$($content:tt)*}) => {
208 async move {
209 $crate::__touch_all!($($args)*,);
210 $($content)*
211 }
212 };
213}
214
215#[macro_export(local_inner_macros)]
217#[doc(hidden)]
218macro_rules! __wrap_touched_v2 {
219 ([$($args:tt)*] |$($params:tt $(:$param_type:ty)?),*| $expr:expr) => {
221 move |$($params $(:$param_type)?),*| {
222 $crate::__touch_all!($($args)*,);
223 $expr
224 }
225 };
226
227 ([$($args:tt)*] |$($params:tt $(:$param_type:ty)?),*| -> $rt:ty { $($content:tt)* }) => {
228 move |$($params $(:$param_type)?),*| -> $rt {
229 $crate::__touch_all!($($args)*,);
230 $($content)*
231 }
232 };
233
234 ([$($args:tt)*] || $content:expr) => {
236 move || {
237 $crate::__touch_all!($($args)*,);
238 $content
239 }
240 };
241
242 ([$($args:tt)*] || -> $rt:ty { $($content:tt)* }) => {
243 move || -> $rt {
244 $crate::__touch_all!($($args)*,);
245 $($content)*
246 }
247 };
248
249 ([$($args:tt)*] async {$($content:tt)*}) => {
251 async move {
252 $crate::__touch_all!($($args)*,);
253 $($content)*
254 }
255 };
256}
257
258#[macro_export(local_inner_macros)]
260#[doc(hidden)]
261macro_rules! __touch_all {
262 ($v:ident, $($tail:tt)*) => {
264 let _ = &$v;
265 $crate::__touch_all!($($tail)*);
266 };
267
268 (* $v:ident, $($tail:tt)*) => {
269 let _ = &$v;
270 $crate::__touch_all!($($tail)*);
271 };
272
273 (&$v:ident, $($tail:tt)*) => {
275 let _ = &$v;
276 $crate::__touch_all!($($tail)*);
277 };
278
279 (&mut $v:ident, $($tail:tt)*) => {
280 let _ = &$v;
281 $crate::__touch_all!($($tail)*);
282 };
283
284 ($a:ident=$_:expr, $($tail:tt)*) => {
286 let _ = &$a;
287 $crate::__touch_all!($($tail)*);
288 };
289
290 (* $a:ident=$_:expr, $($tail:tt)*) => {
291 let _ = &$a;
292 $crate::__touch_all!($($tail)*);
293 };
294
295 ($($ids:ident).+, $($tail:tt)*) => {
297 let _ = &$crate::__last_tok!($($ids).+);
298 $crate::__touch_all!($($tail)*);
299 };
300
301 (* $($ids:ident).+, $($tail:tt)*) => {
302 let _ = &$crate::__last_tok!($($ids).+);
303 $crate::__touch_all!($($tail)*);
304 };
305
306 (&$($ids:ident).+, $($tail:tt)*) => {
308 let _ = &$crate::__last_tok!($($ids).+);
309 $crate::__touch_all!($($tail)*);
310 };
311
312 (&mut $($ids:ident).+, $($tail:tt)*) => {
313 let _ = $crate::__last_tok!($($ids).+);
314 $crate::__touch_all!($($tail)*);
315 };
316
317 ($($ops:ident)::* ($v:ident), $($tail:tt)*) => {
319 let _ = &$v;
320 $crate::__touch_all!($($tail)*);
321 };
322
323 (*$($ops:ident)::* ($v:ident), $($tail:tt)*) => {
324 let _ = &$v;
325 $crate::__touch_all!($($tail)*);
326 };
327
328 ($($ops:ident)::* ($($ids:ident).+), $($tail:tt)*) => {
329 let _ = &$crate::__last_tok!($($ids).+);
330 $crate::__touch_all!($($tail)*);
331 };
332
333 (*$($ops:ident)::* ($($ids:ident).+), $($tail:tt)*) => {
334 let _ = &$crate::__last_tok!($($ids).+);
335 $crate::__touch_all!($($tail)*);
336 };
337
338 ($($ops:ident)::* (&$v:ident), $($tail:tt)*) => {
340 let _ = &$v;
341 $crate::__touch_all!($($tail)*);
342 };
343
344 (*$($ops:ident)::* (&$v:ident), $($tail:tt)*) => {
345 let _ = &$v;
346 $crate::__touch_all!($($tail)*);
347 };
348
349 ($($ops:ident)::* (&$($ids:ident).+), $($tail:tt)*) => {
350 let _ = &$crate::__last_tok!($($ids).+);
351 $crate::__touch_all!($($tail)*);
352 };
353
354 (*$($ops:ident)::* (&$($ids:ident).+), $($tail:tt)*) => {
355 let _ = &$crate::__last_tok!($($ids).+);
356 $crate::__touch_all!($($tail)*);
357 };
358
359 (*$v:ident.$expr:ident($($args:expr),*), $($tail:tt)*) => {
361 let _ = &$v;
362 $crate::__touch_all!($($tail)*);
363 };
364
365 ($v:ident.$expr:ident($($args:expr),*), $($tail:tt)*) => {
366 let _ = &$v;
367 $crate::__touch_all!($($tail)*);
368 };
369
370 ($(,)*) => {};
372}
373
374#[macro_export(local_inner_macros)]
375#[doc(hidden)]
376macro_rules! __capture {
377 ($($ops:ident)::* ($v:ident), $($tail:tt)*) => {
379 let $v = $crate::__apply_ops!($($ops)::*, $v);
380 $crate::__capture!($($tail)*);
381 };
382
383 (*$($ops:ident)::* ($v:ident), $($tail:tt)*) => {
384 let mut $v = $crate::__apply_ops!($($ops)::*, $v);
385 $crate::__capture!($($tail)*);
386 };
387
388 ($($ops:ident)::* ($($ids:ident).+), $($tail:tt)*) => {
389 let __capture_it = $crate::__apply_ops!($($ops)::*, $($ids).+);
390 let $crate::__last_tok!($($ids).+) = __capture_it;
391 $crate::__capture!($($tail)*);
392 };
393
394 (*$($ops:ident)::* ($($ids:ident).+), $($tail:tt)*) => {
395 let __capture_it = $crate::__apply_ops!($($ops)::*, $($ids).+);
396 let $crate::__last_tok_mut!($($ids).+) = __capture_it;
397 $crate::__capture!($($tail)*);
398 };
399
400 ($($ops:ident)::* (&$v:ident), $($tail:tt)*) => {
402 let $v = $crate::__apply_ops!($($ops)::*, &$v);
403 $crate::__capture!($($tail)*);
404 };
405
406 (*$($ops:ident)::* (&$v:ident), $($tail:tt)*) => {
407 let mut $v = $crate::__apply_ops!($($ops)::*, &$v);
408 $crate::__capture!($($tail)*);
409 };
410
411 ($($ops:ident)::* (&$($ids:ident).+), $($tail:tt)*) => {
412 let __capture_it = $crate::__apply_ops!($($ops)::*, &$($ids).+);
413 let $crate::__last_tok!($($ids).+) = __capture_it;
414 $crate::__capture!($($tail)*);
415 };
416
417 (*$($ops:ident)::* (&$($ids:ident).+), $($tail:tt)*) => {
418 let __capture_it = $crate::__apply_ops!($($ops)::*, &$($ids).+);
419 let $crate::__last_tok_mut!($($ids).+) = __capture_it;
420 $crate::__capture!($($tail)*);
421 };
422
423 (*$v:ident.$expr:ident($($args:expr),*), $($tail:tt)*) => {
425 let mut $v = $v.$expr($($args),*);
426 $crate::__capture!($($tail)*);
427 };
428
429 ($v:ident.$expr:ident($($args:expr),*), $($tail:tt)*) => {
430 let $v = $v.$expr($($args),*);
431 $crate::__capture!($($tail)*);
432 };
433
434 ($v:ident, $($tail:tt)*) => {
436 $crate::__capture!(Clone::clone(&$v), $($tail)*);
437 };
438
439 (* $v:ident, $($tail:tt)*) => {
440 $crate::__capture!(*Clone::clone(&$v), $($tail)*);
441 };
442
443 (&$v:ident, $($tail:tt)*) => {
445 $crate::__capture!(__Built_In::refer($v), $($tail)*);
446 };
447
448 (&mut $v:ident, $($tail:tt)*) => {
449 $crate::__capture!(__Built_In::refer_mut($v), $($tail)*);
450 };
451
452 ($a:ident=$v:expr, $($tail:tt)*) => {
454 let $a = $v;
455 $crate::__capture!($($tail)*);
456 };
457
458 (* $a:ident=$v:expr, $($tail:tt)*) => {
459 let mut $a = $v;
460 $crate::__capture!($($tail)*);
461 };
462
463 ($($ids:ident).+, $($tail:tt)*) => {
465 $crate::__capture!(Clone::clone(&$($ids).+), $($tail)*);
466 };
467
468 (* $($ids:ident).+, $($tail:tt)*) => {
469 $crate::__capture!(*Clone::clone(&$($ids).+), $($tail)*);
470 };
471
472 (&$($ids:ident).+, $($tail:tt)*) => {
474 $crate::__capture!(__Built_In::refer($($ids).+), $($tail)*);
475 };
476
477 (&mut $($ids:ident).+, $($tail:tt)*) => {
478 $crate::__capture!(__Built_In::refer_mut($($ids).+), $($tail)*);
479 };
480
481 ($(,)*) => {};
483}
484
485#[macro_export(local_inner_macros)]
486#[doc(hidden)]
487macro_rules! __apply_ops {
488 (Own, $($v:tt)*) => {
489 ($($v)*).to_owned()
490 };
491
492 (Weak, $($v:tt)*) => {
493 $crate::__sync_help::Downgrade::downgrade(&$($v)*)
494 };
495
496 (Some, $($v:tt)*) => {
497 Some(Clone::clone(&$($v)*))
498 };
499
500 (__Built_In::refer, $($v:tt)*) => {
501 &$($v)*
502 };
503
504 (__Built_In::refer_mut, $($v:tt)*) => {
505 &mut $($v)*
506 };
507
508 ($($ops:ident)::*, $($v:tt)*) => {
509 ($($ops)::*)($($v)*)
510 };
511
512 ($($ops:ident)::*, &$($v:tt)*) => {
513 ($($ops)::*)(&$($v)*)
514 };
515}
516
517#[macro_export(local_inner_macros)]
518#[doc(hidden)]
519macro_rules! __last_tok {
520 ($a:ident) => { $a };
521 ($a:ident. $($tail:tt)*) => { $crate::__last_tok!($($tail)*) };
522 () => { compile_error!("??") };
523}
524
525#[macro_export(local_inner_macros)]
526#[doc(hidden)]
527macro_rules! __last_tok_mut {
528 ($a:ident) => { mut $a };
529 ($a:ident. $($tail:tt)*) => { $crate::__last_tok_mut!($($tail)*) };
530 () => { compile_error!("??") };
531}
532
533#[cfg(not(feature = "no-std"))]
534pub mod __sync_help {
535 pub trait Downgrade {
536 type Weak;
537
538 fn downgrade(&self) -> Self::Weak;
539 }
540
541 impl<T> Downgrade for std::rc::Rc<T> {
542 type Weak = std::rc::Weak<T>;
543
544 fn downgrade(&self) -> Self::Weak {
545 std::rc::Rc::downgrade(self)
546 }
547 }
548
549 impl<T> Downgrade for std::sync::Arc<T> {
550 type Weak = std::sync::Weak<T>;
551
552 fn downgrade(&self) -> Self::Weak {
553 std::sync::Arc::downgrade(self)
554 }
555 }
556}
557
558#[cfg(test)]
559mod test {
560 use std::{cell::Cell, rc::Rc};
561
562 struct Foo {
563 inner: Rc<()>,
564 inner_mut: Rc<()>,
565 }
566
567 #[test]
568 fn can_compile() {
569 let ss = Rc::new(());
570 let [foo, bar, baz, mut qux] = std::array::from_fn(|_| ss.clone());
571 let ss_2 = ss.clone();
572 let strt = Foo { inner: ss.clone(), inner_mut: ss.clone() };
573
574 drop(ss);
575
576 let _ = capture!(
577 [
578 foo,
579 *bar,
580 &baz,
581 &mut qux,
582 cloned = bar.clone(),
583 *other = cloned.clone(),
584 oar = 3,
585 ss_2.clone(),
586 strt.inner,
587 *strt.inner_mut,
588 ],
589 move || {
590 drop((other, inner_mut, bar));
591
592 bar = Default::default();
593 other = Default::default();
594 inner_mut = Default::default();
595
596 drop((foo, bar, baz, qux, cloned, inner, other, inner_mut));
597 }
598 );
599
600 #[derive(Default)]
601 struct Foo2 {
602 va: usize,
603 }
604
605 assert!(capture!([], move || Foo2 { va: 5 })().va == 5);
606 assert!(capture!([va = 5], move || Foo2 { va })().va == 5);
607 assert!(capture!([], move || Foo2::default())().va == 0);
608 }
609
610 #[test]
612 fn no_capture_one_line() {
613 let closure = capture!([], move || 5 * 5);
614 assert_eq!(closure(), 25);
615 }
616
617 #[test]
618 fn no_capture_with_arg() {
619 let closure = capture!([], move |x| x * x);
620 assert_eq!(closure(5), 25);
621 }
622
623 #[test]
624 fn no_capture_with_arg_and_type_hint() {
625 let closure = capture!([], move |x: usize| x * x);
626 assert_eq!(closure(5), 25);
627 }
628
629 #[test]
630 fn no_capture_with_arg_and_return_type() {
631 let closure = capture!([], move |x: usize| -> usize { x * x });
632 assert_eq!(closure(5), 25);
633 }
634
635 #[test]
636 fn no_capture_with_return_type() {
637 let closure = capture!([], move || -> &str { "result" });
638 assert_eq!(closure(), "result");
639 }
640
641 #[test]
642 fn capture_by_move() {
643 let string = "move".to_string();
644 let closure = capture!([], move || string.len());
645 assert_eq!(closure(), 4);
646 }
647
648 #[test]
649 fn capture_by_ref() {
650 let var = -1;
651 let closure = capture!([&var], move || *var == -1);
652 assert!(closure());
653 }
654
655 #[test]
656 fn capture_by_own() {
657 let my_str = "move";
658 let other_str = "move_2";
659 let str = "move_3";
660 let char_get = "hello";
661
662 let closure = capture!(
663 [
664 ot = my_str,
665 *Own(my_str),
666 other_str.to_owned(),
667 char_get.ends_with("llo"),
668 String::from(str)
669 ],
670 move || {
671 assert!(char_get);
672
673 my_str.push_str(" back");
674 my_str
675 }
676 );
677
678 assert_eq!(closure(), "move back");
679 }
680
681 #[test]
682 fn capture_by_misc_extension() {
683 let var = -1;
684 let other_str = "hello, world!".to_owned();
685
686 let closure = capture!([&var, Some(other_str)], move || other_str.unwrap() + " go away!");
687
688 assert!(closure() == "hello, world! go away!");
689 }
690
691 #[cfg(not(feature = "no-std"))]
692 #[test]
693 fn capture_by_downgrade() {
694 let arc = std::sync::Arc::new("hell, world!");
695 let rc = std::rc::Rc::new("hell, world!");
696 let ww = std::rc::Rc::downgrade(&rc);
697
698 let closure = capture!([Weak(arc), Weak(rc), ww.upgrade()], move || {
699 drop(ww);
700 (arc.upgrade().is_some(), rc.upgrade().is_some())
701 });
702
703 drop(arc);
704 assert_eq!(closure(), (false, true));
705 }
706
707 #[test]
708 fn capture_by_own_struct() {
709 struct PewPew {
710 inner: &'static str,
711 }
712
713 let my_pewpew = PewPew { inner: "move" };
714 let closure = capture!([*Own(my_pewpew.inner), _r = 3], move || {
715 inner.push_str(" back");
716 inner
717 });
718
719 assert_eq!(closure(), "move back");
720 }
721
722 #[test]
723 fn capture_by_ref_mut() {
724 let mut var = -1;
725 capture!([&mut var], move || *var *= -1)();
726 assert_eq!(var, 1);
727 }
728
729 #[test]
730 fn capture_multiple_mixed() {
731 let borrow = 1;
732 let mut borrow_mut = 1;
733 let string = "move".to_string();
734
735 let closure = capture!([&borrow, &mut borrow_mut, *string], move || {
736 assert_eq!(*borrow, 1);
737 *borrow_mut -= 1;
738 string.push_str("d back");
739 string
740 });
741
742 assert_eq!(&closure(), "moved back");
743 assert_eq!(&string, "move");
744 }
745
746 #[test]
747 fn capture_by_clone() {
748 let rc = Rc::new(0);
749 let closure = capture!([rc, _unused_but_captured = rc.clone()], move |expected| -> bool {
750 assert_eq!(Rc::strong_count(&rc), 3);
751 *rc == expected
752 });
753 assert!(closure(0));
754 }
755
756 #[test]
757 fn async_closure() {
758 let rc = Rc::new(Cell::new(0));
759 let mut borrowed = 1;
760 let copied = 2;
761 let task = capture!([rc, copied, &mut borrowed], async move {
762 assert!(rc.get() == 2);
763 rc.set(1);
764 *borrowed = 2;
765 });
766
767 rc.set(2);
768 let rc = rc; futures::executor::block_on(task);
771 assert!(rc.get() == 1);
772 assert!(borrowed == 2);
773 assert!(copied == 2);
774 }
775
776 #[test]
777 fn struct_field() {
778 struct Bar {
779 borrowed: i32,
780 copied: i32,
781 }
782
783 let mut val = Bar { borrowed: 1, copied: 2 };
784
785 let mut closure = capture!([&mut val.borrowed, val.copied], move || {
786 assert_eq!(*borrowed, 1);
787 assert_eq!(copied, 2);
788
789 *borrowed = 3;
790 });
791
792 closure();
793 assert_eq!(val.borrowed, 3);
794 assert_eq!(val.copied, 2);
795 }
796
797 #[test]
798 #[allow(unused_must_use)]
799 #[allow(unused_unsafe)]
800 fn test_compilation() {
801 let val = 1;
802 let val2 = 2;
803
804 use capture as c_;
805
806 c_!([val, val2], move || val + val2);
807 c_!([val, val2]..|| val + val2);
808
809 c_!([val, val2], move |_: i32| val + val2);
810 c_!([val, val2]..|_: i32| val + val2);
811
812 c_!([val, val2], move |_: i32| -> i32 { val + val2 });
813 c_!([val, val2]..|_: i32| -> i32 { val + val2 });
814
815 c_!([val, val2], move || -> i32 { val + val2 });
816 c_!([val, val2]..|| -> i32 { val + val2 });
817
818 c_!([val, val2], move || async move { val + val2 });
819 c_!([val, val2]..|| async move { val + val2 });
820
821 c_!([val, val2], move || async {});
822 c_!([val, val2]..|| async {});
823
824 c_!([val, val2], async move {});
825 c_!([val, val2]..async {});
826
827 c_!([]..async { val });
828 assert!(3 == capture!([val, val2], move || val + val2)());
829 assert!(3 == c_!([val, val2]..|| val + val2)());
830 assert!(3 == c_!([val, val2]..|| unsafe { val + val2 })());
831 assert!(3 == c_!([val, val2]..|| return val + val2)());
832 assert!(
833 c_!([val, val2]..|| {
834 return val + val2;
835 })() == 3
836 );
837 c_!([val, val2], async move {});
838 c_!([val, val2], move |_: i32, _x| unsafe { core::mem::zeroed::<i32>() })(1, 2);
839
840 struct MyType(i32, i32);
841 c_!([val, val2], move |_: i32, _: i32| MyType(1, 22));
842
843 struct MyType2 {
844 _a: i32,
845 _b: i32,
846 }
847 capture!([val, val2], move |_: i32, _: i32| MyType2 { _a: 1, _b: 22 });
848 }
849}