capture_it/
lib.rs

1//!
2//! # Modern C++-ish closure macros.
3//!
4//! This crate provides the [`capture`] macro, which implements C++11's lambda-style capture
5//! functionality. It uses only a list of AST-parsable tokens, so it can be automatically
6//! formatted by `rustfmt`.
7//!
8//! most of macro expressions are inspired* from the crate
9//! [`oliver-giersch/closure`](https://github.com/oliver-giersch/closure/blob/master/src/lib.rs)
10//!
11
12#![cfg_attr(all(feature = "no-std", not(test)), no_std)]
13
14///
15/// Generate a closure that captures specified variables, and captures all other unspecified
16/// variables by **move**.
17///
18/// The first argument to the macro is always a list of capture arguments wrapped in [], and you
19/// pass a closure or async block to the second argument, separated by commas. In this case, the
20/// second argument must be explicitly specified as move capture.
21///
22/// # Usage
23///
24/// ### capture by copy
25///
26/// If you specify a variable name in square brackets, the [`Clone::clone`] function is called
27/// against that variable, creating a variable of the same name and capturing it with the specified
28/// closure. (Capturing the variable is always guaranteed, even if you don't explicitly use it
29/// within the block.)
30///
31/// ```rust
32/// let a = 1;
33/// let closure = capture_it::capture!([a], move || { a });
34/// assert_eq!(closure(), 1);
35/// ```
36///
37/// All of these rules, except for reference capture (the & prefix), which we'll discuss later, can
38/// be declared mutable by prefixing the variable name with * (an asterisk).
39///
40/// (NOTE: We originally wanted to use the `mut` keyword prefix, but that would cause `rustfmt` to
41/// consider the macro expression as unjustified rust code and disable formatting, so we were forced
42/// to adopt this unorthodox method)
43///
44/// ```rust
45/// let count = 0;
46/// let mut closure = capture_it::capture!([*count], move || { count += 1; count });
47///
48/// assert_eq!(closure(), 1);
49/// assert_eq!(closure(), 2);
50/// assert_eq!(closure(), 3);
51///
52/// assert_eq!(count, 0); // as it was copied ...
53/// ```
54///
55/// ### capture by reference
56///
57/// You can explicitly reference-capture a variable by prefixing its name with & or &mut. (Note that
58/// all variables not specified in the capture list will be MOVE-captured, as only blocks with a
59/// MOVE policy are allowed as second arguments. Any variables you want to capture by reference must
60/// be explicitly specified in the capture list)
61///
62/// ```rust
63/// let a = std::cell::Cell::new(1);
64/// let closure = capture_it::capture!([&a], move || { a.get() });
65/// a.set(2);
66/// assert_eq!(closure(), 2);
67/// ```
68///
69/// ### capture by alias
70///
71/// Similar to the lambda capture rules in modern C++, it is possible to capture an expression by
72/// giving it an alias.
73///
74/// ```rust
75/// let mut closure = capture_it::capture!([*a = 0], move || { a += 1; a });
76///
77/// assert_eq!(closure(), 1);
78/// assert_eq!(closure(), 2);
79/// assert_eq!(closure(), 3);
80/// ```
81///
82/// ### capture struct fields
83///
84/// Under limited conditions, you can capture struct fields. The following expressions will capture
85/// each struct field as a copy and a reference, respectively.
86///
87/// ```rust
88/// struct Foo {
89///     copied: i32,
90///     borrowed: std::cell::Cell<i32>,
91/// }
92///
93/// let mut foo = Foo { copied: 1, borrowed: 2.into() };
94/// let closure = capture_it::capture!([foo.copied, &foo.borrowed], move || {
95///     copied + borrowed.get()
96/// });
97///
98/// foo.copied = 9999;
99/// foo.borrowed.set(3);
100/// assert_eq!(closure(), 4);
101/// ```
102///
103/// ### async blocks
104///
105/// All rules apply equally to the `async move` block.
106///
107/// ```rust
108/// let mut copied = 1;
109/// let borrowed = std::cell::Cell::new(2);
110/// let task = capture_it::capture!([copied, &borrowed], async move {
111///    copied + borrowed.get()
112/// });
113///
114/// copied = 9999;
115/// borrowed.set(3);
116///
117/// let val = futures::executor::block_on(task);
118/// assert_eq!(val, 4);
119/// ```
120///
121/// ## Shortcuts
122///
123/// There are various shortcuts for capturing variables for convenience.
124///
125/// - `Own`: Call the [`ToOwned::to_owned`] method on the target variable.
126/// - `Weak`: Downgrades a [`std::rc::Rc`] or [`std::sync::Arc`] type to a Weak reference.
127/// - `Some`: Wrap cloned variable with [`Option`]. This is useful when you have to retrieve
128///   captured variable when it's not a [`FnOnce`] closure.
129/// - All paths that do not fall under the above rules (`$($p:ident)::*`) are replaced with function
130///   calls.
131/// - You can simply write single method invocation on the captured variable, to capture the result
132///   of return value. `capture!([foo.bar()], move || { ... })` -> in this case, `let foo =
133///   foo.bar()` will be captured into the closure.
134///
135/// ```rust
136/// #[cfg(not(feature = "no-std"))]
137/// {
138///     use capture_it::capture;
139///
140///     let hello = "hello, world!";
141///     let rc = std::rc::Rc::new(());
142///     let arc = std::sync::Arc::new(());
143///     let arc_2 = arc.clone();
144///     let hello_other = "hello, other!";
145///
146///     let closure = capture!([Own(hello), Weak(rc), Weak(arc), arc_2, *hello_other.to_string()], move || {
147///         assert_eq!(hello, "hello, world!");
148///         assert!(rc.upgrade().is_none());
149///         assert!(arc.upgrade().is_some());
150///         assert_eq!(hello_other, "hello, other!");
151///     });
152///
153///     drop((rc, arc));
154///     closure();
155/// }
156/// ```
157#[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/// Generate a closure that touches all specified variables, which makes all of them to be
172/// captures even if they are not used in the provided closure.
173#[macro_export(local_inner_macros)]
174#[doc(hidden)]
175macro_rules! __wrap_touched {
176    /* --------------------------------------- Parametered -------------------------------------- */
177    ([$($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    /* --------------------------------------- Zero Params -------------------------------------- */
192    ([$($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    /* --------------------------------------- Async Move --------------------------------------- */
207    ([$($args:tt)*] async move {$($content:tt)*}) => {
208        async move {
209            $crate::__touch_all!($($args)*,);
210            $($content)*
211        }
212    };
213}
214
215/// Doesn't require 'move' keyword here.
216#[macro_export(local_inner_macros)]
217#[doc(hidden)]
218macro_rules! __wrap_touched_v2 {
219    /* --------------------------------------- Parametered -------------------------------------- */
220    ([$($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    /* --------------------------------------- Zero Params -------------------------------------- */
235    ([$($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    /* --------------------------------------- Async Move --------------------------------------- */
250    ([$($args:tt)*] async {$($content:tt)*}) => {
251        async move {
252            $crate::__touch_all!($($args)*,);
253            $($content)*
254        }
255    };
256}
257
258/// Enforces the compiler to capture all variables in the closure.
259#[macro_export(local_inner_macros)]
260#[doc(hidden)]
261macro_rules! __touch_all {
262    /* ----------------------------------------- By Copy ---------------------------------------- */
263    ($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    /* -------------------------------------- By Reference -------------------------------------- */
274    (&$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    /* -------------------------------------- By Expression ------------------------------------- */
285    ($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    /* ------------------------------------- Struct By Copy ------------------------------------- */
296    ($($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    /* ----------------------------------- Struct By Reference ---------------------------------- */
307    (&$($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    /* ----------------------------------------- By Ops ----------------------------------------- */
318    ($($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    /* -------------------------------------- By Ops - Ref -------------------------------------- */
339    ($($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    /* ---------------------------------- By Self.* Invocation ---------------------------------- */
360    (*$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    /* ----------------------------------------- Escape ----------------------------------------- */
371    ($(,)*) => {};
372}
373
374#[macro_export(local_inner_macros)]
375#[doc(hidden)]
376macro_rules! __capture {
377    /* ----------------------------------------- By Ops ----------------------------------------- */
378    ($($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    /* ----------------------------------- By Ops - & Prefixed ---------------------------------- */
401    ($($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    /* ---------------------------------- By Self.* Invocation ---------------------------------- */
424    (*$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    /* ----------------------------------------- By Copy ---------------------------------------- */
435    ($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    /* -------------------------------------- By Reference -------------------------------------- */
444    (&$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    /* -------------------------------------- By Expression ------------------------------------- */
453    ($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    /* ------------------------------------- Struct By Copy ------------------------------------- */
464    ($($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    /* ----------------------------------- Struct By Reference ---------------------------------- */
473    (&$($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    /* ----------------------------------------- Escape ----------------------------------------- */
482    ($(,)*) => {};
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    // shamelessly cloned test cases from https://github.com/oliver-giersch/closure/blob/master/src/lib.rs
611    #[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; // to check if rc was correctly copied, not referenced ...
769
770        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}