rocket_codegen/attribute/entry/
mod.rs

1mod main;
2mod launch;
3mod test;
4
5use devise::{Diagnostic, Spanned, Result};
6use devise::ext::SpanDiagnosticExt;
7use proc_macro2::{TokenStream, Span};
8
9// Common trait implemented by `async` entry generating attributes.
10trait EntryAttr {
11    /// Whether the attribute requires the attributed function to be `async`.
12    const REQUIRES_ASYNC: bool;
13
14    /// Return a new or rewritten function, using block as the main execution.
15    fn function(f: &mut syn::ItemFn) -> Result<TokenStream>;
16}
17
18fn _async_entry<A: EntryAttr>(
19    _args: proc_macro::TokenStream,
20    input: proc_macro::TokenStream
21) -> Result<TokenStream> {
22    let mut function: syn::ItemFn = syn::parse(input)
23        .map_err(Diagnostic::from)
24        .map_err(|d| d.help("attribute can only be applied to functions"))?;
25
26    if A::REQUIRES_ASYNC && function.sig.asyncness.is_none() {
27        return Err(Span::call_site()
28            .error("attribute can only be applied to `async` functions")
29            .span_note(function.sig.span(), "this function must be `async`"));
30    }
31
32    if !function.sig.inputs.is_empty() {
33        return Err(Span::call_site()
34            .error("attribute can only be applied to functions without arguments")
35            .span_note(function.sig.span(), "this function must take no arguments"));
36    }
37
38    A::function(&mut function)
39}
40
41macro_rules! async_entry {
42    ($name:ident, $kind:ty, $default:expr) => (
43        pub fn $name(a: proc_macro::TokenStream, i: proc_macro::TokenStream) -> TokenStream {
44            _async_entry::<$kind>(a, i).unwrap_or_else(|d| {
45                let d = d.emit_as_item_tokens();
46                let default = $default;
47                quote!(#d #default)
48            })
49        }
50    )
51}
52
53async_entry!(async_test_attribute, test::Test, quote!());
54async_entry!(main_attribute, main::Main, quote!(fn main() {}));
55async_entry!(launch_attribute, launch::Launch, quote!(fn main() {}));