Skip to content

Commit

Permalink
impl StructOpt for Box<impl StructOpt>
Browse files Browse the repository at this point in the history
  • Loading branch information
CreepySkeleton committed Dec 21, 2019
1 parent e2270de commit 3534cb3
Show file tree
Hide file tree
Showing 2 changed files with 65 additions and 28 deletions.
47 changes: 47 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -953,4 +953,51 @@ pub trait StructOpt {
{
Ok(Self::from_clap(&Self::clap().get_matches_from_safe(iter)?))
}

// All the following is NOT PUBLIC API!!!
//
// ** SUBJECT TO CHANGE WITHOUT NOTICE!!! **

#[doc(hidden)]
fn is_subcommand() -> bool {
unimplemented!()
}

#[doc(hidden)]
fn augment_clap<'a, 'b>(_app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
unimplemented!()
}

#[doc(hidden)]
fn from_subcommand<'a, 'b>(_sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option<Self>
where
Self: Sized,
{
unimplemented!()
}
}

impl<T: StructOpt> StructOpt for Box<T> {
fn clap<'a, 'b>() -> clap::App<'a, 'b> {
<T as StructOpt>::clap()
}

fn from_clap(matches: &clap::ArgMatches<'_>) -> Self {
Box::new(<T as StructOpt>::from_clap(matches))
}

#[doc(hidden)]
fn augment_clap<'a, 'b>(app: clap::App<'a, 'b>) -> clap::App<'a, 'b> {
<T as StructOpt>::augment_clap(app)
}

#[doc(hidden)]
fn is_subcommand() -> bool {
<T as StructOpt>::is_subcommand()
}

#[doc(hidden)]
fn from_subcommand<'a, 'b>(sub: (&'b str, Option<&'b clap::ArgMatches<'a>>)) -> Option<Self> {
<T as StructOpt>::from_subcommand(sub).map(Box::new)
}
}
46 changes: 18 additions & 28 deletions structopt-derive/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ fn gen_augmentation(

let span = field.span();
let ts = quote! {
let #app_var = <#subcmd_type>::augment_clap( #app_var );
let #app_var = <#subcmd_type as ::structopt::StructOpt>::augment_clap( #app_var );
#required
};
Some((span, ts))
Expand Down Expand Up @@ -116,8 +116,8 @@ fn gen_augmentation(
Kind::FlattenStruct => {
let ty = &field.ty;
Some(quote_spanned! { kind.span()=>
let #app_var = <#ty>::augment_clap(#app_var);
let #app_var = if <#ty>::is_subcommand() {
let #app_var = <#ty as ::structopt::StructOpt>::augment_clap(#app_var);
let #app_var = if <#ty as ::structopt::StructOpt>::is_subcommand() {
#app_var.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp)
} else {
#app_var
Expand Down Expand Up @@ -249,7 +249,9 @@ fn gen_constructor(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
_ => quote_spanned!( ty.span()=> .unwrap() ),
};
quote_spanned! { kind.span()=>
#field_name: <#subcmd_type>::from_subcommand(matches.subcommand())#unwrapper
#field_name: <#subcmd_type as ::structopt::StructOpt>::from_subcommand(
matches.subcommand())
#unwrapper
}
}

Expand Down Expand Up @@ -394,7 +396,7 @@ fn gen_clap_struct(struct_attrs: &[Attribute]) -> GenOutput {
let augmented_tokens = quote! {
fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
let app = #clap_tokens;
Self::augment_clap(app)
<Self as ::structopt::StructOpt>::augment_clap(app)
}
};

Expand All @@ -408,7 +410,7 @@ fn gen_augment_clap(fields: &Punctuated<Field, Comma>, parent_attribute: &Attrs)
let app_var = Ident::new("app", Span::call_site());
let augmentation = gen_augmentation(fields, &app_var, parent_attribute);
quote! {
pub fn augment_clap<'a, 'b>(
fn augment_clap<'a, 'b>(
#app_var: ::structopt::clap::App<'a, 'b>
) -> ::structopt::clap::App<'a, 'b> {
#augmentation
Expand All @@ -424,7 +426,7 @@ fn gen_clap_enum(enum_attrs: &[Attribute]) -> GenOutput {
fn clap<'a, 'b>() -> ::structopt::clap::App<'a, 'b> {
let app = #clap_tokens
.setting(::structopt::clap::AppSettings::SubcommandRequiredElseHelp);
Self::augment_clap(app)
<Self as ::structopt::StructOpt>::augment_clap(app)
}
};

Expand Down Expand Up @@ -456,8 +458,8 @@ fn gen_augment_clap_enum(
let ty = &unnamed[0];
quote_spanned! { ty.span()=>
{
let #app_var = <#ty>::augment_clap(#app_var);
if <#ty>::is_subcommand() {
let #app_var = <#ty as ::structopt::StructOpt>::augment_clap(#app_var);
if <#ty as ::structopt::StructOpt>::is_subcommand() {
#app_var.setting(
::structopt::clap::AppSettings::SubcommandRequiredElseHelp
)
Expand Down Expand Up @@ -485,7 +487,7 @@ fn gen_augment_clap_enum(
let app_methods = parent_attribute.top_level_methods();

quote! {
pub fn augment_clap<'a, 'b>(
fn augment_clap<'a, 'b>(
app: ::structopt::clap::App<'a, 'b>
) -> ::structopt::clap::App<'a, 'b> {
app #app_methods #( #subcommands )*
Expand All @@ -496,7 +498,7 @@ fn gen_augment_clap_enum(
fn gen_from_clap_enum(name: &Ident) -> TokenStream {
quote! {
fn from_clap(matches: &::structopt::clap::ArgMatches) -> Self {
<#name>::from_subcommand(matches.subcommand())
<#name as ::structopt::StructOpt>::from_subcommand(matches.subcommand())
.unwrap()
}
}
Expand Down Expand Up @@ -536,7 +538,7 @@ fn gen_from_subcommand(
});

quote! {
pub fn from_subcommand<'a, 'b>(
fn from_subcommand<'a, 'b>(
sub: (&'b str, Option<&'b ::structopt::clap::ArgMatches<'a>>)
) -> Option<Self> {
match sub {
Expand Down Expand Up @@ -579,18 +581,12 @@ fn impl_structopt_for_struct(
#[allow(unused_variables)]
#[allow(unknown_lints)]
#[allow(clippy)]
#[allow(dead_code, unreachable_code)]
impl ::structopt::StructOpt for #name {
#clap_tokens
#from_clap
}

#[doc(hidden)]
#[allow(dead_code, unreachable_code)]
#[allow(unknown_lints)]
#[allow(clippy)]
impl #name {
#augment_clap
pub fn is_subcommand() -> bool { false }
fn is_subcommand() -> bool { false }
}

#paw_impl
Expand All @@ -612,20 +608,14 @@ fn impl_structopt_for_enum(
let clap_tokens = basic_clap_app_gen.tokens;
quote! {
#[allow(unknown_lints)]
#[allow(unused_variables, dead_code, unreachable_code)]
#[allow(clippy)]
impl ::structopt::StructOpt for #name {
#clap_tokens
#from_clap
}

#[allow(unused_variables, dead_code, unreachable_code)]
#[allow(unknown_lints)]
#[allow(clippy)]
#[doc(hidden)]
impl #name {
#augment_clap
#from_subcommand
pub fn is_subcommand() -> bool { true }
fn is_subcommand() -> bool { true }
}

#paw_impl
Expand Down

0 comments on commit 3534cb3

Please sign in to comment.