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