async_app_macros/
lib.rs

1use proc_macro::{Span, TokenStream};
2use quote::quote;
3use syn::{ext::IdentExt};
4
5#[proc_macro_attribute]
6pub fn main(_args: TokenStream, input: TokenStream) -> TokenStream {
7    let input = syn::parse_macro_input!(input as syn::ItemFn);
8    if input.sig.ident.unraw() != "main" {
9        return syn::Error::new_spanned(
10            input.sig.ident,
11            "Attribute `async_app::main` must be used on `main` function",
12        ).to_compile_error().into();
13    }
14    if input.sig.asyncness.is_none() {
15        return syn::Error::new_spanned(
16            input.sig.ident,
17            "Attribute `async_app::main` must be used on async function",
18        ).to_compile_error().into();
19    }
20    let async_app_crate = syn::Ident::new("async_app", Span::call_site().into());
21    let ret_type = match &input.sig.output {
22        syn::ReturnType::Default => &syn::Type::Tuple(syn::TypeTuple{
23            paren_token: syn::token::Paren::default(),
24            elems: syn::punctuated::Punctuated::new(),
25        }),
26        syn::ReturnType::Type(_, ty) => &**ty,
27    };
28    let name = &input.sig.ident;
29    let output = quote! {
30        fn main() -> #ret_type {
31            #input
32            let scope = #async_app_crate::entryscope();
33            let future = ::std::boxed::Box::pin((#name)(scope));
34            #async_app_crate::entrypoint(future)
35        }
36    };
37    output.into()
38}