@@ -10,10 +10,28 @@ use syn::{
1010 ext:: IdentExt ,
1111 parse:: { Parse , ParseStream } ,
1212 parse_macro_input,
13+ punctuated:: Punctuated ,
1314 spanned:: Spanned ,
14- FnArg , ItemFn , Lit , Meta , Pat , Token , Visibility ,
15+ Expr , ExprLit , FnArg , ItemFn , Lit , Meta , Pat , Token , Visibility ,
1516} ;
1617
18+ enum WrapperAttributeKind {
19+ Meta ( Meta ) ,
20+ Async ,
21+ }
22+
23+ impl Parse for WrapperAttributeKind {
24+ fn parse ( input : ParseStream ) -> syn:: Result < Self > {
25+ match input. parse :: < Meta > ( ) {
26+ Ok ( m) => Ok ( Self :: Meta ( m) ) ,
27+ Err ( e) => match input. parse :: < Token ! [ async ] > ( ) {
28+ Ok ( _) => Ok ( Self :: Async ) ,
29+ Err ( _) => Err ( e) ,
30+ } ,
31+ }
32+ }
33+ }
34+
1735struct WrapperAttributes {
1836 root : TokenStream2 ,
1937 execution_context : ExecutionContext ,
@@ -28,12 +46,19 @@ impl Parse for WrapperAttributes {
2846 argument_case : ArgumentCase :: Camel ,
2947 } ;
3048
31- loop {
32- match input. parse :: < Meta > ( ) {
33- Ok ( Meta :: List ( _) ) => { }
34- Ok ( Meta :: NameValue ( v) ) => {
49+ let attrs = Punctuated :: < WrapperAttributeKind , Token ! [ , ] > :: parse_terminated ( input) ?;
50+ for attr in attrs {
51+ match attr {
52+ WrapperAttributeKind :: Meta ( Meta :: List ( _) ) => {
53+ return Err ( syn:: Error :: new ( input. span ( ) , "unexpected list input" ) ) ;
54+ }
55+ WrapperAttributeKind :: Meta ( Meta :: NameValue ( v) ) => {
3556 if v. path . is_ident ( "rename_all" ) {
36- if let Lit :: Str ( s) = v. lit {
57+ if let Expr :: Lit ( ExprLit {
58+ lit : Lit :: Str ( s) ,
59+ attrs : _,
60+ } ) = v. value
61+ {
3762 wrapper_attributes. argument_case = match s. value ( ) . as_str ( ) {
3863 "snake_case" => ArgumentCase :: Snake ,
3964 "camelCase" => ArgumentCase :: Camel ,
@@ -46,7 +71,11 @@ impl Parse for WrapperAttributes {
4671 } ;
4772 }
4873 } else if v. path . is_ident ( "root" ) {
49- if let Lit :: Str ( s) = v. lit {
74+ if let Expr :: Lit ( ExprLit {
75+ lit : Lit :: Str ( s) ,
76+ attrs : _,
77+ } ) = v. value
78+ {
5079 let lit = s. value ( ) ;
5180
5281 wrapper_attributes. root = if lit == "crate" {
@@ -58,22 +87,16 @@ impl Parse for WrapperAttributes {
5887 }
5988 }
6089 }
61- Ok ( Meta :: Path ( p) ) => {
62- if p. is_ident ( "async" ) {
63- wrapper_attributes. execution_context = ExecutionContext :: Async ;
64- } else {
65- return Err ( syn:: Error :: new ( p. span ( ) , "expected `async`" ) ) ;
66- }
90+ WrapperAttributeKind :: Meta ( Meta :: Path ( _) ) => {
91+ return Err ( syn:: Error :: new (
92+ input. span ( ) ,
93+ "unexpected input, expected one of `rename_all`, `root`, `async`" ,
94+ ) ) ;
6795 }
68- Err ( _e ) => {
69- break ;
96+ WrapperAttributeKind :: Async => {
97+ wrapper_attributes . execution_context = ExecutionContext :: Async ;
7098 }
7199 }
72-
73- let lookahead = input. lookahead1 ( ) ;
74- if lookahead. peek ( Token ! [ , ] ) {
75- input. parse :: < Token ! [ , ] > ( ) ?;
76- }
77100 }
78101
79102 Ok ( wrapper_attributes)
@@ -101,10 +124,15 @@ struct Invoke {
101124
102125/// Create a new [`Wrapper`] from the function and the generated code parsed from the function.
103126pub fn wrapper ( attributes : TokenStream , item : TokenStream ) -> TokenStream {
127+ let mut attrs = parse_macro_input ! ( attributes as WrapperAttributes ) ;
104128 let function = parse_macro_input ! ( item as ItemFn ) ;
105129 let wrapper = super :: format_command_wrapper ( & function. sig . ident ) ;
106130 let visibility = & function. vis ;
107131
132+ if function. sig . asyncness . is_some ( ) {
133+ attrs. execution_context = ExecutionContext :: Async ;
134+ }
135+
108136 // macros used with `pub use my_macro;` need to be exported with `#[macro_export]`
109137 let maybe_macro_export = match & function. vis {
110138 Visibility :: Public ( _) => quote ! ( #[ macro_export] ) ,
@@ -173,28 +201,18 @@ pub fn wrapper(attributes: TokenStream, item: TokenStream) -> TokenStream {
173201 }
174202 }
175203
176- // body to the command wrapper or a `compile_error!` of an error occurred while parsing it.
177- let ( body, attributes) = syn:: parse :: < WrapperAttributes > ( attributes)
178- . map ( |mut attrs| {
179- if function. sig . asyncness . is_some ( ) {
180- attrs. execution_context = ExecutionContext :: Async ;
181- }
182- attrs
183- } )
184- . and_then ( |attrs| {
185- let body = match attrs. execution_context {
186- ExecutionContext :: Async => body_async ( & function, & invoke, & attrs) ,
187- ExecutionContext :: Blocking => body_blocking ( & function, & invoke, & attrs) ,
188- } ;
189- body. map ( |b| ( b, Some ( attrs) ) )
190- } )
191- . unwrap_or_else ( |e| ( syn:: Error :: into_compile_error ( e) , None ) ) ;
204+ let body = match attrs. execution_context {
205+ ExecutionContext :: Async => {
206+ body_async ( & function, & invoke, & attrs) . unwrap_or_else ( syn:: Error :: into_compile_error)
207+ }
208+ ExecutionContext :: Blocking => {
209+ body_blocking ( & function, & invoke, & attrs) . unwrap_or_else ( syn:: Error :: into_compile_error)
210+ }
211+ } ;
192212
193213 let Invoke { message, resolver } = invoke;
194214
195- let root = attributes
196- . map ( |a| a. root )
197- . unwrap_or_else ( || quote ! ( :: tauri) ) ;
215+ let root = attrs. root ;
198216
199217 // Rely on rust 2018 edition to allow importing a macro from a path.
200218 quote ! (
0 commit comments