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