extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, ItemFn};
#[proc_macro_attribute]
pub fn async_wrapper(_attr: TokenStream, item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemFn);
generate_async_wrapper(&input).into()
}
fn generate_async_wrapper(input: &ItemFn) -> proc_macro2::TokenStream {
let fn_name = &input.sig.ident; let fn_inputs = &input.sig.inputs; let fn_output = &input.sig.output; let fn_block = &input.block;
quote! {
#[tauri::command]
pub async fn #fn_name(#fn_inputs) #fn_output {
tauri::async_runtime::spawn_blocking(move || {
#fn_block
})
.await
.map_err(|e| e.to_string())?
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use proc_macro2::TokenStream as TokenStream2;
use quote::quote;
use syn::parse_quote;
#[test]
fn test_async_wrapper() {
let input_fn: ItemFn = parse_quote! {
pub fn test_function(x: i32, y: String) -> Result<String, String> {
Ok(format!("{} {}", x, y))
}
};
let output = generate_async_wrapper(&input_fn);
let expected_output: TokenStream2 = quote! {
#[tauri::command]
pub async fn test_function(x: i32, y: String) -> Result<String, String> {
tauri::async_runtime::spawn_blocking(move || {
{ Ok(format!("{} {}", x, y)) }
})
.await
.map_err(|e| e.to_string())?
}
};
assert_eq!(output.to_string(), expected_output.to_string());
}
}