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
//! `#[autumn_web::main]` macro implementation.
//!
//! Generates a synchronous `main()` that builds a tokio runtime and
//! blocks on the user's async body. We generate the runtime manually
//! instead of delegating to `#[tokio::main]` because `tokio::main`
//! emits code with `::tokio::` paths, which don't resolve when the
//! user only depends on `autumn-web`.
use proc_macro2::TokenStream;
use quote::quote;
use syn::ItemFn;
pub fn main_macro(item: TokenStream) -> TokenStream {
let input_fn: ItemFn = match syn::parse2(item) {
Ok(f) => f,
Err(err) => return err.to_compile_error(),
};
if input_fn.sig.asyncness.is_none() {
return syn::Error::new_spanned(input_fn.sig.fn_token, "the main function must be async")
.to_compile_error();
}
let body = &input_fn.block;
let attrs = &input_fn.attrs;
quote! {
#(#attrs)*
fn main() {
// Tell the framework where autumn.toml lives (the app's crate root),
// and whether the *user's* crate was built in debug mode.
// cfg!(debug_assertions) evaluates here — in the user's crate context —
// so it reflects their build mode, not autumn-web's library build mode.
::autumn_web::config::__set_macro_context(
env!("CARGO_MANIFEST_DIR").to_string(),
cfg!(debug_assertions),
);
::autumn_web::reexports::tokio::runtime::Builder::new_multi_thread()
.enable_all()
.build()
.expect("failed to build tokio runtime")
.block_on(async move #body);
}
}
}