1 // Copyright 2018 Guillaume Pinot (@TeXitoi) <[email protected]>,
2 // Kevin Knapp (@kbknapp) <[email protected]>, and
3 // Ana Hobden (@hoverbear) <[email protected]>
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10 //
11 // This work was derived from Structopt (https://github.com/TeXitoi/structopt)
12 // commit#ea76fa1b1b273e65e3b0b1046643715b49bec51f which is licensed under the
13 // MIT/Apache 2.0 license.
14 
15 use proc_macro2::{Ident, Span, TokenStream};
16 use quote::{format_ident, quote, quote_spanned};
17 use syn::{
18     punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DataStruct, DeriveInput, Field,
19     Fields, FieldsNamed, Generics,
20 };
21 
22 use crate::item::{Item, Kind, Name};
23 use crate::utils::{inner_type, sub_type, Sp, Ty};
24 
derive_args(input: &DeriveInput) -> Result<TokenStream, syn::Error>25 pub fn derive_args(input: &DeriveInput) -> Result<TokenStream, syn::Error> {
26     let ident = &input.ident;
27 
28     match input.data {
29         Data::Struct(DataStruct {
30             fields: Fields::Named(ref fields),
31             ..
32         }) => {
33             let name = Name::Derived(ident.clone());
34             let item = Item::from_args_struct(input, name)?;
35             let fields = collect_args_fields(&item, fields)?;
36             gen_for_struct(&item, ident, &input.generics, &fields)
37         }
38         Data::Struct(DataStruct {
39             fields: Fields::Unit,
40             ..
41         }) => {
42             let name = Name::Derived(ident.clone());
43             let item = Item::from_args_struct(input, name)?;
44             let fields = Punctuated::<Field, Comma>::new();
45             let fields = fields
46                 .iter()
47                 .map(|field| {
48                     let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
49                     Ok((field, item))
50                 })
51                 .collect::<Result<Vec<_>, syn::Error>>()?;
52             gen_for_struct(&item, ident, &input.generics, &fields)
53         }
54         _ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"),
55     }
56 }
57 
gen_for_struct( item: &Item, item_name: &Ident, generics: &Generics, fields: &[(&Field, Item)], ) -> Result<TokenStream, syn::Error>58 pub fn gen_for_struct(
59     item: &Item,
60     item_name: &Ident,
61     generics: &Generics,
62     fields: &[(&Field, Item)],
63 ) -> Result<TokenStream, syn::Error> {
64     if !matches!(&*item.kind(), Kind::Command(_)) {
65         abort! { item.kind().span(),
66             "`{}` cannot be used with `command`",
67             item.kind().name(),
68         }
69     }
70 
71     let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
72 
73     let constructor = gen_constructor(fields)?;
74     let updater = gen_updater(fields, true)?;
75     let raw_deprecated = raw_deprecated();
76 
77     let app_var = Ident::new("__clap_app", Span::call_site());
78     let augmentation = gen_augment(fields, &app_var, item, false)?;
79     let augmentation_update = gen_augment(fields, &app_var, item, true)?;
80 
81     let group_id = if item.skip_group() {
82         quote!(None)
83     } else {
84         let group_id = item.group_id();
85         quote!(Some(clap::Id::from(#group_id)))
86     };
87 
88     Ok(quote! {
89         #[allow(
90             dead_code,
91             unreachable_code,
92             unused_variables,
93             unused_braces,
94             unused_qualifications,
95         )]
96         #[allow(
97             clippy::style,
98             clippy::complexity,
99             clippy::pedantic,
100             clippy::restriction,
101             clippy::perf,
102             clippy::deprecated,
103             clippy::nursery,
104             clippy::cargo,
105             clippy::suspicious_else_formatting,
106             clippy::almost_swapped,
107             clippy::redundant_locals,
108         )]
109         #[automatically_derived]
110         impl #impl_generics clap::FromArgMatches for #item_name #ty_generics #where_clause {
111             fn from_arg_matches(__clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
112                 Self::from_arg_matches_mut(&mut __clap_arg_matches.clone())
113             }
114 
115             fn from_arg_matches_mut(__clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<Self, clap::Error> {
116                 #raw_deprecated
117                 let v = #item_name #constructor;
118                 ::std::result::Result::Ok(v)
119             }
120 
121             fn update_from_arg_matches(&mut self, __clap_arg_matches: &clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
122                 self.update_from_arg_matches_mut(&mut __clap_arg_matches.clone())
123             }
124 
125             fn update_from_arg_matches_mut(&mut self, __clap_arg_matches: &mut clap::ArgMatches) -> ::std::result::Result<(), clap::Error> {
126                 #raw_deprecated
127                 #updater
128                 ::std::result::Result::Ok(())
129             }
130         }
131 
132         #[allow(
133             dead_code,
134             unreachable_code,
135             unused_variables,
136             unused_braces,
137             unused_qualifications,
138         )]
139         #[allow(
140             clippy::style,
141             clippy::complexity,
142             clippy::pedantic,
143             clippy::restriction,
144             clippy::perf,
145             clippy::deprecated,
146             clippy::nursery,
147             clippy::cargo,
148             clippy::suspicious_else_formatting,
149             clippy::almost_swapped,
150             clippy::redundant_locals,
151         )]
152         #[automatically_derived]
153         impl #impl_generics clap::Args for #item_name #ty_generics #where_clause {
154             fn group_id() -> Option<clap::Id> {
155                 #group_id
156             }
157             fn augment_args<'b>(#app_var: clap::Command) -> clap::Command {
158                 #augmentation
159             }
160             fn augment_args_for_update<'b>(#app_var: clap::Command) -> clap::Command {
161                 #augmentation_update
162             }
163         }
164     })
165 }
166 
167 /// Generate a block of code to add arguments/subcommands corresponding to
168 /// the `fields` to an cmd.
gen_augment( fields: &[(&Field, Item)], app_var: &Ident, parent_item: &Item, override_required: bool, ) -> Result<TokenStream, syn::Error>169 pub fn gen_augment(
170     fields: &[(&Field, Item)],
171     app_var: &Ident,
172     parent_item: &Item,
173     override_required: bool,
174 ) -> Result<TokenStream, syn::Error> {
175     let mut subcommand_specified = false;
176     let mut args = Vec::new();
177     for (field, item) in fields {
178         let kind = item.kind();
179         let genned = match &*kind {
180             Kind::Command(_)
181             | Kind::Value
182             | Kind::Skip(_, _)
183             | Kind::FromGlobal(_)
184             | Kind::ExternalSubcommand => None,
185             Kind::Subcommand(ty) => {
186                 if subcommand_specified {
187                     abort!(
188                         field.span(),
189                         "`#[command(subcommand)]` can only be used once per container"
190                     );
191                 }
192                 subcommand_specified = true;
193 
194                 let subcmd_type = match (**ty, sub_type(&field.ty)) {
195                     (Ty::Option, Some(sub_type)) => sub_type,
196                     _ => &field.ty,
197                 };
198                 let implicit_methods = if **ty == Ty::Option {
199                     quote!()
200                 } else {
201                     quote_spanned! { kind.span()=>
202                         .subcommand_required(true)
203                         .arg_required_else_help(true)
204                     }
205                 };
206 
207                 let override_methods = if override_required {
208                     quote_spanned! { kind.span()=>
209                         .subcommand_required(false)
210                         .arg_required_else_help(false)
211                     }
212                 } else {
213                     quote!()
214                 };
215 
216                 Some(quote! {
217                     let #app_var = <#subcmd_type as clap::Subcommand>::augment_subcommands( #app_var );
218                     let #app_var = #app_var
219                         #implicit_methods
220                         #override_methods;
221                 })
222             }
223             Kind::Flatten(ty) => {
224                 let inner_type = match (**ty, sub_type(&field.ty)) {
225                     (Ty::Option, Some(sub_type)) => sub_type,
226                     _ => &field.ty,
227                 };
228 
229                 let next_help_heading = item.next_help_heading();
230                 let next_display_order = item.next_display_order();
231                 if override_required {
232                     Some(quote_spanned! { kind.span()=>
233                         let #app_var = #app_var
234                             #next_help_heading
235                             #next_display_order;
236                         let #app_var = <#inner_type as clap::Args>::augment_args_for_update(#app_var);
237                     })
238                 } else {
239                     Some(quote_spanned! { kind.span()=>
240                         let #app_var = #app_var
241                             #next_help_heading
242                             #next_display_order;
243                         let #app_var = <#inner_type as clap::Args>::augment_args(#app_var);
244                     })
245                 }
246             }
247             Kind::Arg(ty) => {
248                 let value_parser = item.value_parser(&field.ty);
249                 let action = item.action(&field.ty);
250                 let value_name = item.value_name();
251 
252                 let implicit_methods = match **ty {
253                     Ty::Unit => {
254                         // Leaving out `value_parser` as it will always fail
255                         quote_spanned! { ty.span()=>
256                             .value_name(#value_name)
257                             #action
258                         }
259                     }
260                     Ty::Option => {
261                         quote_spanned! { ty.span()=>
262                             .value_name(#value_name)
263                             #value_parser
264                             #action
265                         }
266                     }
267 
268                     Ty::OptionOption => quote_spanned! { ty.span()=>
269                         .value_name(#value_name)
270                         .num_args(0..=1)
271                         #value_parser
272                         #action
273                     },
274 
275                     Ty::OptionVec => {
276                         if item.is_positional() {
277                             quote_spanned! { ty.span()=>
278                                 .value_name(#value_name)
279                                 .num_args(1..)  // action won't be sufficient for getting multiple
280                                 #value_parser
281                                 #action
282                             }
283                         } else {
284                             quote_spanned! { ty.span()=>
285                                 .value_name(#value_name)
286                                 #value_parser
287                                 #action
288                             }
289                         }
290                     }
291 
292                     Ty::Vec => {
293                         if item.is_positional() {
294                             quote_spanned! { ty.span()=>
295                                 .value_name(#value_name)
296                                 .num_args(1..)  // action won't be sufficient for getting multiple
297                                 #value_parser
298                                 #action
299                             }
300                         } else {
301                             quote_spanned! { ty.span()=>
302                                 .value_name(#value_name)
303                                 #value_parser
304                                 #action
305                             }
306                         }
307                     }
308 
309                     Ty::VecVec | Ty::OptionVecVec => {
310                         quote_spanned! { ty.span() =>
311                             .value_name(#value_name)
312                             #value_parser
313                             #action
314                         }
315                     }
316 
317                     Ty::Other => {
318                         let required = item.find_default_method().is_none();
319                         // `ArgAction::takes_values` is assuming `ArgAction::default_value` will be
320                         // set though that won't always be true but this should be good enough,
321                         // otherwise we'll report an "arg required" error when unwrapping.
322                         let action_value = action.args();
323                         quote_spanned! { ty.span()=>
324                             .value_name(#value_name)
325                             .required(#required && #action_value.takes_values())
326                             #value_parser
327                             #action
328                         }
329                     }
330                 };
331 
332                 let id = item.id();
333                 let explicit_methods = item.field_methods();
334                 let deprecations = if !override_required {
335                     item.deprecations()
336                 } else {
337                     quote!()
338                 };
339                 let override_methods = if override_required {
340                     quote_spanned! { kind.span()=>
341                         .required(false)
342                     }
343                 } else {
344                     quote!()
345                 };
346 
347                 Some(quote_spanned! { field.span()=>
348                     let #app_var = #app_var.arg({
349                         #deprecations
350 
351                         #[allow(deprecated)]
352                         let arg = clap::Arg::new(#id)
353                             #implicit_methods;
354 
355                         let arg = arg
356                             #explicit_methods;
357 
358                         let arg = arg
359                             #override_methods;
360 
361                         arg
362                     });
363                 })
364             }
365         };
366         args.push(genned);
367     }
368 
369     let deprecations = if !override_required {
370         parent_item.deprecations()
371     } else {
372         quote!()
373     };
374     let initial_app_methods = parent_item.initial_top_level_methods();
375     let final_app_methods = parent_item.final_top_level_methods();
376     let group_app_methods = if parent_item.skip_group() {
377         quote!()
378     } else {
379         let group_id = parent_item.group_id();
380         let literal_group_members = fields
381             .iter()
382             .filter_map(|(_field, item)| {
383                 let kind = item.kind();
384                 if matches!(*kind, Kind::Arg(_)) {
385                     Some(item.id())
386                 } else {
387                     None
388                 }
389             })
390             .collect::<Vec<_>>();
391         let literal_group_members_len = literal_group_members.len();
392         let mut literal_group_members = quote! {{
393             let members: [clap::Id; #literal_group_members_len] = [#( clap::Id::from(#literal_group_members) ),* ];
394             members
395         }};
396         // HACK: Validation isn't ready yet for nested arg groups, so just don't populate the group in
397         // that situation
398         let possible_group_members_len = fields
399             .iter()
400             .filter(|(_field, item)| {
401                 let kind = item.kind();
402                 matches!(*kind, Kind::Flatten(_))
403             })
404             .count();
405         if 0 < possible_group_members_len {
406             literal_group_members = quote! {{
407                 let members: [clap::Id; 0] = [];
408                 members
409             }};
410         }
411 
412         let group_methods = parent_item.group_methods();
413 
414         quote!(
415             .group(
416                 clap::ArgGroup::new(#group_id)
417                     .multiple(true)
418                     #group_methods
419                     .args(#literal_group_members)
420             )
421         )
422     };
423     Ok(quote! {{
424         #deprecations
425         let #app_var = #app_var
426             #initial_app_methods
427             #group_app_methods
428             ;
429         #( #args )*
430         #app_var #final_app_methods
431     }})
432 }
433 
gen_constructor(fields: &[(&Field, Item)]) -> Result<TokenStream, syn::Error>434 pub fn gen_constructor(fields: &[(&Field, Item)]) -> Result<TokenStream, syn::Error> {
435     let fields = fields.iter().map(|(field, item)| {
436         let field_name = field.ident.as_ref().unwrap();
437         let kind = item.kind();
438         let arg_matches = format_ident!("__clap_arg_matches");
439         let genned = match &*kind {
440             Kind::Command(_)
441             | Kind::Value
442             | Kind::ExternalSubcommand => {
443                 abort! { kind.span(),
444                     "`{}` cannot be used with `arg`",
445                     kind.name(),
446                 }
447             }
448             Kind::Subcommand(ty) => {
449                 let subcmd_type = match (**ty, sub_type(&field.ty)) {
450                     (Ty::Option, Some(sub_type)) => sub_type,
451                     _ => &field.ty,
452                 };
453                 match **ty {
454                     Ty::Option => {
455                         quote_spanned! { kind.span()=>
456                             #field_name: {
457                                 if #arg_matches.subcommand_name().map(<#subcmd_type as clap::Subcommand>::has_subcommand).unwrap_or(false) {
458                                     Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?)
459                                 } else {
460                                     None
461                                 }
462                             }
463                         }
464                     },
465                     Ty::Other => {
466                         quote_spanned! { kind.span()=>
467                             #field_name: {
468                                 <#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?
469                             }
470                         }
471                     },
472                     Ty::Unit |
473                     Ty::Vec |
474                     Ty::OptionOption |
475                     Ty::OptionVec |
476                     Ty::VecVec |
477                     Ty::OptionVecVec => {
478                         abort!(
479                             ty.span(),
480                             "{} types are not supported for subcommand",
481                             ty.as_str()
482                         );
483                     }
484                 }
485             }
486 
487             Kind::Flatten(ty) => {
488                 let inner_type = match (**ty, sub_type(&field.ty)) {
489                     (Ty::Option, Some(sub_type)) => sub_type,
490                     _ => &field.ty,
491                 };
492                 match **ty {
493                     Ty::Other => {
494                         quote_spanned! { kind.span()=>
495                             #field_name: <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?
496                         }
497                     },
498                     Ty::Option => {
499                         quote_spanned! { kind.span()=>
500                             #field_name: {
501                                 let group_id = <#inner_type as clap::Args>::group_id()
502                                     .expect("`#[arg(flatten)]`ed field type implements `Args::group_id`");
503                                 if #arg_matches.contains_id(group_id.as_str()) {
504                                     Some(
505                                         <#inner_type as clap::FromArgMatches>::from_arg_matches_mut(#arg_matches)?
506                                     )
507                                 } else {
508                                     None
509                                 }
510                             }
511                         }
512                     },
513                     Ty::Unit |
514                     Ty::Vec |
515                     Ty::OptionOption |
516                     Ty::OptionVec |
517                     Ty::VecVec |
518                     Ty::OptionVecVec => {
519                         abort!(
520                             ty.span(),
521                             "{} types are not supported for flatten",
522                             ty.as_str()
523                         );
524                     }
525                 }
526             },
527 
528             Kind::Skip(val, _) => match val {
529                 None => quote_spanned!(kind.span()=> #field_name: Default::default()),
530                 Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
531             },
532 
533             Kind::Arg(ty) | Kind::FromGlobal(ty) => {
534                 gen_parsers(item, ty, field_name, field, None)?
535             }
536         };
537         Ok(genned)
538     }).collect::<Result<Vec<_>, syn::Error>>()?;
539 
540     Ok(quote! {{
541         #( #fields ),*
542     }})
543 }
544 
gen_updater(fields: &[(&Field, Item)], use_self: bool) -> Result<TokenStream, syn::Error>545 pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> Result<TokenStream, syn::Error> {
546     let mut genned_fields = Vec::new();
547     for (field, item) in fields {
548         let field_name = field.ident.as_ref().unwrap();
549         let kind = item.kind();
550 
551         let access = if use_self {
552             quote! {
553                 #[allow(non_snake_case)]
554                 let #field_name = &mut self.#field_name;
555             }
556         } else {
557             quote!()
558         };
559         let arg_matches = format_ident!("__clap_arg_matches");
560 
561         let genned = match &*kind {
562             Kind::Command(_) | Kind::Value | Kind::ExternalSubcommand => {
563                 abort! { kind.span(),
564                     "`{}` cannot be used with `arg`",
565                     kind.name(),
566                 }
567             }
568             Kind::Subcommand(ty) => {
569                 let subcmd_type = match (**ty, sub_type(&field.ty)) {
570                     (Ty::Option, Some(sub_type)) => sub_type,
571                     _ => &field.ty,
572                 };
573 
574                 let updater = quote_spanned! { ty.span()=>
575                     <#subcmd_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?;
576                 };
577 
578                 let updater = match **ty {
579                     Ty::Option => quote_spanned! { kind.span()=>
580                         if let Some(#field_name) = #field_name.as_mut() {
581                             #updater
582                         } else {
583                             *#field_name = Some(<#subcmd_type as clap::FromArgMatches>::from_arg_matches_mut(
584                                 #arg_matches
585                             )?);
586                         }
587                     },
588                     _ => quote_spanned! { kind.span()=>
589                         #updater
590                     },
591                 };
592 
593                 quote_spanned! { kind.span()=>
594                     {
595                         #access
596                         #updater
597                     }
598                 }
599             }
600 
601             Kind::Flatten(ty) => {
602                 let inner_type = match (**ty, sub_type(&field.ty)) {
603                     (Ty::Option, Some(sub_type)) => sub_type,
604                     _ => &field.ty,
605                 };
606 
607                 let updater = quote_spanned! { ty.span()=>
608                     <#inner_type as clap::FromArgMatches>::update_from_arg_matches_mut(#field_name, #arg_matches)?;
609                 };
610 
611                 let updater = match **ty {
612                     Ty::Option => quote_spanned! { kind.span()=>
613                         if let Some(#field_name) = #field_name.as_mut() {
614                             #updater
615                         } else {
616                             *#field_name = Some(<#inner_type as clap::FromArgMatches>::from_arg_matches_mut(
617                                 #arg_matches
618                             )?);
619                         }
620                     },
621                     _ => quote_spanned! { kind.span()=>
622                         #updater
623                     },
624                 };
625 
626                 quote_spanned! { kind.span()=>
627                     {
628                         #access
629                         #updater
630                     }
631                 }
632             }
633 
634             Kind::Skip(_, _) => quote!(),
635 
636             Kind::Arg(ty) | Kind::FromGlobal(ty) => {
637                 gen_parsers(item, ty, field_name, field, Some(&access))?
638             }
639         };
640         genned_fields.push(genned);
641     }
642 
643     Ok(quote! {
644         #( #genned_fields )*
645     })
646 }
647 
gen_parsers( item: &Item, ty: &Sp<Ty>, field_name: &Ident, field: &Field, update: Option<&TokenStream>, ) -> Result<TokenStream, syn::Error>648 fn gen_parsers(
649     item: &Item,
650     ty: &Sp<Ty>,
651     field_name: &Ident,
652     field: &Field,
653     update: Option<&TokenStream>,
654 ) -> Result<TokenStream, syn::Error> {
655     let span = ty.span();
656     let convert_type = inner_type(&field.ty);
657     let id = item.id();
658     let get_one = quote_spanned!(span=> remove_one::<#convert_type>);
659     let get_many = quote_spanned!(span=> remove_many::<#convert_type>);
660     let get_occurrences = quote_spanned!(span=> remove_occurrences::<#convert_type>);
661 
662     // Give this identifier the same hygiene
663     // as the `arg_matches` parameter definition. This
664     // allows us to refer to `arg_matches` within a `quote_spanned` block
665     let arg_matches = format_ident!("__clap_arg_matches");
666 
667     let field_value = match **ty {
668         Ty::Unit => {
669             quote_spanned! { ty.span()=>
670                 ()
671             }
672         }
673 
674         Ty::Option => {
675             quote_spanned! { ty.span()=>
676                 #arg_matches.#get_one(#id)
677             }
678         }
679 
680         Ty::OptionOption => quote_spanned! { ty.span()=>
681             if #arg_matches.contains_id(#id) {
682                 Some(
683                     #arg_matches.#get_one(#id)
684                 )
685             } else {
686                 None
687             }
688         },
689 
690         Ty::OptionVec => quote_spanned! { ty.span()=>
691             if #arg_matches.contains_id(#id) {
692                 Some(#arg_matches.#get_many(#id)
693                     .map(|v| v.collect::<Vec<_>>())
694                     .unwrap_or_else(Vec::new))
695             } else {
696                 None
697             }
698         },
699 
700         Ty::Vec => {
701             quote_spanned! { ty.span()=>
702                 #arg_matches.#get_many(#id)
703                     .map(|v| v.collect::<Vec<_>>())
704                     .unwrap_or_else(Vec::new)
705             }
706         }
707 
708         Ty::VecVec => quote_spanned! { ty.span()=>
709             #arg_matches.#get_occurrences(#id)
710                 .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>())
711                 .unwrap_or_else(Vec::new)
712         },
713 
714         Ty::OptionVecVec => quote_spanned! { ty.span()=>
715             #arg_matches.#get_occurrences(#id)
716                 .map(|g| g.map(::std::iter::Iterator::collect).collect::<Vec<Vec<_>>>())
717         },
718 
719         Ty::Other => {
720             quote_spanned! { ty.span()=>
721                 #arg_matches.#get_one(#id)
722                     .ok_or_else(|| clap::Error::raw(clap::error::ErrorKind::MissingRequiredArgument, concat!("The following required argument was not provided: ", #id)))?
723             }
724         }
725     };
726 
727     let genned = if let Some(access) = update {
728         quote_spanned! { field.span()=>
729             if #arg_matches.contains_id(#id) {
730                 #access
731                 *#field_name = #field_value
732             }
733         }
734     } else {
735         quote_spanned!(field.span()=> #field_name: #field_value )
736     };
737     Ok(genned)
738 }
739 
740 #[cfg(feature = "raw-deprecated")]
raw_deprecated() -> TokenStream741 pub fn raw_deprecated() -> TokenStream {
742     quote! {}
743 }
744 
745 #[cfg(not(feature = "raw-deprecated"))]
raw_deprecated() -> TokenStream746 pub fn raw_deprecated() -> TokenStream {
747     quote! {
748         #![allow(deprecated)]  // Assuming any deprecation in here will be related to a deprecation in `Args`
749 
750     }
751 }
752 
collect_args_fields<'a>( item: &'a Item, fields: &'a FieldsNamed, ) -> Result<Vec<(&'a Field, Item)>, syn::Error>753 pub fn collect_args_fields<'a>(
754     item: &'a Item,
755     fields: &'a FieldsNamed,
756 ) -> Result<Vec<(&'a Field, Item)>, syn::Error> {
757     fields
758         .named
759         .iter()
760         .map(|field| {
761             let item = Item::from_args_field(field, item.casing(), item.env_casing())?;
762             Ok((field, item))
763         })
764         .collect()
765 }
766