rocket_codegen/attribute/entry/
mod.rs1mod main;
2mod launch;
3mod test;
4
5use devise::{Diagnostic, Spanned, Result};
6use devise::ext::SpanDiagnosticExt;
7use proc_macro2::{TokenStream, Span};
8
9trait EntryAttr {
11 const REQUIRES_ASYNC: bool;
13
14 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() {}));