1extern crate proc_macro;
3
4use proc_macro::TokenStream;
5use quote::quote;
6
7#[proc_macro_attribute]
18#[cfg(not(test))] pub 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#[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}