1- use std:: collections:: VecDeque ;
2-
31use proc_macro2:: { Delimiter , TokenStream , TokenTree } ;
42use quote:: ToTokens ;
3+ use std:: collections:: VecDeque ;
4+ use std:: ops:: Not ;
55use syn:: parse:: ParseStream ;
6- use syn:: { Attribute , Error , Meta , Path , PathSegment , TypePath } ;
6+ use syn:: { Attribute , Error , Meta , Path , PathSegment , Token , TypePath } ;
77
8- struct CallMethodAttribute {
8+ pub struct CallMethodAttribute {
99 name : syn:: Ident ,
1010}
1111
@@ -17,6 +17,35 @@ impl syn::parse::Parse for CallMethodAttribute {
1717 }
1818}
1919
20+ #[ derive( Default , Clone ) ]
21+ pub struct GetFieldAttribute {
22+ reference : Option < ( Token ! [ & ] , Option < Token ! [ mut ] > ) > ,
23+ member : Option < syn:: Member > ,
24+ }
25+
26+ impl GetFieldAttribute {
27+ pub fn reference_tokens ( & self ) -> Option < TokenStream > {
28+ let ( ref_, mut_) = self . reference . as_ref ( ) ?;
29+ let mut tokens = ref_. to_token_stream ( ) ;
30+ mut_. to_tokens ( & mut tokens) ;
31+ Some ( tokens)
32+ }
33+ }
34+
35+ impl syn:: parse:: Parse for GetFieldAttribute {
36+ fn parse ( input : ParseStream ) -> Result < Self , Error > {
37+ let mut reference = None ;
38+ if let Ok ( ref_) = input. parse :: < syn:: Token ![ & ] > ( ) {
39+ reference = Some ( ( ref_, None ) ) ;
40+ }
41+ if let Some ( ( _, mut_) ) = & mut reference {
42+ * mut_ = input. parse :: < syn:: Token ![ mut ] > ( ) . ok ( ) ;
43+ }
44+ let member = input. is_empty ( ) . not ( ) . then ( || input. parse ( ) ) . transpose ( ) ?;
45+ Ok ( GetFieldAttribute { reference, member } )
46+ }
47+ }
48+
2049struct GenerateAwaitAttribute {
2150 literal : syn:: LitBool ,
2251}
@@ -202,10 +231,28 @@ pub enum ReturnExpression {
202231 Unwrap ,
203232}
204233
234+ pub enum TargetSpecifier {
235+ Field ( GetFieldAttribute ) ,
236+ Method ( CallMethodAttribute ) ,
237+ }
238+
239+ impl TargetSpecifier {
240+ pub fn get_member ( & self , default : & syn:: Ident ) -> syn:: Member {
241+ match self {
242+ Self :: Field ( GetFieldAttribute {
243+ member : Some ( member) ,
244+ ..
245+ } ) => member. clone ( ) ,
246+ Self :: Field ( _) => default. clone ( ) . into ( ) ,
247+ Self :: Method ( method) => method. name . clone ( ) . into ( ) ,
248+ }
249+ }
250+ }
251+
205252enum ParsedAttribute {
206253 ReturnExpression ( ReturnExpression ) ,
207254 Await ( bool ) ,
208- TargetMethod ( syn :: Ident ) ,
255+ TargetSpecifier ( TargetSpecifier ) ,
209256 ThroughTrait ( TraitTarget ) ,
210257 ConstantAccess ( AssociatedConstant ) ,
211258 Expr ( TemplateExpr ) ,
@@ -231,7 +278,19 @@ fn parse_attributes(
231278 let target = attribute
232279 . parse_args :: < CallMethodAttribute > ( )
233280 . expect ( "Cannot parse `call` attribute" ) ;
234- Some ( ParsedAttribute :: TargetMethod ( target. name ) )
281+ let spec = TargetSpecifier :: Method ( target) ;
282+ Some ( ParsedAttribute :: TargetSpecifier ( spec) )
283+ }
284+ "field" => {
285+ let target = if let syn:: Meta :: Path ( _) = & attribute. meta {
286+ GetFieldAttribute :: default ( )
287+ } else {
288+ attribute
289+ . parse_args :: < GetFieldAttribute > ( )
290+ . expect ( "Cannot parse `field` attribute" )
291+ } ;
292+ let spec = TargetSpecifier :: Field ( target) ;
293+ Some ( ParsedAttribute :: TargetSpecifier ( spec) )
235294 }
236295 "into" => {
237296 let into = match & attribute. meta {
@@ -300,7 +359,7 @@ fn parse_attributes(
300359
301360pub struct MethodAttributes < ' a > {
302361 pub attributes : Vec < & ' a Attribute > ,
303- pub target_method : Option < syn :: Ident > ,
362+ pub target_specifier : Option < TargetSpecifier > ,
304363 pub expressions : VecDeque < ReturnExpression > ,
305364 pub generate_await : Option < bool > ,
306365 pub target_trait : Option < TypePath > ,
@@ -320,7 +379,7 @@ pub fn parse_method_attributes<'a>(
320379 attrs : & ' a [ Attribute ] ,
321380 method : & syn:: TraitItemFn ,
322381) -> MethodAttributes < ' a > {
323- let mut target_method : Option < syn :: Ident > = None ;
382+ let mut target_spec : Option < TargetSpecifier > = None ;
324383 let mut expressions: Vec < ReturnExpression > = vec ! [ ] ;
325384 let mut generate_await: Option < bool > = None ;
326385 let mut target_trait: Option < TraitTarget > = None ;
@@ -340,14 +399,14 @@ pub fn parse_method_attributes<'a>(
340399 }
341400 generate_await = Some ( value) ;
342401 }
343- ParsedAttribute :: TargetMethod ( target ) => {
344- if target_method . is_some ( ) {
402+ ParsedAttribute :: TargetSpecifier ( spec ) => {
403+ if target_spec . is_some ( ) {
345404 panic ! (
346- "Multiple call attributes specified for {}" ,
405+ "Multiple field/ call attributes specified for {}" ,
347406 method. sig. ident
348407 )
349408 }
350- target_method = Some ( target ) ;
409+ target_spec = Some ( spec ) ;
351410 }
352411 ParsedAttribute :: ThroughTrait ( target) => {
353412 if target_trait. is_some ( ) {
@@ -379,13 +438,13 @@ pub fn parse_method_attributes<'a>(
379438 }
380439 }
381440
382- if associated_constant. is_some ( ) && target_method . is_some ( ) {
383- panic ! ( "Cannot use both `call` and `const` attributes." ) ;
441+ if associated_constant. is_some ( ) && target_spec . is_some ( ) {
442+ panic ! ( "Cannot use both `call`/`field` and `const` attributes." ) ;
384443 }
385444
386445 MethodAttributes {
387446 attributes : other. into_iter ( ) . collect ( ) ,
388- target_method ,
447+ target_specifier : target_spec ,
389448 generate_await,
390449 expressions : expressions. into ( ) ,
391450 target_trait : target_trait. map ( |t| t. type_path ) ,
@@ -425,8 +484,8 @@ pub fn parse_segment_attributes(attrs: &[Attribute]) -> SegmentAttributes {
425484 }
426485 target_trait = Some ( target) ;
427486 }
428- ParsedAttribute :: TargetMethod ( _) => {
429- panic ! ( "Call attribute cannot be specified on a `to <expr>` segment." ) ;
487+ ParsedAttribute :: TargetSpecifier ( _) => {
488+ panic ! ( "Field/call attribute cannot be specified on a `to <expr>` segment." ) ;
430489 }
431490 ParsedAttribute :: ConstantAccess ( _) => {
432491 panic ! ( "Const attribute cannot be specified on a `to <expr>` segment." ) ;
0 commit comments