mirror of
https://github.com/clap-rs/clap
synced 2024-12-13 22:32:33 +00:00
perf(derive): Consolidate field/variant parsing
This commit is contained in:
parent
6e8b366107
commit
5264a62181
4 changed files with 127 additions and 121 deletions
|
@ -36,8 +36,15 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream {
|
||||||
}) => {
|
}) => {
|
||||||
let name = Name::Derived(ident.clone());
|
let name = Name::Derived(ident.clone());
|
||||||
let item = Item::from_args_struct(input, name);
|
let item = Item::from_args_struct(input, name);
|
||||||
let fields = &fields.named;
|
let fields = fields
|
||||||
gen_for_struct(&item, ident, &input.generics, fields)
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_struct(&item, ident, &input.generics, &fields)
|
||||||
}
|
}
|
||||||
Data::Struct(DataStruct {
|
Data::Struct(DataStruct {
|
||||||
fields: Fields::Unit,
|
fields: Fields::Unit,
|
||||||
|
@ -45,8 +52,15 @@ pub fn derive_args(input: &DeriveInput) -> TokenStream {
|
||||||
}) => {
|
}) => {
|
||||||
let name = Name::Derived(ident.clone());
|
let name = Name::Derived(ident.clone());
|
||||||
let item = Item::from_args_struct(input, name);
|
let item = Item::from_args_struct(input, name);
|
||||||
let fields = &Punctuated::<Field, Comma>::new();
|
let fields = Punctuated::<Field, Comma>::new();
|
||||||
gen_for_struct(&item, ident, &input.generics, fields)
|
let fields = fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_struct(&item, ident, &input.generics, &fields)
|
||||||
}
|
}
|
||||||
_ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"),
|
_ => abort_call_site!("`#[derive(Args)]` only supports non-tuple structs"),
|
||||||
}
|
}
|
||||||
|
@ -56,12 +70,12 @@ pub fn gen_for_struct(
|
||||||
item: &Item,
|
item: &Item,
|
||||||
item_name: &Ident,
|
item_name: &Ident,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
fields: &Punctuated<Field, Comma>,
|
fields: &[(&Field, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
let constructor = gen_constructor(fields, item);
|
let constructor = gen_constructor(fields);
|
||||||
let updater = gen_updater(fields, item, true);
|
let updater = gen_updater(fields, true);
|
||||||
let raw_deprecated = raw_deprecated();
|
let raw_deprecated = raw_deprecated();
|
||||||
|
|
||||||
let app_var = Ident::new("__clap_app", Span::call_site());
|
let app_var = Ident::new("__clap_app", Span::call_site());
|
||||||
|
@ -131,17 +145,12 @@ pub fn gen_for_struct(
|
||||||
/// Generate a block of code to add arguments/subcommands corresponding to
|
/// Generate a block of code to add arguments/subcommands corresponding to
|
||||||
/// the `fields` to an cmd.
|
/// the `fields` to an cmd.
|
||||||
pub fn gen_augment(
|
pub fn gen_augment(
|
||||||
fields: &Punctuated<Field, Comma>,
|
fields: &[(&Field, Item)],
|
||||||
app_var: &Ident,
|
app_var: &Ident,
|
||||||
parent_item: &Item,
|
parent_item: &Item,
|
||||||
override_required: bool,
|
override_required: bool,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let mut subcmds = fields.iter().filter_map(|field| {
|
let mut subcmds = fields.iter().filter_map(|(field, item)| {
|
||||||
let item = Item::from_args_field(
|
|
||||||
field,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
if let Kind::Subcommand(ty) = &*kind {
|
if let Kind::Subcommand(ty) = &*kind {
|
||||||
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
let subcmd_type = match (**ty, sub_type(&field.ty)) {
|
||||||
|
@ -182,12 +191,7 @@ pub fn gen_augment(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = fields.iter().filter_map(|field| {
|
let args = fields.iter().filter_map(|(field, item)| {
|
||||||
let item = Item::from_args_field(
|
|
||||||
field,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
match &*kind {
|
match &*kind {
|
||||||
Kind::Subcommand(_)
|
Kind::Subcommand(_)
|
||||||
|
@ -313,13 +317,8 @@ pub fn gen_augment(
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_item: &Item) -> TokenStream {
|
pub fn gen_constructor(fields: &[(&Field, Item)]) -> TokenStream {
|
||||||
let fields = fields.iter().map(|field| {
|
let fields = fields.iter().map(|(field, item)| {
|
||||||
let item = Item::from_args_field(
|
|
||||||
field,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
let field_name = field.ident.as_ref().unwrap();
|
let field_name = field.ident.as_ref().unwrap();
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
let arg_matches = format_ident!("__clap_arg_matches");
|
let arg_matches = format_ident!("__clap_arg_matches");
|
||||||
|
@ -366,7 +365,7 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_item: &Item) ->
|
||||||
},
|
},
|
||||||
|
|
||||||
Kind::Arg(ty) | Kind::FromGlobal(ty) => {
|
Kind::Arg(ty) | Kind::FromGlobal(ty) => {
|
||||||
gen_parsers(&item, ty, field_name, field, None)
|
gen_parsers(item, ty, field_name, field, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -376,17 +375,8 @@ pub fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_item: &Item) ->
|
||||||
}}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_updater(
|
pub fn gen_updater(fields: &[(&Field, Item)], use_self: bool) -> TokenStream {
|
||||||
fields: &Punctuated<Field, Comma>,
|
let fields = fields.iter().map(|(field, item)| {
|
||||||
parent_item: &Item,
|
|
||||||
use_self: bool,
|
|
||||||
) -> TokenStream {
|
|
||||||
let fields = fields.iter().map(|field| {
|
|
||||||
let item = Item::from_args_field(
|
|
||||||
field,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
let field_name = field.ident.as_ref().unwrap();
|
let field_name = field.ident.as_ref().unwrap();
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
|
|
||||||
|
@ -447,7 +437,7 @@ pub fn gen_updater(
|
||||||
|
|
||||||
Kind::Skip(_) => quote!(),
|
Kind::Skip(_) => quote!(),
|
||||||
|
|
||||||
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(&item, ty, field_name, field, Some(&access)),
|
Kind::Arg(ty) | Kind::FromGlobal(ty) => gen_parsers(item, ty, field_name, field, Some(&access)),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ use proc_macro2::TokenStream;
|
||||||
use proc_macro_error::abort_call_site;
|
use proc_macro_error::abort_call_site;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use syn::Ident;
|
use syn::Ident;
|
||||||
use syn::Token;
|
|
||||||
use syn::Variant;
|
use syn::Variant;
|
||||||
use syn::{
|
use syn::{
|
||||||
self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields,
|
self, punctuated::Punctuated, token::Comma, Data, DataStruct, DeriveInput, Field, Fields,
|
||||||
|
@ -42,8 +41,15 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream {
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_default()));
|
.unwrap_or_default()));
|
||||||
let item = Item::from_args_struct(input, name);
|
let item = Item::from_args_struct(input, name);
|
||||||
let fields = &fields.named;
|
let fields = fields
|
||||||
gen_for_struct(&item, ident, &input.generics, fields)
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_struct(&item, ident, &input.generics, &fields)
|
||||||
}
|
}
|
||||||
Data::Struct(DataStruct {
|
Data::Struct(DataStruct {
|
||||||
fields: Fields::Unit,
|
fields: Fields::Unit,
|
||||||
|
@ -55,8 +61,15 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream {
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_default()));
|
.unwrap_or_default()));
|
||||||
let item = Item::from_args_struct(input, name);
|
let item = Item::from_args_struct(input, name);
|
||||||
let fields = &Punctuated::<Field, Comma>::new();
|
let fields = Punctuated::<Field, Comma>::new();
|
||||||
gen_for_struct(&item, ident, &input.generics, fields)
|
let fields = fields
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_struct(&item, ident, &input.generics, &fields)
|
||||||
}
|
}
|
||||||
Data::Enum(ref e) => {
|
Data::Enum(ref e) => {
|
||||||
dummies::parser_enum(ident);
|
dummies::parser_enum(ident);
|
||||||
|
@ -65,8 +78,16 @@ pub fn derive_parser(input: &DeriveInput) -> TokenStream {
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or_default()));
|
.unwrap_or_default()));
|
||||||
let item = Item::from_subcommand_enum(input, name);
|
let item = Item::from_subcommand_enum(input, name);
|
||||||
let variants = &e.variants;
|
let variants = e
|
||||||
gen_for_enum(&item, ident, &input.generics, variants)
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|variant| {
|
||||||
|
let item =
|
||||||
|
Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
|
||||||
|
(variant, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_enum(&item, ident, &input.generics, &variants)
|
||||||
}
|
}
|
||||||
_ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
|
_ => abort_call_site!("`#[derive(Parser)]` only supports non-tuple structs and enums"),
|
||||||
}
|
}
|
||||||
|
@ -76,7 +97,7 @@ fn gen_for_struct(
|
||||||
item: &Item,
|
item: &Item,
|
||||||
item_name: &Ident,
|
item_name: &Ident,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
fields: &Punctuated<Field, Comma>,
|
fields: &[(&Field, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
|
@ -95,7 +116,7 @@ fn gen_for_enum(
|
||||||
item: &Item,
|
item: &Item,
|
||||||
item_name: &Ident,
|
item_name: &Ident,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
variants: &[(&Variant, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,7 @@
|
||||||
use proc_macro2::{Ident, Span, TokenStream};
|
use proc_macro2::{Ident, Span, TokenStream};
|
||||||
use proc_macro_error::{abort, abort_call_site};
|
use proc_macro_error::{abort, abort_call_site};
|
||||||
use quote::{format_ident, quote, quote_spanned};
|
use quote::{format_ident, quote, quote_spanned};
|
||||||
use syn::{
|
use syn::{spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Variant};
|
||||||
punctuated::Punctuated, spanned::Spanned, Data, DeriveInput, FieldsUnnamed, Generics, Token,
|
|
||||||
Variant,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::derives::args;
|
use crate::derives::args;
|
||||||
use crate::dummies;
|
use crate::dummies;
|
||||||
|
@ -34,8 +31,16 @@ pub fn derive_subcommand(input: &DeriveInput) -> TokenStream {
|
||||||
Data::Enum(ref e) => {
|
Data::Enum(ref e) => {
|
||||||
let name = Name::Derived(ident.clone());
|
let name = Name::Derived(ident.clone());
|
||||||
let item = Item::from_subcommand_enum(input, name);
|
let item = Item::from_subcommand_enum(input, name);
|
||||||
let variants = &e.variants;
|
let variants = e
|
||||||
gen_for_enum(&item, ident, &input.generics, variants)
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|variant| {
|
||||||
|
let item =
|
||||||
|
Item::from_subcommand_variant(variant, item.casing(), item.env_casing());
|
||||||
|
(variant, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_enum(&item, ident, &input.generics, &variants)
|
||||||
}
|
}
|
||||||
_ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
|
_ => abort_call_site!("`#[derive(Subcommand)]` only supports enums"),
|
||||||
}
|
}
|
||||||
|
@ -45,16 +50,16 @@ pub fn gen_for_enum(
|
||||||
item: &Item,
|
item: &Item,
|
||||||
item_name: &Ident,
|
item_name: &Ident,
|
||||||
generics: &Generics,
|
generics: &Generics,
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
variants: &[(&Variant, Item)],
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
|
||||||
|
|
||||||
let from_arg_matches = gen_from_arg_matches(variants, item);
|
let from_arg_matches = gen_from_arg_matches(variants);
|
||||||
let update_from_arg_matches = gen_update_from_arg_matches(variants, item);
|
let update_from_arg_matches = gen_update_from_arg_matches(variants);
|
||||||
|
|
||||||
let augmentation = gen_augment(variants, item, false);
|
let augmentation = gen_augment(variants, item, false);
|
||||||
let augmentation_update = gen_augment(variants, item, true);
|
let augmentation_update = gen_augment(variants, item, true);
|
||||||
let has_subcommand = gen_has_subcommand(variants, item);
|
let has_subcommand = gen_has_subcommand(variants);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
|
#[allow(dead_code, unreachable_code, unused_variables, unused_braces)]
|
||||||
|
@ -111,7 +116,7 @@ pub fn gen_for_enum(
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_augment(
|
fn gen_augment(
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
variants: &[(&Variant, Item)],
|
||||||
parent_item: &Item,
|
parent_item: &Item,
|
||||||
override_required: bool,
|
override_required: bool,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
|
@ -121,12 +126,7 @@ fn gen_augment(
|
||||||
|
|
||||||
let subcommands: Vec<_> = variants
|
let subcommands: Vec<_> = variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|(variant, item)| {
|
||||||
let item = Item::from_subcommand_variant(
|
|
||||||
variant,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
let kind = item.kind();
|
let kind = item.kind();
|
||||||
|
|
||||||
match &*kind {
|
match &*kind {
|
||||||
|
@ -238,7 +238,15 @@ fn gen_augment(
|
||||||
let sub_augment = match variant.fields {
|
let sub_augment = match variant.fields {
|
||||||
Named(ref fields) => {
|
Named(ref fields) => {
|
||||||
// Defer to `gen_augment` for adding cmd methods
|
// Defer to `gen_augment` for adding cmd methods
|
||||||
args::gen_augment(&fields.named, &subcommand_var, &item, override_required)
|
let fields = fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
args::gen_augment(&fields, &subcommand_var, item, override_required)
|
||||||
}
|
}
|
||||||
Unit => {
|
Unit => {
|
||||||
let arg_block = quote!( #subcommand_var );
|
let arg_block = quote!( #subcommand_var );
|
||||||
|
@ -300,23 +308,14 @@ fn gen_augment(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_has_subcommand(
|
fn gen_has_subcommand(variants: &[(&Variant, Item)]) -> TokenStream {
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
|
||||||
parent_item: &Item,
|
|
||||||
) -> TokenStream {
|
|
||||||
use syn::Fields::*;
|
use syn::Fields::*;
|
||||||
|
|
||||||
let mut ext_subcmd = false;
|
let mut ext_subcmd = false;
|
||||||
|
|
||||||
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
|
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|(variant, item)| {
|
||||||
let item = Item::from_subcommand_variant(
|
|
||||||
variant,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Kind::ExternalSubcommand = &*item.kind() {
|
if let Kind::ExternalSubcommand = &*item.kind() {
|
||||||
ext_subcmd = true;
|
ext_subcmd = true;
|
||||||
None
|
None
|
||||||
|
@ -367,10 +366,7 @@ fn gen_has_subcommand(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_from_arg_matches(
|
fn gen_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
|
||||||
parent_item: &Item,
|
|
||||||
) -> TokenStream {
|
|
||||||
use syn::Fields::*;
|
use syn::Fields::*;
|
||||||
|
|
||||||
let mut ext_subcmd = None;
|
let mut ext_subcmd = None;
|
||||||
|
@ -379,13 +375,7 @@ fn gen_from_arg_matches(
|
||||||
let sub_arg_matches_var = format_ident!("__clap_arg_matches");
|
let sub_arg_matches_var = format_ident!("__clap_arg_matches");
|
||||||
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
|
let (flatten_variants, variants): (Vec<_>, Vec<_>) = variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|(variant, item)| {
|
||||||
let item = Item::from_subcommand_variant(
|
|
||||||
variant,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
|
|
||||||
if let Kind::ExternalSubcommand = &*item.kind() {
|
if let Kind::ExternalSubcommand = &*item.kind() {
|
||||||
if ext_subcmd.is_some() {
|
if ext_subcmd.is_some() {
|
||||||
abort!(
|
abort!(
|
||||||
|
@ -443,7 +433,17 @@ fn gen_from_arg_matches(
|
||||||
let sub_name = item.cased_name();
|
let sub_name = item.cased_name();
|
||||||
let variant_name = &variant.ident;
|
let variant_name = &variant.ident;
|
||||||
let constructor_block = match variant.fields {
|
let constructor_block = match variant.fields {
|
||||||
Named(ref fields) => args::gen_constructor(&fields.named, item),
|
Named(ref fields) => {
|
||||||
|
let fields = fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
args::gen_constructor(&fields)
|
||||||
|
},
|
||||||
Unit => quote!(),
|
Unit => quote!(),
|
||||||
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
Unnamed(ref fields) if fields.unnamed.len() == 1 => {
|
||||||
let ty = &fields.unnamed[0];
|
let ty = &fields.unnamed[0];
|
||||||
|
@ -519,21 +519,12 @@ fn gen_from_arg_matches(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_update_from_arg_matches(
|
fn gen_update_from_arg_matches(variants: &[(&Variant, Item)]) -> TokenStream {
|
||||||
variants: &Punctuated<Variant, Token![,]>,
|
|
||||||
parent_item: &Item,
|
|
||||||
) -> TokenStream {
|
|
||||||
use syn::Fields::*;
|
use syn::Fields::*;
|
||||||
|
|
||||||
let (flatten, variants): (Vec<_>, Vec<_>) = variants
|
let (flatten, variants): (Vec<_>, Vec<_>) = variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|(variant, item)| {
|
||||||
let item = Item::from_subcommand_variant(
|
|
||||||
variant,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
|
|
||||||
match &*item.kind() {
|
match &*item.kind() {
|
||||||
// Fallback to `from_arg_matches_mut`
|
// Fallback to `from_arg_matches_mut`
|
||||||
Kind::ExternalSubcommand => None,
|
Kind::ExternalSubcommand => None,
|
||||||
|
@ -553,7 +544,15 @@ fn gen_update_from_arg_matches(
|
||||||
let field_names = fields.named.iter().map(|field| {
|
let field_names = fields.named.iter().map(|field| {
|
||||||
field.ident.as_ref().unwrap()
|
field.ident.as_ref().unwrap()
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
let update = args::gen_updater(&fields.named, item, false);
|
let fields = fields
|
||||||
|
.named
|
||||||
|
.iter()
|
||||||
|
.map(|field| {
|
||||||
|
let item = Item::from_args_field(field, item.casing(), item.env_casing());
|
||||||
|
(field, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let update = args::gen_updater(&fields, false);
|
||||||
(quote!( { #( #field_names, )* }), quote!( { #update } ))
|
(quote!( { #( #field_names, )* }), quote!( { #update } ))
|
||||||
}
|
}
|
||||||
Unit => (quote!(), quote!({})),
|
Unit => (quote!(), quote!({})),
|
||||||
|
|
|
@ -12,10 +12,7 @@ use proc_macro2::TokenStream;
|
||||||
use proc_macro_error::{abort, abort_call_site};
|
use proc_macro_error::{abort, abort_call_site};
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
use quote::quote_spanned;
|
use quote::quote_spanned;
|
||||||
use syn::{
|
use syn::{spanned::Spanned, Data, DeriveInput, Fields, Ident, Variant};
|
||||||
punctuated::Punctuated, spanned::Spanned, token::Comma, Data, DeriveInput, Fields, Ident,
|
|
||||||
Variant,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::dummies;
|
use crate::dummies;
|
||||||
use crate::item::{Item, Kind, Name};
|
use crate::item::{Item, Kind, Name};
|
||||||
|
@ -29,19 +26,23 @@ pub fn derive_value_enum(input: &DeriveInput) -> TokenStream {
|
||||||
Data::Enum(ref e) => {
|
Data::Enum(ref e) => {
|
||||||
let name = Name::Derived(ident.clone());
|
let name = Name::Derived(ident.clone());
|
||||||
let item = Item::from_value_enum(input, name);
|
let item = Item::from_value_enum(input, name);
|
||||||
let variants = &e.variants;
|
let variants = e
|
||||||
gen_for_enum(&item, ident, variants)
|
.variants
|
||||||
|
.iter()
|
||||||
|
.map(|variant| {
|
||||||
|
let item =
|
||||||
|
Item::from_value_enum_variant(variant, item.casing(), item.env_casing());
|
||||||
|
(variant, item)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
gen_for_enum(&item, ident, &variants)
|
||||||
}
|
}
|
||||||
_ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"),
|
_ => abort_call_site!("`#[derive(ValueEnum)]` only supports enums"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_for_enum(
|
pub fn gen_for_enum(_item: &Item, item_name: &Ident, variants: &[(&Variant, Item)]) -> TokenStream {
|
||||||
item: &Item,
|
let lits = lits(variants);
|
||||||
item_name: &Ident,
|
|
||||||
variants: &Punctuated<Variant, Comma>,
|
|
||||||
) -> TokenStream {
|
|
||||||
let lits = lits(variants, item);
|
|
||||||
let value_variants = gen_value_variants(&lits);
|
let value_variants = gen_value_variants(&lits);
|
||||||
let to_possible_value = gen_to_possible_value(&lits);
|
let to_possible_value = gen_to_possible_value(&lits);
|
||||||
|
|
||||||
|
@ -66,15 +67,10 @@ pub fn gen_for_enum(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lits(variants: &Punctuated<Variant, Comma>, parent_item: &Item) -> Vec<(TokenStream, Ident)> {
|
fn lits(variants: &[(&Variant, Item)]) -> Vec<(TokenStream, Ident)> {
|
||||||
variants
|
variants
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|variant| {
|
.filter_map(|(variant, item)| {
|
||||||
let item = Item::from_value_enum_variant(
|
|
||||||
variant,
|
|
||||||
parent_item.casing(),
|
|
||||||
parent_item.env_casing(),
|
|
||||||
);
|
|
||||||
if let Kind::Skip(_) = &*item.kind() {
|
if let Kind::Skip(_) = &*item.kind() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in a new issue