From 39f8f269164d2fda3d5b614a193b12bb266e4b4b Mon Sep 17 00:00:00 2001 From: chip Date: Thu, 13 May 2021 06:18:15 -0700 Subject: [PATCH] refactor(macros): explicitly pass idents (#1812) --- .changes/command-macros-binding-refactor.md | 5 ++ core/tauri-macros/src/command/handler.rs | 13 ++-- core/tauri-macros/src/command/wrapper.rs | 66 +++++++++++---------- 3 files changed, 49 insertions(+), 35 deletions(-) create mode 100644 .changes/command-macros-binding-refactor.md diff --git a/.changes/command-macros-binding-refactor.md b/.changes/command-macros-binding-refactor.md new file mode 100644 index 000000000..1d48c96b8 --- /dev/null +++ b/.changes/command-macros-binding-refactor.md @@ -0,0 +1,5 @@ +--- +"tauri-macros": patch +--- + +internal: Refactor all macro code that expects specific bindings to be passed Idents diff --git a/core/tauri-macros/src/command/handler.rs b/core/tauri-macros/src/command/handler.rs index 6c97ae4d7..131f6f85b 100644 --- a/core/tauri-macros/src/command/handler.rs +++ b/core/tauri-macros/src/command/handler.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use quote::format_ident; use syn::{ parse::{Parse, ParseBuffer}, Ident, Path, Token, @@ -51,12 +52,14 @@ impl From for proc_macro::TokenStream { wrappers, }: Handler, ) -> Self { - quote::quote!(move |__tauri_invoke__| { - let __tauri_cmd__ = __tauri_invoke__.message.command(); - match __tauri_cmd__ { - #(stringify!(#commands) => #wrappers!(#paths, __tauri_invoke__),)* + let cmd = format_ident!("__tauri_cmd__"); + let invoke = format_ident!("__tauri_invoke__"); + quote::quote!(move |#invoke| { + let #cmd = #invoke.message.command(); + match #cmd { + #(stringify!(#commands) => #wrappers!(#paths, #invoke),)* _ => { - __tauri_invoke__.resolver.reject(format!("command {} not found", __tauri_cmd__)) + #invoke.resolver.reject(format!("command {} not found", #cmd)) }, } }) diff --git a/core/tauri-macros/src/command/wrapper.rs b/core/tauri-macros/src/command/wrapper.rs index 88b465c7c..c4f5820ee 100644 --- a/core/tauri-macros/src/command/wrapper.rs +++ b/core/tauri-macros/src/command/wrapper.rs @@ -4,7 +4,7 @@ use proc_macro::TokenStream; use proc_macro2::TokenStream as TokenStream2; -use quote::quote; +use quote::{format_ident, quote}; use syn::{ parse::{Parse, ParseBuffer}, parse_macro_input, @@ -36,6 +36,12 @@ impl Parse for ExecutionContext { } } +/// The bindings we attach to `tauri::Invoke`. +struct Invoke { + message: Ident, + resolver: Ident, +} + /// Create a new [`Wrapper`] from the function and the generated code parsed from the function. pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { let function = parse_macro_input!(item as ItemFn); @@ -48,6 +54,11 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { _ => Default::default(), }; + let invoke = Invoke { + message: format_ident!("__tauri_message__"), + resolver: format_ident!("__tauri_resolver__"), + }; + // body to the command wrapper or a `compile_error!` of an error occurred while parsing it. let body = syn::parse::(attributes) .map(|context| match function.sig.asyncness { @@ -55,11 +66,13 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { None => context, }) .and_then(|context| match context { - ExecutionContext::Async => body_async(&function), - ExecutionContext::Blocking => body_blocking(&function), + ExecutionContext::Async => body_async(&function, &invoke), + ExecutionContext::Blocking => body_blocking(&function, &invoke), }) .unwrap_or_else(syn::Error::into_compile_error); + let Invoke { message, resolver } = invoke; + // Rely on rust 2018 edition to allow importing a macro from a path. quote!( #function @@ -68,16 +81,9 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { macro_rules! #wrapper { // double braces because the item is expected to be a block expression ($path:path, $invoke:ident) => {{ - // import all the autoref specialization items - #[allow(unused_imports)] - use ::tauri::command::private::*; - // prevent warnings when the body is a `compile_error!` or if the command has no arguments #[allow(unused_variables)] - let ::tauri::Invoke { - message: __tauri_message__, - resolver: __tauri_resolver__ - } = $invoke; + let ::tauri::Invoke { message: #message, resolver: #resolver } = $invoke; #body }}; @@ -94,14 +100,15 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream { /// /// See the [`tauri::command`] module for all the items and traits that make this possible. /// -/// * Requires binding `__tauri_message__` and `__tauri_resolver__`. -/// * Requires all the traits from `tauri::command::private` to be in scope. -/// /// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html -fn body_async(function: &ItemFn) -> syn::Result { - parse_args(function).map(|args| { +fn body_async(function: &ItemFn, invoke: &Invoke) -> syn::Result { + let Invoke { message, resolver } = invoke; + parse_args(function, message).map(|args| { quote! { - __tauri_resolver__.respond_async_serialized(async move { + #[allow(unused_imports)] + use ::tauri::command::private::*; + + #resolver.respond_async_serialized(async move { let result = $path(#(#args?),*); let kind = (&result).async_kind(); kind.future(result).await @@ -114,40 +121,39 @@ fn body_async(function: &ItemFn) -> syn::Result { /// /// See the [`tauri::command`] module for all the items and traits that make this possible. /// -/// * Requires binding `__tauri_message__` and `__tauri_resolver__`. -/// * Requires all the traits from `tauri::command::private` to be in scope. -/// /// [`tauri::command`]: https://docs.rs/tauri/*/tauri/runtime/index.html -fn body_blocking(function: &ItemFn) -> syn::Result { - let args = parse_args(function)?; +fn body_blocking(function: &ItemFn, invoke: &Invoke) -> syn::Result { + let Invoke { message, resolver } = invoke; + let args = parse_args(function, message)?; // the body of a `match` to early return any argument that wasn't successful in parsing. let match_body = quote!({ Ok(arg) => arg, - Err(err) => return __tauri_resolver__.invoke_error(err), + Err(err) => return #resolver.invoke_error(err), }); Ok(quote! { + #[allow(unused_imports)] + use ::tauri::command::private::*; + let result = $path(#(match #args #match_body),*); let kind = (&result).blocking_kind(); - kind.block(result, __tauri_resolver__); + kind.block(result, #resolver); }) } /// Parse all arguments for the command wrapper to use from the signature of the command function. -fn parse_args(function: &ItemFn) -> syn::Result> { +fn parse_args(function: &ItemFn, message: &Ident) -> syn::Result> { function .sig .inputs .iter() - .map(|arg| parse_arg(&function.sig.ident, arg)) + .map(|arg| parse_arg(&function.sig.ident, arg, message)) .collect() } /// Transform a [`FnArg`] into a command argument. -/// -/// * Requires binding `__tauri_message__`. -fn parse_arg(command: &Ident, arg: &FnArg) -> syn::Result { +fn parse_arg(command: &Ident, arg: &FnArg, message: &Ident) -> syn::Result { // we have no use for self arguments let mut arg = match arg { FnArg::Typed(arg) => arg.pat.as_ref().clone(), @@ -190,7 +196,7 @@ fn parse_arg(command: &Ident, arg: &FnArg) -> syn::Result { ::tauri::command::CommandItem { name: stringify!(#command), key: #key, - message: &__tauri_message__, + message: &#message, } ))) }