@@ -50,17 +50,19 @@ use proc_macro2::Span;
50
50
use quote:: __rt:: TokenStream as Tokens ;
51
51
use quote:: quote;
52
52
use syn:: Attribute ;
53
+ use syn:: Binding ;
53
54
use syn:: Data ;
54
55
use syn:: DeriveInput ;
55
56
use syn:: Fields ;
56
57
use syn:: GenericParam ;
57
58
use syn:: Generics ;
58
- use syn:: Lit ;
59
- use syn:: Meta ;
60
- use syn:: NestedMeta ;
59
+ use syn:: parenthesized ;
60
+ use syn:: parse :: Parse ;
61
+ use syn:: parse :: ParseStream ;
61
62
use syn:: parse2;
62
63
use syn:: punctuated:: Punctuated ;
63
64
use syn:: token:: Comma ;
65
+ use syn:: Type ;
64
66
use syn:: TypeGenerics ;
65
67
use syn:: WhereClause ;
66
68
use syn:: WherePredicate ;
@@ -69,7 +71,7 @@ use syn::WherePredicate;
69
71
/// A type indicating whether or not to create a default implementation of Type::new().
70
72
type New = Option < ( ) > ;
71
73
/// A type representing an event type to parametrize a widget with.
72
- type Event = Option < String > ;
74
+ type Event = Option < Type > ;
73
75
74
76
75
77
/// The error type used internally by this module.
@@ -185,60 +187,79 @@ fn parse_attributes(attributes: &[Attribute]) -> Result<(New, Event)> {
185
187
}
186
188
187
189
/// Parse a single item in a #[gui(list...)] attribute list.
188
- fn parse_gui_attribute ( item : & NestedMeta ) -> Result < ( New , Event ) > {
189
- match * item {
190
- NestedMeta :: Meta ( ref meta_item) => {
191
- match * meta_item {
192
- Meta :: NameValue ( ref name_val) if name_val. ident == "Event" => {
193
- match name_val. lit {
194
- Lit :: Str ( ref string) => Ok ( ( None , Some ( string. value ( ) ) ) ) ,
195
- _ => Ok ( ( None , None ) ) ,
196
- }
197
- } ,
198
- Meta :: Word ( ref ident) if ident == "default_new" => Ok ( ( Some ( ( ) ) , None ) ) ,
199
- _ => Err ( Error :: from ( format ! ( "unsupported attribute: {}" , meta_item. name( ) ) ) ) ,
190
+ fn parse_gui_attribute ( item : Attr ) -> Result < ( New , Event ) > {
191
+ match item {
192
+ Attr :: Ident ( ref ident) if ident == "default_new" => {
193
+ Ok ( ( Some ( ( ) ) , None ) )
194
+ } ,
195
+ Attr :: Binding ( binding) => {
196
+ // Unfortunately we can't use a pattern guard here. See issue
197
+ // https://github.com/rust-lang/rust/issues/15287 for more
198
+ // details.
199
+ if binding. ident == "Event" {
200
+ Ok ( ( None , Some ( binding. ty ) ) )
201
+ } else {
202
+ Err ( Error :: from ( "encountered unknown attribute" ) )
200
203
}
201
204
} ,
202
- NestedMeta :: Literal ( _ ) => Err ( Error :: from ( "unsupported literal " ) ) ,
205
+ _ => Err ( Error :: from ( "encountered unknown attribute " ) ) ,
203
206
}
204
207
}
205
208
206
209
/// Parse a #[gui(list...)] attribute list.
207
- fn parse_gui_attributes ( list : & Punctuated < NestedMeta , Comma > ) -> Result < ( New , Event ) > {
210
+ fn parse_gui_attributes ( list : AttrList ) -> Result < ( New , Event ) > {
208
211
let mut new = None ;
209
212
let mut event = None ;
210
213
211
- for item in list {
214
+ for item in list. 0 {
212
215
let ( this_new, this_event) = parse_gui_attribute ( item) ?;
213
216
new = this_new. or ( new) ;
214
217
event = this_event. or ( event) ;
215
218
}
216
219
Ok ( ( new, event) )
217
220
}
218
221
219
- /// Parse a single attribute, e.g., #[GuiType = "Widget"].
220
- // TODO: Once https://github.com/rust-lang/rust/pull/57367 lands in
221
- // stable we should migrate to using the actual type and not a
222
- // textual representation of it.
223
- fn parse_attribute ( attribute : & Attribute ) -> Result < ( New , Event ) > {
224
- // We don't care about the other meta data elements, inner/outer,
225
- // doc/non-doc, it's all fine by us.
226
-
227
- match attribute. interpret_meta ( ) {
228
- Some ( x) => {
229
- match x {
230
- Meta :: List ( ref list) if list. ident == "gui" => {
231
- // Here we have found an attribute of the form #[gui(xxx, yyy,
232
- // ...)]. Parse the inner list.
233
- parse_gui_attributes ( & list. nested )
234
- } ,
235
- _ => Ok ( ( None , None ) ) ,
236
- }
237
- } ,
238
- None => Ok ( ( None , None ) ) ,
222
+
223
+ /// An attribute list representing an syn::Attribute::tts.
224
+ struct AttrList ( Punctuated < Attr , Comma > ) ;
225
+
226
+ impl Parse for AttrList {
227
+ fn parse ( input : ParseStream < ' _ > ) -> syn:: Result < Self > {
228
+ let content;
229
+ let _ = parenthesized ! ( content in input) ;
230
+ let list = content. parse_terminated ( Attr :: parse) ?;
231
+
232
+ Ok ( Self ( list) )
239
233
}
240
234
}
241
235
236
+
237
+ enum Attr {
238
+ Ident ( Ident ) ,
239
+ Binding ( Binding ) ,
240
+ }
241
+
242
+ impl Parse for Attr {
243
+ fn parse ( input : ParseStream < ' _ > ) -> syn:: Result < Self > {
244
+ if let Ok ( bind) = input. parse :: < Binding > ( ) {
245
+ Ok ( Attr :: Binding ( bind) )
246
+ } else {
247
+ input. parse :: < Ident > ( ) . map ( |ident| Attr :: Ident ( ident) )
248
+ }
249
+ }
250
+ }
251
+
252
+
253
+ /// Parse a single attribute, e.g., #[Event = MyEvent].
254
+ fn parse_attribute ( attribute : & Attribute ) -> Result < ( New , Event ) > {
255
+ let tokens = attribute. tts . clone ( ) ;
256
+ let attr = parse2 :: < AttrList > ( tokens) . or_else ( |err| {
257
+ Err ( format ! ( "unable to parse attributes: {:?}" , err) )
258
+ } ) ?;
259
+
260
+ parse_gui_attributes ( attr)
261
+ }
262
+
242
263
/// Expand the input with the implementation of the required traits.
243
264
fn expand_widget_input ( new : New , event : & Event , input : & DeriveInput ) -> Result < Tokens > {
244
265
match input. data {
@@ -353,12 +374,12 @@ fn expand_widget_trait(event: &Event, input: &DeriveInput) -> Tokens {
353
374
let generic = event. is_none ( ) ;
354
375
let ( generics, ty_generics, where_clause) = split_for_impl ( & input. generics , generic) ;
355
376
356
- let event = if let Some ( event) = event {
357
- Ident :: new ( & event , Span :: call_site ( ) )
377
+ let widget = if let Some ( event) = event {
378
+ quote ! { :: gui :: Widget <#event> }
358
379
} else {
359
- Ident :: new ( "__E" , Span :: call_site ( ) )
380
+ let event = Ident :: new ( "__E" , Span :: call_site ( ) ) ;
381
+ quote ! { :: gui:: Widget <#event> }
360
382
} ;
361
- let widget = quote ! { :: gui:: Widget <#event> } ;
362
383
363
384
quote ! {
364
385
impl #generics #widget for #name #ty_generics #where_clause {
@@ -470,12 +491,12 @@ fn expand_handleable_trait(event: &Event, input: &DeriveInput) -> Tokens {
470
491
let generic = event. is_none ( ) ;
471
492
let ( generics, ty_generics, where_clause) = split_for_impl ( & input. generics , generic) ;
472
493
473
- let event = if let Some ( event) = event {
474
- Ident :: new ( & event , Span :: call_site ( ) )
494
+ let handleable = if let Some ( event) = event {
495
+ quote ! { :: gui :: Handleable <#event> }
475
496
} else {
476
- Ident :: new ( "__E" , Span :: call_site ( ) )
497
+ let event = Ident :: new ( "__E" , Span :: call_site ( ) ) ;
498
+ quote ! { :: gui:: Handleable <#event> }
477
499
} ;
478
- let handleable = quote ! { :: gui:: Handleable <#event> } ;
479
500
480
501
quote ! {
481
502
impl #generics #handleable for #name #ty_generics #where_clause { }
0 commit comments