@@ -50,17 +50,20 @@ 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:: token:: Eq ;
66
+ use syn:: Type ;
64
67
use syn:: TypeGenerics ;
65
68
use syn:: WhereClause ;
66
69
use syn:: WherePredicate ;
@@ -69,7 +72,7 @@ use syn::WherePredicate;
69
72
/// A type indicating whether or not to create a default implementation of Type::new().
70
73
type New = Option < ( ) > ;
71
74
/// A type representing an event type to parametrize a widget with.
72
- type Event = Option < String > ;
75
+ type Event = Option < Type > ;
73
76
74
77
75
78
/// The error type used internally by this module.
@@ -185,57 +188,83 @@ fn parse_attributes(attributes: &[Attribute]) -> Result<(New, Event)> {
185
188
}
186
189
187
190
/// 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( ) ) ) ) ,
191
+ fn parse_gui_attribute ( item : Attr ) -> Result < ( New , Event ) > {
192
+ match item {
193
+ Attr :: Ident ( ref ident) if ident == "default_new" => {
194
+ Ok ( ( Some ( ( ) ) , None ) )
195
+ } ,
196
+ Attr :: Binding ( binding) => {
197
+ // Unfortunately we can't use a pattern guard here. See issue
198
+ // https://github.com/rust-lang/rust/issues/15287 for more
199
+ // details.
200
+ if binding. ident == "Event" {
201
+ Ok ( ( None , Some ( binding. ty ) ) )
202
+ } else {
203
+ Err ( Error :: from ( "encountered unknown binding attribute" ) )
200
204
}
201
205
} ,
202
- NestedMeta :: Literal ( _ ) => Err ( Error :: from ( "unsupported literal " ) ) ,
206
+ _ => Err ( Error :: from ( "encountered unknown attribute " ) ) ,
203
207
}
204
208
}
205
209
206
210
/// Parse a #[gui(list...)] attribute list.
207
- fn parse_gui_attributes ( list : & Punctuated < NestedMeta , Comma > ) -> Result < ( New , Event ) > {
211
+ fn parse_gui_attributes ( list : AttrList ) -> Result < ( New , Event ) > {
208
212
let mut new = None ;
209
213
let mut event = None ;
210
214
211
- for item in list {
215
+ for item in list. 0 {
212
216
let ( this_new, this_event) = parse_gui_attribute ( item) ?;
213
217
new = this_new. or ( new) ;
214
218
event = this_event. or ( event) ;
215
219
}
216
220
Ok ( ( new, event) )
217
221
}
218
222
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
+
224
+ /// An attribute list representing an syn::Attribute::tts.
225
+ struct AttrList ( Punctuated < Attr , Comma > ) ;
226
+
227
+ impl Parse for AttrList {
228
+ fn parse ( input : ParseStream < ' _ > ) -> syn:: Result < Self > {
229
+ let content;
230
+ let _ = parenthesized ! ( content in input) ;
231
+ let list = content. parse_terminated ( Attr :: parse) ?;
232
+
233
+ Ok ( Self ( list) )
234
+ }
235
+ }
236
+
237
+
238
+ enum Attr {
239
+ Ident ( Ident ) ,
240
+ Binding ( Binding ) ,
241
+ }
242
+
243
+ impl Parse for Attr {
244
+ fn parse ( input : ParseStream < ' _ > ) -> syn:: Result < Self > {
245
+ // We need to peek at the second token coming up next first, because
246
+ // attempting to parse it would advance the position in the buffer.
247
+ if input. peek2 ( Eq ) {
248
+ let bind = input. parse :: < Binding > ( ) ?;
249
+ Ok ( Attr :: Binding ( bind) )
250
+ } else {
251
+ input. parse :: < Ident > ( ) . map ( Attr :: Ident )
252
+ }
253
+ }
254
+ }
255
+
256
+
257
+ /// Parse a single attribute, e.g., #[Event = MyEvent].
223
258
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 ) ) ,
259
+ if attribute. path . is_ident ( "gui" ) {
260
+ let tokens = attribute. tts . clone ( ) ;
261
+ let attr = parse2 :: < AttrList > ( tokens) . or_else ( |err| {
262
+ Err ( format ! ( "unable to parse attributes: {:?}" , err) )
263
+ } ) ?;
264
+
265
+ parse_gui_attributes ( attr)
266
+ } else {
267
+ Ok ( ( None , None ) )
239
268
}
240
269
}
241
270
@@ -353,12 +382,12 @@ fn expand_widget_trait(event: &Event, input: &DeriveInput) -> Tokens {
353
382
let generic = event. is_none ( ) ;
354
383
let ( generics, ty_generics, where_clause) = split_for_impl ( & input. generics , generic) ;
355
384
356
- let event = if let Some ( event) = event {
357
- Ident :: new ( & event , Span :: call_site ( ) )
385
+ let widget = if let Some ( event) = event {
386
+ quote ! { :: gui :: Widget <#event> }
358
387
} else {
359
- Ident :: new ( "__E" , Span :: call_site ( ) )
388
+ let event = Ident :: new ( "__E" , Span :: call_site ( ) ) ;
389
+ quote ! { :: gui:: Widget <#event> }
360
390
} ;
361
- let widget = quote ! { :: gui:: Widget <#event> } ;
362
391
363
392
quote ! {
364
393
impl #generics #widget for #name #ty_generics #where_clause {
@@ -382,7 +411,7 @@ fn expand_widget_trait(event: &Event, input: &DeriveInput) -> Tokens {
382
411
/// # use gui_derive::Widget;
383
412
/// # type Event = ();
384
413
/// # #[derive(Debug, Widget)]
385
- /// # #[gui(Event = " Event" )]
414
+ /// # #[gui(Event = Event)]
386
415
/// # struct TestWidget {
387
416
/// # id: gui::Id,
388
417
/// # }
@@ -470,12 +499,12 @@ fn expand_handleable_trait(event: &Event, input: &DeriveInput) -> Tokens {
470
499
let generic = event. is_none ( ) ;
471
500
let ( generics, ty_generics, where_clause) = split_for_impl ( & input. generics , generic) ;
472
501
473
- let event = if let Some ( event) = event {
474
- Ident :: new ( & event , Span :: call_site ( ) )
502
+ let handleable = if let Some ( event) = event {
503
+ quote ! { :: gui :: Handleable <#event> }
475
504
} else {
476
- Ident :: new ( "__E" , Span :: call_site ( ) )
505
+ let event = Ident :: new ( "__E" , Span :: call_site ( ) ) ;
506
+ quote ! { :: gui:: Handleable <#event> }
477
507
} ;
478
- let handleable = quote ! { :: gui:: Handleable <#event> } ;
479
508
480
509
quote ! {
481
510
impl #generics #handleable for #name #ty_generics #where_clause { }
@@ -515,26 +544,49 @@ mod tests {
515
544
#[ test]
516
545
fn custom_event ( ) {
517
546
let tokens = quote ! {
518
- #[ gui( Event = " FooBarBazEvent" ) ]
547
+ #[ gui( Event = FooBarBazEvent ) ]
519
548
struct Bar { }
520
549
} ;
521
550
522
551
let input = parse2 :: < DeriveInput > ( tokens) . unwrap ( ) ;
523
552
let ( new, event) = parse_attributes ( & input. attrs ) . unwrap ( ) ;
524
553
assert_eq ! ( new, None ) ;
525
- assert_eq ! ( event, Some ( "FooBarBazEvent" . to_string( ) ) ) ;
554
+
555
+ let tokens = quote ! { FooBarBazEvent } ;
556
+ let foobar = parse2 :: < Type > ( tokens) . unwrap ( ) ;
557
+ assert_eq ! ( event, Some ( foobar) ) ;
558
+ }
559
+
560
+ #[ test]
561
+ fn default_new_and_event_with_ignore ( ) {
562
+ let tokens = quote ! {
563
+ #[ allow( an_attribute_to_be_ignored) ]
564
+ #[ gui( default_new, Event = ( ) ) ]
565
+ struct Baz { }
566
+ } ;
567
+
568
+ let input = parse2 :: < DeriveInput > ( tokens) . unwrap ( ) ;
569
+ let ( new, event) = parse_attributes ( & input. attrs ) . unwrap ( ) ;
570
+ assert_eq ! ( new, Some ( ( ) ) ) ;
571
+
572
+ let tokens = quote ! { ( ) } ;
573
+ let parens = parse2 :: < Type > ( tokens) . unwrap ( ) ;
574
+ assert_eq ! ( event, Some ( parens) ) ;
526
575
}
527
576
528
577
#[ test]
529
578
fn last_event_type_takes_precedence ( ) {
530
579
let tokens = quote ! {
531
- #[ gui( Event = " Event1" ) ]
532
- #[ gui( Event = " Event2" ) ]
580
+ #[ gui( Event = Event1 ) ]
581
+ #[ gui( Event = Event2 ) ]
533
582
struct Foo { }
534
583
} ;
535
584
536
585
let input = parse2 :: < DeriveInput > ( tokens) . unwrap ( ) ;
537
586
let ( _, event) = parse_attributes ( & input. attrs ) . unwrap ( ) ;
538
- assert_eq ! ( event. as_ref( ) . map( String :: as_str) , Some ( "Event2" ) ) ;
587
+
588
+ let tokens = quote ! { Event2 } ;
589
+ let event2 = parse2 :: < Type > ( tokens) . unwrap ( ) ;
590
+ assert_eq ! ( event, Some ( event2) ) ;
539
591
}
540
592
}
0 commit comments