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
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//! Procedural macros for `winit-main`.
//!
//! Re-exported by `winit-main` if `winit-main` is compiled with the `proc`
/// feature.

use proc_macro::TokenStream;
use syn::{
    parse_macro_input,
    parse_quote,
};
use quote::quote;


/// Proc-macro around a "simulated main thread" function, which hijacks itself
/// with `winit_main::run` and spawns the function body in a new thread with
/// callbacks to communcate with the main thread. 
///
/// Input:
/// ```rust,compile_fail
/// #[winit_main::main]
/// fn main(event_loop: EventLoopHandle, events: EventReceiver) {
///     // stuff goes here
/// }
/// ```
///
/// Output:
/// ```rust,compile_fail
/// fn main() -> ! {
///     fn _inner(event_loop: EventLoopHandle, events: EventReceiver) {
///         // stuff goes here
///     }
///     ::winit_main::run(_inner)
/// }
/// ```
#[proc_macro_attribute]
pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let item = parse_macro_input!(item as syn::ItemFn);

    let mut inner_fn = item.clone();
    inner_fn.sig.ident = parse_quote! { _inner };

    let outer_fn = syn::ItemFn {
        attrs: item.attrs.clone(),
        vis: item.vis.clone(),
        sig: syn::Signature {
            unsafety: item.sig.unsafety.clone(),
            ident: item.sig.ident.clone(),
            generics: item.sig.generics.clone(),

            constness: None,
            asyncness: None,
            abi: None,
            variadic: None,
            output: parse_quote! { -> ! },

            fn_token: Default::default(),
            paren_token: Default::default(),
            inputs: Default::default(),
        },
        block: Box::new(parse_quote! {
            {
                #inner_fn
                ::winit_main::run(_inner)
            }
        }),
    };

    (quote! { #outer_fn }).into()
}