captures/
changes.rs

1//! Our macro expands to something vaguely like this:
2//!
3//! ```text
4//! {
5//!     
6//!     let x = x.clone(), // for `mut clone x`
7//!     let y = &mut y, // for `ref mut y`
8//!     let z = &z, // for `mut ref z`
9//!     let w = expr, // for `with w = expr`
10//!
11//!     |old_sig| { // Keep the old closure signature
12//!         let _ = &b; // for `all b`
13//!         old_body // old closure body
14//!     }
15//! }
16//! ```
17
18use proc_macro2::{Ident, Punct, Spacing, TokenStream};
19use quote::{quote, quote_spanned, ToTokens};
20
21use crate::parse::*;
22
23pub struct Changes {
24    pub exterior: TokenStream,
25    pub interior: TokenStream,
26    pub exempt: Vec<Ident>,
27}
28
29impl Changes {
30    pub fn from_input(input: &Input, only: bool) -> Changes {
31        let mut exempt = Vec::new();
32        let mut ext = TokenStream::new();
33        let mut int = TokenStream::new();
34
35        for d in &input.assigned {
36            let mu = &d.mu;
37            let mut int_upvar = d.upvar.clone();
38            if only {
39                make_mixed!(int_upvar);
40            }
41            ext.extend(quote!(let #mu #int_upvar = ));
42            match &d.ty {
43                DirectiveType::Clone(sp) => {
44                    let sp = *sp;
45                    let ext_upvar = &d.upvar;
46                    ext.extend(quote_spanned![sp=> ::core::clone::Clone::clone(&#ext_upvar)]);
47                }
48                DirectiveType::With(expr) => {
49                    (&expr).to_tokens(&mut ext);
50                }
51                DirectiveType::Ref(sp, mu) => {
52                    let mut ref_punc = Punct::new('&', Spacing::Alone);
53                    ref_punc.set_span(*sp);
54                    let ext_upvar = &d.upvar;
55                    ext.extend(quote!(#ref_punc #mu #ext_upvar));
56                }
57            }
58            ext.extend(quote!(;));
59        }
60
61        for d in &input.all {
62            let upvar = &d.upvar;
63            exempt.push(upvar.clone());
64            int.extend(quote!(let _ = &#upvar;));
65        }
66
67        Changes {
68            exterior: ext,
69            interior: int,
70            exempt,
71        }
72    }
73}