fluvio_future_derive/
lib.rs

1extern crate proc_macro;
2
3use proc_macro::TokenStream;
4use proc_macro2::Span;
5use quote::{quote, quote_spanned};
6use syn::spanned::Spanned;
7use syn::{Ident, ItemFn};
8
9#[proc_macro_attribute]
10pub fn main_async(_attr: TokenStream, item: TokenStream) -> TokenStream {
11    let input = syn::parse_macro_input!(item as syn::ItemFn);
12
13    let ret = &input.sig.output;
14    let inputs = &input.sig.inputs;
15    let name = &input.sig.ident;
16    let body = &input.block;
17    let attrs = &input.attrs;
18    let vis = &input.vis;
19
20    if name != "main" {
21        return TokenStream::from(quote_spanned! { name.span() =>
22            compile_error!("only the main function can be tagged with #[fluvio_future::main_async]"),
23        });
24    }
25
26    if input.sig.asyncness.is_none() {
27        return TokenStream::from(quote_spanned! { input.span() =>
28            compile_error!("the async keyword is missing from the function declaration"),
29        });
30    }
31
32    let result = quote! {
33        #vis fn main() #ret {
34
35            ::fluvio_future::subscriber::init_logger();
36
37            #(#attrs)*
38            async fn main(#inputs) #ret {
39                #body
40            }
41
42            ::fluvio_future::task::run_block_on(async {
43                main().await
44            })
45        }
46
47    };
48
49    result.into()
50}
51
52#[proc_macro_attribute]
53pub fn test_async(args: TokenStream, item: TokenStream) -> TokenStream {
54
55    let attribute_args = syn::parse_macro_input!(args with syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated);
56    let input = syn::parse_macro_input!(item as ItemFn);
57    let name = &input.sig.ident;
58    let sync_name = format!("{}_sync", name);
59    let out_fn_iden = Ident::new(&sync_name, Span::call_site());
60
61    let test_attributes = generate::generate_test_attributes(&attribute_args);
62
63    let expression = quote! {
64
65        #[test]
66        #test_attributes
67        fn #out_fn_iden()  {
68
69            ::fluvio_future::subscriber::init_logger();
70
71            #input
72
73            let ft = async {
74                #name().await
75            };
76
77            #[cfg(not(target_arch = "wasm32"))]
78            if let Err(err) = ::fluvio_future::task::run_block_on(ft) {
79                assert!(false,"error: {:?}",err);
80            }
81        }
82    };
83
84    expression.into()
85}
86
87#[proc_macro_attribute]
88pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
89
90    let attribute_args = syn::parse_macro_input!(args with syn::punctuated::Punctuated::<syn::Meta, syn::Token![,]>::parse_terminated);
91    let input = syn::parse_macro_input!(item as ItemFn);
92    let name = &input.sig.ident;
93    let sync_name = format!("{}_sync", name);
94    let out_fn_iden = Ident::new(&sync_name, Span::call_site());
95
96    let test_attributes = generate::generate_test_attributes(&attribute_args);
97
98    let expression = quote! {
99
100        #[test]
101        #test_attributes
102        fn #out_fn_iden()  {
103
104            ::fluvio_future::subscriber::init_logger();
105
106            #input
107
108            let ft = async {
109                #name().await;
110            };
111
112
113            ::fluvio_future::task::run_block_on(ft);
114        }
115    };
116
117    expression.into()
118}
119
120mod generate {
121
122    use proc_macro2::TokenStream;
123    use quote::quote;
124
125    pub fn generate_test_attributes(attributes: &syn::punctuated::Punctuated<syn::Meta, syn::Token![,]>) -> TokenStream {
126        let args = attributes.iter().map(|meta| {
127            quote! {
128                #[#meta]
129            }
130        });
131
132        quote! {
133
134            #(#args)*
135
136        }
137    }
138}