@@ -559,10 +559,10 @@ fn gen_augment_clap_enum(
559
559
}
560
560
}
561
561
562
- fn gen_from_clap_enum ( name : & Ident ) -> TokenStream {
562
+ fn gen_from_clap_enum ( ) -> TokenStream {
563
563
quote ! {
564
564
fn from_clap( matches: & :: structopt:: clap:: ArgMatches ) -> Self {
565
- <#name as :: structopt:: StructOptInternal >:: from_subcommand( matches. subcommand( ) )
565
+ <Self as :: structopt:: StructOptInternal >:: from_subcommand( matches. subcommand( ) )
566
566
. expect( "structopt misuse: You likely tried to #[flatten] a struct \
567
567
that contains #[subcommand]. This is forbidden.")
568
568
}
@@ -736,9 +736,9 @@ fn gen_from_subcommand(
736
736
}
737
737
738
738
#[ cfg( feature = "paw" ) ]
739
- fn gen_paw_impl ( name : & Ident ) -> TokenStream {
739
+ fn gen_paw_impl ( impl_generics : & ImplGenerics , name : & Ident , ty_generics : & TypeGenerics , where_clause : & TokenStream ) -> TokenStream {
740
740
quote ! {
741
- impl :: structopt:: paw:: ParseArgs for #name {
741
+ impl #impl_generics :: structopt:: paw:: ParseArgs for #name #ty_generics #where_clause {
742
742
type Error = std:: io:: Error ;
743
743
744
744
fn parse_args( ) -> std:: result:: Result <Self , Self :: Error > {
@@ -748,19 +748,109 @@ fn gen_paw_impl(name: &Ident) -> TokenStream {
748
748
}
749
749
}
750
750
#[ cfg( not( feature = "paw" ) ) ]
751
- fn gen_paw_impl ( _: & Ident ) -> TokenStream {
751
+ fn gen_paw_impl ( _: & ImplGenerics , _ : & Ident , _ : & TypeGenerics , _ : & TokenStream ) -> TokenStream {
752
752
TokenStream :: new ( )
753
753
}
754
754
755
+ fn split_structopt_generics_for_impl ( generics : & Generics ) -> ( ImplGenerics , TypeGenerics , TokenStream ) {
756
+ use syn:: { token:: Add , TypeParamBound :: Trait } ;
757
+
758
+ fn path_ends_with ( path : & Path , ident : & str ) -> bool {
759
+ path. segments . last ( ) . unwrap ( ) . ident == ident
760
+ }
761
+
762
+ fn type_param_bounds_contains ( bounds : & Punctuated < TypeParamBound , Add > , ident : & str ) -> bool {
763
+ for bound in bounds {
764
+ if let Trait ( bound) = bound {
765
+ if path_ends_with ( & bound. path , ident) {
766
+ return true ;
767
+ }
768
+ }
769
+ }
770
+ return false ;
771
+ }
772
+
773
+ struct TraitBoundAmendments {
774
+ tokens : TokenStream ,
775
+ need_where : bool ,
776
+ need_comma : bool ,
777
+ }
778
+
779
+ impl TraitBoundAmendments {
780
+ fn new ( where_clause : Option < & WhereClause > ) -> Self {
781
+ let tokens = TokenStream :: new ( ) ;
782
+ let ( need_where, need_comma) = if let Some ( where_clause) = where_clause {
783
+ if where_clause. predicates . trailing_punct ( ) {
784
+ ( false , false )
785
+ } else {
786
+ ( false , true )
787
+ }
788
+ } else {
789
+ ( true , false )
790
+ } ;
791
+ Self { tokens, need_where, need_comma}
792
+ }
793
+
794
+ fn add ( & mut self , amendment : TokenStream ) {
795
+ if self . need_where {
796
+ self . tokens . extend ( quote ! { where } ) ;
797
+ self . need_where = false ;
798
+ }
799
+ if self . need_comma {
800
+ self . tokens . extend ( quote ! { , } ) ;
801
+ }
802
+ self . tokens . extend ( amendment) ;
803
+ self . need_comma = true ;
804
+ }
805
+
806
+ fn into_tokens ( self ) -> TokenStream {
807
+ self . tokens
808
+ }
809
+ }
810
+
811
+ let mut trait_bound_amendments = TraitBoundAmendments :: new ( generics. where_clause . as_ref ( ) ) ;
812
+
813
+ for param in & generics. params {
814
+ if let GenericParam :: Type ( param) = param {
815
+ let param_ident = & param. ident ;
816
+ if type_param_bounds_contains ( & param. bounds , "StructOpt" ) {
817
+ trait_bound_amendments. add ( quote ! { #param_ident : :: structopt:: StructOptInternal } ) ;
818
+ }
819
+ }
820
+ }
821
+
822
+ if let Some ( where_clause) = & generics. where_clause {
823
+ for predicate in & where_clause. predicates {
824
+ if let WherePredicate :: Type ( predicate) = predicate {
825
+ let predicate_bounded_ty = & predicate. bounded_ty ;
826
+ if type_param_bounds_contains ( & predicate. bounds , "StructOpt" ) {
827
+ trait_bound_amendments. add ( quote ! { #predicate_bounded_ty : :: structopt:: StructOptInternal } ) ;
828
+ }
829
+ }
830
+ }
831
+ }
832
+
833
+ let trait_bound_amendments = trait_bound_amendments. into_tokens ( ) ;
834
+
835
+ let ( impl_generics, ty_generics, where_clause) = generics. split_for_impl ( ) ;
836
+
837
+ let where_clause = quote ! { #where_clause #trait_bound_amendments } ;
838
+
839
+ ( impl_generics, ty_generics, where_clause)
840
+ }
841
+
755
842
fn impl_structopt_for_struct (
756
843
name : & Ident ,
757
844
fields : & Punctuated < Field , Comma > ,
758
845
attrs : & [ Attribute ] ,
846
+ generics : & Generics ,
759
847
) -> TokenStream {
848
+ let ( impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl ( & generics) ;
849
+
760
850
let basic_clap_app_gen = gen_clap_struct ( attrs) ;
761
851
let augment_clap = gen_augment_clap ( fields, & basic_clap_app_gen. attrs ) ;
762
852
let from_clap = gen_from_clap ( name, fields, & basic_clap_app_gen. attrs ) ;
763
- let paw_impl = gen_paw_impl ( name) ;
853
+ let paw_impl = gen_paw_impl ( & impl_generics , name, & ty_generics , & where_clause ) ;
764
854
765
855
let clap_tokens = basic_clap_app_gen. tokens ;
766
856
quote ! {
@@ -778,7 +868,7 @@ fn impl_structopt_for_struct(
778
868
) ]
779
869
#[ deny( clippy:: correctness) ]
780
870
#[ allow( dead_code, unreachable_code) ]
781
- impl :: structopt:: StructOpt for #name {
871
+ impl #impl_generics :: structopt:: StructOpt for #name #ty_generics #where_clause {
782
872
#clap_tokens
783
873
#from_clap
784
874
}
@@ -797,7 +887,7 @@ fn impl_structopt_for_struct(
797
887
) ]
798
888
#[ deny( clippy:: correctness) ]
799
889
#[ allow( dead_code, unreachable_code) ]
800
- impl :: structopt:: StructOptInternal for #name {
890
+ impl #impl_generics :: structopt:: StructOptInternal for #name #ty_generics #where_clause {
801
891
#augment_clap
802
892
fn is_subcommand( ) -> bool { false }
803
893
}
@@ -810,15 +900,19 @@ fn impl_structopt_for_enum(
810
900
name : & Ident ,
811
901
variants : & Punctuated < Variant , Comma > ,
812
902
attrs : & [ Attribute ] ,
903
+ generics : & Generics ,
813
904
) -> TokenStream {
905
+
906
+ let ( impl_generics, ty_generics, where_clause) = split_structopt_generics_for_impl ( & generics) ;
907
+
814
908
let basic_clap_app_gen = gen_clap_enum ( attrs) ;
815
909
let clap_tokens = basic_clap_app_gen. tokens ;
816
910
let attrs = basic_clap_app_gen. attrs ;
817
911
818
912
let augment_clap = gen_augment_clap_enum ( variants, & attrs) ;
819
- let from_clap = gen_from_clap_enum ( name ) ;
913
+ let from_clap = gen_from_clap_enum ( ) ;
820
914
let from_subcommand = gen_from_subcommand ( name, variants, & attrs) ;
821
- let paw_impl = gen_paw_impl ( name) ;
915
+ let paw_impl = gen_paw_impl ( & impl_generics , name, & ty_generics , & where_clause ) ;
822
916
823
917
quote ! {
824
918
#[ allow( unknown_lints) ]
@@ -834,7 +928,7 @@ fn impl_structopt_for_enum(
834
928
clippy:: cargo
835
929
) ]
836
930
#[ deny( clippy:: correctness) ]
837
- impl :: structopt:: StructOpt for #name {
931
+ impl #impl_generics :: structopt:: StructOpt for #name #ty_generics #where_clause {
838
932
#clap_tokens
839
933
#from_clap
840
934
}
@@ -853,7 +947,7 @@ fn impl_structopt_for_enum(
853
947
) ]
854
948
#[ deny( clippy:: correctness) ]
855
949
#[ allow( dead_code, unreachable_code) ]
856
- impl :: structopt:: StructOptInternal for #name {
950
+ impl #impl_generics :: structopt:: StructOptInternal for #name #ty_generics #where_clause {
857
951
#augment_clap
858
952
#from_subcommand
859
953
fn is_subcommand( ) -> bool { true }
@@ -885,8 +979,8 @@ fn impl_structopt(input: &DeriveInput) -> TokenStream {
885
979
Struct ( DataStruct {
886
980
fields : syn:: Fields :: Named ( ref fields) ,
887
981
..
888
- } ) => impl_structopt_for_struct ( struct_name, & fields. named , & input. attrs ) ,
889
- Enum ( ref e) => impl_structopt_for_enum ( struct_name, & e. variants , & input. attrs ) ,
982
+ } ) => impl_structopt_for_struct ( struct_name, & fields. named , & input. attrs , & input . generics ) ,
983
+ Enum ( ref e) => impl_structopt_for_enum ( struct_name, & e. variants , & input. attrs , & input . generics ) ,
890
984
_ => abort_call_site ! ( "structopt only supports non-tuple structs and enums" ) ,
891
985
}
892
986
}
0 commit comments