tauri_plugin_dev_invoke_macros/
lib.rs

1use proc_macro::TokenStream;
2use quote::{format_ident, quote};
3use syn::{parse_macro_input, FnArg, ItemFn, Pat};
4
5#[proc_macro_attribute]
6pub fn command(_attr: TokenStream, item: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(item as ItemFn);
8    let name = &input.sig.ident;
9    let vis = &input.vis;
10    let wrapper_name = format_ident!("__dev_invoke_wrapper_{}", name);
11    let args_struct_name = format_ident!("__DevInvokeArgs_{}", name);
12
13    // Extract arguments for the helper struct
14    let mut struct_fields = Vec::new();
15    let mut call_args = Vec::new();
16
17    for arg in &input.sig.inputs {
18        if let FnArg::Typed(pat_type) = arg {
19            if let Pat::Ident(pat_ident) = &*pat_type.pat {
20                let arg_name = &pat_ident.ident;
21                let arg_type = &pat_type.ty;
22
23                struct_fields.push(quote! {
24                    pub #arg_name: #arg_type
25                });
26                call_args.push(quote! {
27                    args.#arg_name
28                });
29            }
30        }
31    }
32
33    let expanded = quote! {
34        #[tauri::command]
35        #input
36
37        #[allow(non_camel_case_types)]
38        #[derive(serde::Deserialize)]
39        pub struct #args_struct_name {
40            #(#struct_fields),*
41        }
42
43        #vis fn #wrapper_name(args_json: serde_json::Value) -> std::result::Result<serde_json::Value, String> {
44            let args: #args_struct_name = serde_json::from_value(args_json)
45                .map_err(|e| format!("Failed to deserialize arguments for {}: {}", stringify!(#name), e))?;
46
47            // Call the original function
48            let result = #name(#(#call_args),*);
49
50            // Serialize result
51            serde_json::to_value(result)
52                .map_err(|e| format!("Failed to serialize result for {}: {}", stringify!(#name), e))
53        }
54    };
55
56    TokenStream::from(expanded)
57}