1#![forbid(unsafe_code, future_incompatible, rust_2018_idioms)]
2#![deny(missing_debug_implementations, nonstandard_style)]
3#![recursion_limit = "512"]
4
5use proc_macro::TokenStream;
6use quote::{quote, quote_spanned};
7use syn::spanned::Spanned;
8
9#[cfg(not(test))] #[proc_macro_attribute]
21pub fn main(_attr: TokenStream, item: TokenStream) -> TokenStream {
22 let input = syn::parse_macro_input!(item as syn::ItemFn);
23
24 let ret = &input.sig.output;
25 let inputs = &input.sig.inputs;
26 let name = &input.sig.ident;
27 let body = &input.block;
28 let attrs = &input.attrs;
29
30 if name != "main" {
31 return TokenStream::from(quote_spanned! { name.span() =>
32 compile_error!("only the main function can be tagged with #[smol::main]"),
33 });
34 }
35
36 if input.sig.asyncness.is_none() {
37 return TokenStream::from(quote_spanned! { input.span() =>
38 compile_error!("the async keyword is missing from the function declaration"),
39 });
40 }
41
42 let result = quote! {
43 fn main() #ret {
44 #(#attrs)*
45 async fn main(#inputs) #ret {
46 #body
47 }
48
49 smol::run(async {
50 main().await
51 })
52 }
53
54 };
55
56 result.into()
57}
58
59#[proc_macro_attribute]
71pub fn test(_attr: TokenStream, item: TokenStream) -> TokenStream {
72 let input = syn::parse_macro_input!(item as syn::ItemFn);
73
74 let ret = &input.sig.output;
75 let name = &input.sig.ident;
76 let body = &input.block;
77 let attrs = &input.attrs;
78
79 if input.sig.asyncness.is_none() {
80 return TokenStream::from(quote_spanned! { input.span() =>
81 compile_error!("the async keyword is missing from the function declaration"),
82 });
83 }
84
85 let result = quote! {
86 #[test]
87 #(#attrs)*
88 fn #name() #ret {
89 smol::run(async { #body })
90 }
91 };
92
93 result.into()
94}
95
96#[proc_macro_attribute]
110pub fn bench(_attr: TokenStream, item: TokenStream) -> TokenStream {
111 let input = syn::parse_macro_input!(item as syn::ItemFn);
112
113 let ret = &input.sig.output;
114 let args = &input.sig.inputs;
115 let name = &input.sig.ident;
116 let body = &input.block;
117 let attrs = &input.attrs;
118
119 if input.sig.asyncness.is_none() {
120 return TokenStream::from(quote_spanned! { input.span() =>
121 compile_error!("the async keyword is missing from the function declaration"),
122 });
123 }
124
125 if !args.is_empty() {
126 return TokenStream::from(quote_spanned! { args.span() =>
127 compile_error!("async benchmarks don't take any arguments"),
128 });
129 }
130
131 let result = quote! {
132 #[bench]
133 #(#attrs)*
134 fn #name(b: &mut test::Bencher) #ret {
135 let _ = b.iter(|| {
136 smol::block_on(async {
137 #body
138 })
139 });
140 }
141 };
142
143 result.into()
144}