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}