]> git.proxmox.com Git - rustc.git/blame - vendor/structopt-derive/src/lib.rs
Update upstream source from tag 'upstream/1.52.1+dfsg1'
[rustc.git] / vendor / structopt-derive / src / lib.rs
CommitLineData
f20569fa
XL
1// Copyright 2018 Guillaume Pinot (@TeXitoi) <texitoi@texitoi.eu>
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! This crate is custom derive for `StructOpt`. It should not be used
10//! directly. See [structopt documentation](https://docs.rs/structopt)
11//! for the usage of `#[derive(StructOpt)]`.
12
13#![allow(clippy::large_enum_variant)]
14
15extern crate proc_macro;
16
17mod attrs;
18mod doc_comments;
19mod parse;
20mod spanned;
21mod ty;
22
23use crate::{
24 attrs::{Attrs, CasingStyle, Kind, Name, ParserKind},
25 spanned::Sp,
26 ty::{is_simple_ty, sub_type, subty_if_name, Ty},
27};
28
29use proc_macro2::{Span, TokenStream};
30use proc_macro_error::{abort, abort_call_site, proc_macro_error, set_dummy};
31use quote::{format_ident, quote, quote_spanned};
32use syn::{punctuated::Punctuated, spanned::Spanned, token::Comma, *};
33
34/// Default casing style for generated arguments.
35const DEFAULT_CASING: CasingStyle = CasingStyle::Kebab;
36
37/// Default casing style for environment variables
38const DEFAULT_ENV_CASING: CasingStyle = CasingStyle::ScreamingSnake;
39
40/// Output for the `gen_xxx()` methods were we need more than a simple stream of tokens.
41///
42/// The output of a generation method is not only the stream of new tokens but also the attribute
43/// information of the current element. These attribute information may contain valuable information
44/// for any kind of child arguments.
45struct GenOutput {
46 tokens: TokenStream,
47 attrs: Attrs,
48}
49
50/// Generates the `StructOpt` impl.
51#[proc_macro_derive(StructOpt, attributes(structopt))]
52#[proc_macro_error]
53pub fn structopt(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
54 let input: DeriveInput = syn::parse(input).unwrap();
55 let gen = impl_structopt(&input);
56 gen.into()
57}
58
59/// Generate a block of code to add arguments/subcommands corresponding to
60/// the `fields` to an app.
61fn gen_augmentation(
62 fields: &Punctuated<Field, Comma>,
63 app_var: &Ident,
64 parent_attribute: &Attrs,
65) -> TokenStream {
66 let mut subcmds = fields.iter().filter_map(|field| {
67 let attrs = Attrs::from_field(
68 field,
69 Some(parent_attribute),
70 parent_attribute.casing(),
71 parent_attribute.env_casing(),
72 );
73 let kind = attrs.kind();
74 if let Kind::Subcommand(ty) = &*kind {
75 let subcmd_type = match (**ty, sub_type(&field.ty)) {
76 (Ty::Option, Some(sub_type)) => sub_type,
77 _ => &field.ty,
78 };
79 let required = if **ty == Ty::Option {
80 quote!()
81 } else {
82 quote_spanned! { kind.span()=>
83 let #app_var = #app_var.setting(
84 ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
85 );
86 }
87 };
88
89 let span = field.span();
90 let ts = quote! {
91 let #app_var = <#subcmd_type as ::structopt::StructOptInternal>::augment_clap(
92 #app_var
93 );
94 #required
95 };
96 Some((span, ts))
97 } else {
98 None
99 }
100 });
101
102 let subcmd = subcmds.next().map(|(_, ts)| ts);
103 if let Some((span, _)) = subcmds.next() {
104 abort!(
105 span,
106 "multiple subcommand sets are not allowed, that's the second"
107 );
108 }
109
110 let args = fields.iter().filter_map(|field| {
111 let attrs = Attrs::from_field(
112 field,
113 Some(parent_attribute),
114 parent_attribute.casing(),
115 parent_attribute.env_casing(),
116 );
117 let kind = attrs.kind();
118 match &*kind {
119 Kind::ExternalSubcommand => abort!(
120 kind.span(),
121 "`external_subcommand` is only allowed on enum variants"
122 ),
123 Kind::Subcommand(_) | Kind::Skip(_) => None,
124 Kind::Flatten => {
125 let ty = &field.ty;
126 Some(quote_spanned! { kind.span()=>
127 let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(#app_var);
128 let #app_var = if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
129 #app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp)
130 } else {
131 #app_var
132 };
133 })
134 }
135 Kind::Arg(ty) => {
136 let convert_type = match **ty {
137 Ty::Vec | Ty::Option => sub_type(&field.ty).unwrap_or(&field.ty),
138 Ty::OptionOption | Ty::OptionVec => {
139 sub_type(&field.ty).and_then(sub_type).unwrap_or(&field.ty)
140 }
141 _ => &field.ty,
142 };
143
144 let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
145 let flag = *attrs.parser().kind == ParserKind::FromFlag;
146
147 let parser = attrs.parser();
148 let func = &parser.func;
149 let validator = match *parser.kind {
150 ParserKind::TryFromStr => quote_spanned! { func.span()=>
151 .validator(|s| {
152 #func(s.as_str())
153 .map(|_: #convert_type| ())
154 .map_err(|e| e.to_string())
155 })
156 },
157 ParserKind::TryFromOsStr => quote_spanned! { func.span()=>
158 .validator_os(|s| #func(&s).map(|_: #convert_type| ()))
159 },
160 _ => quote!(),
161 };
162
163 let modifier = match **ty {
164 Ty::Bool => quote_spanned! { ty.span()=>
165 .takes_value(false)
166 .multiple(false)
167 },
168
169 Ty::Option => quote_spanned! { ty.span()=>
170 .takes_value(true)
171 .multiple(false)
172 #validator
173 },
174
175 Ty::OptionOption => quote_spanned! { ty.span()=>
176 .takes_value(true)
177 .multiple(false)
178 .min_values(0)
179 .max_values(1)
180 #validator
181 },
182
183 Ty::OptionVec => quote_spanned! { ty.span()=>
184 .takes_value(true)
185 .multiple(true)
186 .min_values(0)
187 #validator
188 },
189
190 Ty::Vec => quote_spanned! { ty.span()=>
191 .takes_value(true)
192 .multiple(true)
193 #validator
194 },
195
196 Ty::Other if occurrences => quote_spanned! { ty.span()=>
197 .takes_value(false)
198 .multiple(true)
199 },
200
201 Ty::Other if flag => quote_spanned! { ty.span()=>
202 .takes_value(false)
203 .multiple(false)
204 },
205
206 Ty::Other => {
207 let required = !attrs.has_method("default_value");
208 quote_spanned! { ty.span()=>
209 .takes_value(true)
210 .multiple(false)
211 .required(#required)
212 #validator
213 }
214 }
215 };
216
217 let name = attrs.cased_name();
218 let methods = attrs.field_methods();
219
220 Some(quote_spanned! { field.span()=>
221 let #app_var = #app_var.arg(
222 ::structopt::clap::Arg::with_name(#name)
223 #modifier
224 #methods
225 );
226 })
227 }
228 }
229 });
230
231 let app_methods = parent_attribute.top_level_methods();
232 let version = parent_attribute.version();
233 quote! {{
234 let #app_var = #app_var#app_methods;
235 #( #args )*
236 #subcmd
237 #app_var#version
238 }}
239}
240
241fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
242 // This ident is used in several match branches below,
243 // and the `quote[_spanned]` invocations have different spans.
244 //
245 // Given that this ident is used in several places and
246 // that the branches are located inside of a loop, it is possible that
247 // this ident will be given _different_ spans in different places, and
248 // thus will not be the _same_ ident anymore. To make sure the `matches`
249 // is always the same, we factor it out.
250 let matches = format_ident!("matches");
251
252 let fields = fields.iter().map(|field| {
253 let attrs = Attrs::from_field(
254 field,
255 Some(parent_attribute),
256 parent_attribute.casing(),
257 parent_attribute.env_casing(),
258 );
259 let field_name = field.ident.as_ref().unwrap();
260 let kind = attrs.kind();
261 match &*kind {
262 Kind::ExternalSubcommand => abort!(
263 kind.span(),
264 "`external_subcommand` is allowed only on enum variants"
265 ),
266
267 Kind::Subcommand(ty) => {
268 let subcmd_type = match (**ty, sub_type(&field.ty)) {
269 (Ty::Option, Some(sub_type)) => sub_type,
270 _ => &field.ty,
271 };
272 let unwrapper = match **ty {
273 Ty::Option => quote!(),
274 _ => quote_spanned!( ty.span()=> .unwrap() ),
275 };
276 quote_spanned! { kind.span()=>
277 #field_name: <#subcmd_type as ::structopt::StructOptInternal>::from_subcommand(
278 #matches.subcommand())
279 #unwrapper
280 }
281 }
282
283 Kind::Flatten => quote_spanned! { kind.span()=>
284 #field_name: ::structopt::StructOpt::from_clap(#matches)
285 },
286
287 Kind::Skip(val) => match val {
288 None => quote_spanned!(kind.span()=> #field_name: Default::default()),
289 Some(val) => quote_spanned!(kind.span()=> #field_name: (#val).into()),
290 },
291
292 Kind::Arg(ty) => {
293 use crate::attrs::ParserKind::*;
294
295 let parser = attrs.parser();
296 let func = &parser.func;
297 let span = parser.kind.span();
298 let (value_of, values_of, parse) = match *parser.kind {
299 FromStr => (
300 quote_spanned!(span=> value_of),
301 quote_spanned!(span=> values_of),
302 func.clone(),
303 ),
304 TryFromStr => (
305 quote_spanned!(span=> value_of),
306 quote_spanned!(span=> values_of),
307 quote_spanned!(func.span()=> |s| #func(s).unwrap()),
308 ),
309 FromOsStr => (
310 quote_spanned!(span=> value_of_os),
311 quote_spanned!(span=> values_of_os),
312 func.clone(),
313 ),
314 TryFromOsStr => (
315 quote_spanned!(span=> value_of_os),
316 quote_spanned!(span=> values_of_os),
317 quote_spanned!(func.span()=> |s| #func(s).unwrap()),
318 ),
319 FromOccurrences => (
320 quote_spanned!(span=> occurrences_of),
321 quote!(),
322 func.clone(),
323 ),
324 FromFlag => (quote!(), quote!(), func.clone()),
325 };
326
327 let flag = *attrs.parser().kind == ParserKind::FromFlag;
328 let occurrences = *attrs.parser().kind == ParserKind::FromOccurrences;
329 let name = attrs.cased_name();
330 let field_value = match **ty {
331 Ty::Bool => quote_spanned!(ty.span()=> #matches.is_present(#name)),
332
333 Ty::Option => quote_spanned! { ty.span()=>
334 #matches.#value_of(#name)
335 .map(#parse)
336 },
337
338 Ty::OptionOption => quote_spanned! { ty.span()=>
339 if #matches.is_present(#name) {
340 Some(#matches.#value_of(#name).map(#parse))
341 } else {
342 None
343 }
344 },
345
346 Ty::OptionVec => quote_spanned! { ty.span()=>
347 if #matches.is_present(#name) {
348 Some(#matches.#values_of(#name)
349 .map_or_else(Vec::new, |v| v.map(#parse).collect()))
350 } else {
351 None
352 }
353 },
354
355 Ty::Vec => quote_spanned! { ty.span()=>
356 #matches.#values_of(#name)
357 .map_or_else(Vec::new, |v| v.map(#parse).collect())
358 },
359
360 Ty::Other if occurrences => quote_spanned! { ty.span()=>
361 #parse(#matches.#value_of(#name))
362 },
363
364 Ty::Other if flag => quote_spanned! { ty.span()=>
365 #parse(#matches.is_present(#name))
366 },
367
368 Ty::Other => quote_spanned! { ty.span()=>
369 #matches.#value_of(#name)
370 .map(#parse)
371 .unwrap()
372 },
373 };
374
375 quote_spanned!(field.span()=> #field_name: #field_value )
376 }
377 }
378 });
379
380 quote! {{
381 #( #fields ),*
382 }}
383}
384
385fn gen_from_clap(
386 struct_name: &Ident,
387 fields: &Punctuated<Field, Comma>,
388 parent_attribute: &Attrs,
389) -> TokenStream {
390 let field_block = gen_constructor(fields, parent_attribute);
391
392 quote! {
393 fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
394 #struct_name #field_block
395 }
396 }
397}
398
399fn gen_clap(attrs: &[Attribute]) -> GenOutput {
400 let name = std::env::var("CARGO_PKG_NAME").ok().unwrap_or_default();
401
402 let attrs = Attrs::from_struct(
403 Span::call_site(),
404 attrs,
405 Name::Assigned(quote!(#name)),
406 None,
407 Sp::call_site(DEFAULT_CASING),
408 Sp::call_site(DEFAULT_ENV_CASING),
409 );
410 let tokens = {
411 let name = attrs.cased_name();
412 quote!(::structopt::clap::App::new(#name))
413 };
414
415 GenOutput { tokens, attrs }
416}
417
418fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput {
419 let initial_clap_app_gen = gen_clap(struct_attrs);
420 let clap_tokens = initial_clap_app_gen.tokens;
421
422 let augmented_tokens = quote! {
423 fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
424 let app = #clap_tokens;
425 <Self as ::structopt::StructOptInternal>::augment_clap(app)
426 }
427 };
428
429 GenOutput {
430 tokens: augmented_tokens,
431 attrs: initial_clap_app_gen.attrs,
432 }
433}
434
435fn gen_augment_clap(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs) -> TokenStream {
436 let app_var = Ident::new("app", Span::call_site());
437 let augmentation = gen_augmentation(fields, &app_var, parent_attribute);
438 quote! {
439 fn augment_clap<'a, 'b>(
440 #app_var: ::structopt::clap::App<'a, 'b>
441 ) -> ::structopt::clap::App<'a, 'b> {
442 #augmentation
443 }
444 }
445}
446
447fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput {
448 let initial_clap_app_gen = gen_clap(enum_attrs);
449 let clap_tokens = initial_clap_app_gen.tokens;
450
451 let tokens = quote! {
452 fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
453 let app = #clap_tokens
454 .setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp);
455 <Self as ::structopt::StructOptInternal>::augment_clap(app)
456 }
457 };
458
459 GenOutput {
460 tokens,
461 attrs: initial_clap_app_gen.attrs,
462 }
463}
464
465fn gen_augment_clap_enum(
466 variants: &Punctuated<Variant, Comma>,
467 parent_attribute: &Attrs,
468) -> TokenStream {
469 use syn::Fields::*;
470
471 let subcommands = variants.iter().map(|variant| {
472 let attrs = Attrs::from_struct(
473 variant.span(),
474 &variant.attrs,
475 Name::Derived(variant.ident.clone()),
476 Some(parent_attribute),
477 parent_attribute.casing(),
478 parent_attribute.env_casing(),
479 );
480
481 let kind = attrs.kind();
482 match &*kind {
483 Kind::ExternalSubcommand => {
484 quote_spanned! { attrs.kind().span()=>
485 let app = app.setting(
486 ::structopt::clap::AppSettings::AllowExternalSubcommands
487 );
488 }
489 },
490
491 Kind::Flatten => {
492 match variant.fields {
493 Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
494 let ty = &unnamed[0];
495 quote! {
496 let app = <#ty as ::structopt::StructOptInternal>::augment_clap(app);
497 }
498 },
499 _ => abort!(
500 variant,
501 "`flatten` is usable only with single-typed tuple variants"
502 ),
503 }
504 },
505
506 _ => {
507 let app_var = Ident::new("subcommand", Span::call_site());
508 let arg_block = match variant.fields {
509 Named(ref fields) => gen_augmentation(&fields.named, &app_var, &attrs),
510 Unit => quote!( #app_var ),
511 Unnamed(FieldsUnnamed { ref unnamed, .. }) if unnamed.len() == 1 => {
512 let ty = &unnamed[0];
513 quote_spanned! { ty.span()=>
514 {
515 let #app_var = <#ty as ::structopt::StructOptInternal>::augment_clap(
516 #app_var
517 );
518 if <#ty as ::structopt::StructOptInternal>::is_subcommand() {
519 #app_var.setting(
520 ::structopt::clap::AppSettings::SubcommandRequiredElseHelp
521 )
522 } else {
523 #app_var
524 }
525 }
526 }
527 }
528 Unnamed(..) => abort!(variant, "non single-typed tuple enums are not supported"),
529 };
530
531 let name = attrs.cased_name();
532 let from_attrs = attrs.top_level_methods();
533 let version = attrs.version();
534 quote! {
535 let app = app.subcommand({
536 let #app_var = ::structopt::clap::SubCommand::with_name(#name);
537 let #app_var = #arg_block;
538 #app_var#from_attrs#version
539 });
540 }
541 },
542 }
543 });
544
545 let app_methods = parent_attribute.top_level_methods();
546 let version = parent_attribute.version();
547 quote! {
548 fn augment_clap<'a, 'b>(
549 app: ::structopt::clap::App<'a, 'b>
550 ) -> ::structopt::clap::App<'a, 'b> {
551 let app = app #app_methods;
552 #( #subcommands )*;
553 app #version
554 }
555 }
556}
557
558fn gen_from_clap_enum(name: &Ident) -> TokenStream {
559 quote! {
560 fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
561 <#name as ::structopt::StructOptInternal>::from_subcommand(matches.subcommand())
562 .expect("structopt misuse: You likely tried to #[flatten] a struct \
563 that contains #[subcommand]. This is forbidden.")
564 }
565 }
566}
567
568fn gen_from_subcommand(
569 name: &Ident,
570 variants: &Punctuated<Variant, Comma>,
571 parent_attribute: &Attrs,
572) -> TokenStream {
573 use syn::Fields::*;
574
575 let mut ext_subcmd = None;
576
577 let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
578 .iter()
579 .filter_map(|variant| {
580 let attrs = Attrs::from_struct(
581 variant.span(),
582 &variant.attrs,
583 Name::Derived(variant.ident.clone()),
584 Some(parent_attribute),
585 parent_attribute.casing(),
586 parent_attribute.env_casing(),
587 );
588
589 let variant_name = &variant.ident;
590
591 if let Kind::ExternalSubcommand = *attrs.kind() {
592 if ext_subcmd.is_some() {
593 abort!(
594 attrs.kind().span(),
595 "Only one variant can be marked with `external_subcommand`, \
596 this is the second"
597 );
598 }
599
600 let ty = match variant.fields {
601 Unnamed(ref fields) if fields.unnamed.len() == 1 => &fields.unnamed[0].ty,
602
603 _ => abort!(
604 variant,
605 "The enum variant marked with `external_attribute` must be \
606 a single-typed tuple, and the type must be either `Vec<String>` \
607 or `Vec<OsString>`."
608 ),
609 };
610
611 let (span, str_ty, values_of) = match subty_if_name(ty, "Vec") {
612 Some(subty) => {
613 if is_simple_ty(subty, "String") {
614 (
615 subty.span(),
616 quote!(::std::string::String),
617 quote!(values_of),
618 )
619 } else {
620 (
621 subty.span(),
622 quote!(::std::ffi::OsString),
623 quote!(values_of_os),
624 )
625 }
626 }
627
628 None => abort!(
629 ty,
630 "The type must be either `Vec<String>` or `Vec<OsString>` \
631 to be used with `external_subcommand`."
632 ),
633 };
634
635 ext_subcmd = Some((span, variant_name, str_ty, values_of));
636 None
637 } else {
638 Some((variant, attrs))
639 }
640 })
641 .partition(|(_, attrs)| match &*attrs.kind() {
642 Kind::Flatten => true,
643 _ => false,
644 });
645
646 let external = match ext_subcmd {
647 Some((span, var_name, str_ty, values_of)) => quote_spanned! { span=>
648 match other {
649 ("", ::std::option::Option::None) => None,
650
651 (external, Some(matches)) => {
652 ::std::option::Option::Some(#name::#var_name(
653 ::std::iter::once(#str_ty::from(external))
654 .chain(
655 matches.#values_of("").into_iter().flatten().map(#str_ty::from)
656 )
657 .collect::<::std::vec::Vec<_>>()
658 ))
659 }
660
661 (external, None) => {
662 ::std::option::Option::Some(#name::#var_name(
663 ::std::iter::once(#str_ty::from(external))
664 .collect::<::std::vec::Vec<_>>()
665 ))
666 }
667 }
668 },
669
670 None => quote!(None),
671 };
672
673 let match_arms = variants.iter().map(|(variant, attrs)| {
674 let sub_name = attrs.cased_name();
675 let variant_name = &variant.ident;
676 let constructor_block = match variant.fields {
677 Named(ref fields) => gen_constructor(&fields.named, &attrs),
678 Unit => quote!(),
679 Unnamed(ref fields) if fields.unnamed.len() == 1 => {
680 let ty = &fields.unnamed[0];
681 quote!( ( <#ty as ::structopt::StructOpt>::from_clap(matches) ) )
682 }
683 Unnamed(..) => abort!(
684 variant.ident,
685 "non single-typed tuple enums are not supported"
686 ),
687 };
688
689 quote! {
690 (#sub_name, Some(matches)) => {
691 Some(#name :: #variant_name #constructor_block)
692 }
693 }
694 });
695
696 let child_subcommands = flatten_variants.iter().map(|(variant, _attrs)| {
697 let variant_name = &variant.ident;
698 match variant.fields {
699 Unnamed(ref fields) if fields.unnamed.len() == 1 => {
700 let ty = &fields.unnamed[0];
701 quote! {
702 if let Some(res) =
703 <#ty as ::structopt::StructOptInternal>::from_subcommand(other)
704 {
705 return Some(#name :: #variant_name (res));
706 }
707 }
708 }
709 _ => abort!(
710 variant,
711 "`flatten` is usable only with single-typed tuple variants"
712 ),
713 }
714 });
715
716 quote! {
717 fn from_subcommand<'a, 'b>(
718 sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>)
719 ) -> Option<Self> {
720 match sub {
721 #( #match_arms, )*
722 other => {
723 #( #child_subcommands )else*;
724 #external
725 }
726 }
727 }
728 }
729}
730
731#[cfg(feature = "paw")]
732fn gen_paw_impl(name: &Ident) -> TokenStream {
733 quote! {
734 impl ::structopt::paw::ParseArgs for #name {
735 type Error = std::io::Error;
736
737 fn parse_args() -> std::result::Result<Self, Self::Error> {
738 Ok(<#name as ::structopt::StructOpt>::from_args())
739 }
740 }
741 }
742}
743#[cfg(not(feature = "paw"))]
744fn gen_paw_impl(_: &Ident) -> TokenStream {
745 TokenStream::new()
746}
747
748fn impl_structopt_for_struct(
749 name: &Ident,
750 fields: &Punctuated<Field, Comma>,
751 attrs: &[Attribute],
752) -> TokenStream {
753 let basic_clap_app_gen = gen_clap_struct(attrs);
754 let augment_clap = gen_augment_clap(fields, &basic_clap_app_gen.attrs);
755 let from_clap = gen_from_clap(name, fields, &basic_clap_app_gen.attrs);
756 let paw_impl = gen_paw_impl(name);
757
758 let clap_tokens = basic_clap_app_gen.tokens;
759 quote! {
760 #[allow(unused_variables)]
761 #[allow(unknown_lints)]
762 #[allow(
763 clippy::style,
764 clippy::complexity,
765 clippy::pedantic,
766 clippy::restriction,
767 clippy::perf,
768 clippy::deprecated,
769 clippy::nursery,
770 clippy::cargo
771 )]
772 #[deny(clippy::correctness)]
773 #[allow(dead_code, unreachable_code)]
774 impl ::structopt::StructOpt for #name {
775 #clap_tokens
776 #from_clap
777 }
778
779 #[allow(unused_variables)]
780 #[allow(unknown_lints)]
781 #[allow(
782 clippy::style,
783 clippy::complexity,
784 clippy::pedantic,
785 clippy::restriction,
786 clippy::perf,
787 clippy::deprecated,
788 clippy::nursery,
789 clippy::cargo
790 )]
791 #[deny(clippy::correctness)]
792 #[allow(dead_code, unreachable_code)]
793 impl ::structopt::StructOptInternal for #name {
794 #augment_clap
795 fn is_subcommand() -> bool { false }
796 }
797
798 #paw_impl
799 }
800}
801
802fn impl_structopt_for_enum(
803 name: &Ident,
804 variants: &Punctuated<Variant, Comma>,
805 attrs: &[Attribute],
806) -> TokenStream {
807 let basic_clap_app_gen = gen_clap_enum(attrs);
808 let clap_tokens = basic_clap_app_gen.tokens;
809 let attrs = basic_clap_app_gen.attrs;
810
811 let augment_clap = gen_augment_clap_enum(variants, &attrs);
812 let from_clap = gen_from_clap_enum(name);
813 let from_subcommand = gen_from_subcommand(name, variants, &attrs);
814 let paw_impl = gen_paw_impl(name);
815
816 quote! {
817 #[allow(unknown_lints)]
818 #[allow(unused_variables, dead_code, unreachable_code)]
819 #[allow(
820 clippy::style,
821 clippy::complexity,
822 clippy::pedantic,
823 clippy::restriction,
824 clippy::perf,
825 clippy::deprecated,
826 clippy::nursery,
827 clippy::cargo
828 )]
829 #[deny(clippy::correctness)]
830 impl ::structopt::StructOpt for #name {
831 #clap_tokens
832 #from_clap
833 }
834
835 #[allow(unused_variables)]
836 #[allow(unknown_lints)]
837 #[allow(
838 clippy::style,
839 clippy::complexity,
840 clippy::pedantic,
841 clippy::restriction,
842 clippy::perf,
843 clippy::deprecated,
844 clippy::nursery,
845 clippy::cargo
846 )]
847 #[deny(clippy::correctness)]
848 #[allow(dead_code, unreachable_code)]
849 impl ::structopt::StructOptInternal for #name {
850 #augment_clap
851 #from_subcommand
852 fn is_subcommand() -> bool { true }
853 }
854
855 #paw_impl
856 }
857}
858
859fn impl_structopt(input: &DeriveInput) -> TokenStream {
860 use syn::Data::*;
861
862 let struct_name = &input.ident;
863
864 set_dummy(quote! {
865 impl ::structopt::StructOpt for #struct_name {
866 fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
867 unimplemented!()
868 }
869 fn from_clap(_matches: &::structopt::clap::ArgMatches) -> Self {
870 unimplemented!()
871 }
872 }
873
874 impl ::structopt::StructOptInternal for #struct_name {}
875 });
876
877 match input.data {
878 Struct(DataStruct {
879 fields: syn::Fields::Named(ref fields),
880 ..
881 }) => impl_structopt_for_struct(struct_name, &fields.named, &input.attrs),
882 Enum(ref e) => impl_structopt_for_enum(struct_name, &e.variants, &input.attrs),
883 _ => abort_call_site!("structopt only supports non-tuple structs and enums"),
884 }
885}