requiem_macros/
lib.rs

1//! Macros for use with Tokio
2extern crate proc_macro;
3
4use proc_macro::TokenStream;
5use quote::quote;
6
7/// Marks async function to be executed by actix system.
8///
9/// ## Usage
10///
11/// ```rust
12/// #[actix_rt::main]
13/// async fn main() {
14///     println!("Hello world");
15/// }
16/// ```
17#[proc_macro_attribute]
18#[cfg(not(test))] // Work around for rust-lang/rust#62127
19pub fn main(_: TokenStream, item: TokenStream) -> TokenStream {
20    let mut input = syn::parse_macro_input!(item as syn::ItemFn);
21    let attrs = &input.attrs;
22    let vis = &input.vis;
23    let sig = &mut input.sig;
24    let body = &input.block;
25    let name = &sig.ident;
26
27    if sig.asyncness.is_none() {
28        return syn::Error::new_spanned(sig.fn_token, "only async fn is supported")
29            .to_compile_error()
30            .into();
31    }
32
33    sig.asyncness = None;
34
35    (quote! {
36        #(#attrs)*
37        #vis #sig {
38            actix_rt::System::new(stringify!(#name))
39                .block_on(async move { #body })
40        }
41    })
42    .into()
43}
44
45/// Marks async test function to be executed by actix runtime.
46///
47/// ## Usage
48///
49/// ```no_run
50/// #[actix_rt::test]
51/// async fn my_test() {
52///     assert!(true);
53/// }
54/// ```
55#[proc_macro_attribute]
56pub fn test(_: TokenStream, item: TokenStream) -> TokenStream {
57    let input = syn::parse_macro_input!(item as syn::ItemFn);
58
59    let ret = &input.sig.output;
60    let name = &input.sig.ident;
61    let body = &input.block;
62    let attrs = &input.attrs;
63    let mut has_test_attr = false;
64
65    for attr in attrs {
66        if attr.path.is_ident("test") {
67            has_test_attr = true;
68        }
69    }
70
71    if input.sig.asyncness.is_none() {
72        return syn::Error::new_spanned(
73            input.sig.fn_token,
74            format!("only async fn is supported, {}", input.sig.ident),
75        )
76        .to_compile_error()
77        .into();
78    }
79
80    let result = if has_test_attr {
81        quote! {
82            #(#attrs)*
83            fn #name() #ret {
84                actix_rt::System::new("test")
85                    .block_on(async { #body })
86            }
87        }
88    } else {
89        quote! {
90            #[test]
91            #(#attrs)*
92            fn #name() #ret {
93                actix_rt::System::new("test")
94                    .block_on(async { #body })
95            }
96        }
97    };
98
99    result.into()
100}