1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
mod retained_let;
mod state;

use proc_macro::TokenStream;
use proc_macro2::Span;
use quote::{quote_spanned, ToTokens};
use retained_let::RetainedLetExpander;
use state::{State, StateArg, StateDecl};
use syn::{parse_macro_input, visit_mut::VisitMut, FnArg, Ident, ItemFn};

#[proc_macro_attribute]
pub fn retained(attr: TokenStream, item: TokenStream) -> TokenStream {
    let mut f = parse_macro_input!(item as ItemFn);

    let mut state = State {
        vis: f.vis.clone(),
        decl: parse_macro_input!(attr as StateDecl),
        fields: Vec::new(),
    };

    let state_arg = StateArg {
        name: Ident::new("__inner", Span::mixed_site()),
        decl: state.decl.clone(),
    };

    RetainedLetExpander {
        state_arg: &state_arg,
        fields: &mut state.fields,
    }
    .visit_block_mut(&mut f.block);

    f.sig.inputs.push({
        let s = TokenStream::from(state_arg.to_token_stream());
        parse_macro_input!(s as FnArg)
    });

    TokenStream::from(quote_spanned! { Span::mixed_site() =>
        #state
        #f
    })
}