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::{Ident, ItemFn};
7use syn::spanned::Spanned;
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    use syn::AttributeArgs;
55
56    let attribute_args = syn::parse_macro_input!(args as AttributeArgs);
57    let input = syn::parse_macro_input!(item as ItemFn);
58    let name = &input.sig.ident;
59    let sync_name = format!("{}_sync", name);
60    let out_fn_iden = Ident::new(&sync_name, Span::call_site());
61
62    let test_attributes = generate::generate_test_attributes(&attribute_args);
63
64    let expression = quote! {
65
66        #[test]
67        #test_attributes
68        fn #out_fn_iden()  {
69
70            ::fluvio_future::subscriber::init_logger();
71
72            #input
73
74            let ft = async {
75                #name().await
76            };
77
78            #[cfg(not(target_arch = "wasm32"))]
79            if let Err(err) = ::fluvio_future::task::run_block_on(ft) {
80                assert!(false,"error: {:?}",err);
81            }
82            #[cfg(target_arch = "wasm32")]
83            ::fluvio_future::task::run_block_on(ft);
84
85        }
86    };
87
88    expression.into()
89}
90
91#[proc_macro_attribute]
92pub fn test(args: TokenStream, item: TokenStream) -> TokenStream {
93    use syn::AttributeArgs;
94
95    let attribute_args = syn::parse_macro_input!(args as AttributeArgs);
96    let input = syn::parse_macro_input!(item as ItemFn);
97    let name = &input.sig.ident;
98    let sync_name = format!("{}_sync", name);
99    let out_fn_iden = Ident::new(&sync_name, Span::call_site());
100
101    let test_attributes = generate::generate_test_attributes(&attribute_args);
102
103    let expression = quote! {
104
105        #[test]
106        #test_attributes
107        fn #out_fn_iden()  {
108
109            ::fluvio_future::subscriber::init_logger();
110
111            #input
112
113            let ft = async {
114                #name().await;
115            };
116
117
118            ::fluvio_future::task::run_block_on(ft);
119
120        }
121    };
122
123    expression.into()
124}
125
126mod generate {
127
128    use proc_macro2::TokenStream;
129    use quote::quote;
130    use syn::NestedMeta;
131
132    pub fn generate_test_attributes(attributes: &Vec<NestedMeta>) -> TokenStream {
133        let args = attributes.iter().map(|meta| {
134            quote! {
135                #[#meta]
136            }
137        });
138
139        quote! {
140
141            #(#args)*
142
143        }
144    }
145}