1
- use proc_macro2:: TokenStream ;
2
- use quote:: quote;
1
+ use convert_case:: { Case , Casing } ;
2
+ use proc_macro2:: { Ident , TokenStream } ;
3
+ use quote:: { quote, quote_spanned} ;
3
4
use syn:: Type ;
4
5
use synstructure:: VariantInfo ;
5
6
@@ -79,7 +80,7 @@ fn downcast_to_variant(s: &synstructure::Structure, v: &VariantInfo) -> TokenStr
79
80
}
80
81
} ) ;
81
82
82
- s. gen_impl ( quote ! {
83
+ let mut ts = s. gen_impl ( quote ! {
83
84
use formality_core:: { DowncastTo } ;
84
85
85
86
gen impl DowncastTo <( #( #binding_tys) , * ) > for @Self {
@@ -89,5 +90,44 @@ fn downcast_to_variant(s: &synstructure::Structure, v: &VariantInfo) -> TokenStr
89
90
}
90
91
}
91
92
}
92
- } )
93
+ } ) ;
94
+
95
+ if binding_tys. len ( ) == 1 && matches ! ( s. ast( ) . data, syn:: Data :: Enum ( _) ) {
96
+ let binding_ty = & binding_tys[ 0 ] ;
97
+ let type_name = & s. ast ( ) . ident ;
98
+ let variant_name = & v. ast ( ) . ident ;
99
+ let as_method_name = Ident :: new (
100
+ & format ! ( "as_{}" , variant_name. to_string( ) . to_case( Case :: Snake ) ) ,
101
+ v. ast ( ) . ident . span ( ) ,
102
+ ) ;
103
+ let ( impl_generics, type_generics, where_clauses) = s. ast ( ) . generics . split_for_impl ( ) ;
104
+
105
+ let match_arms = s. each_variant ( |variant_info| {
106
+ if variant_info. ast ( ) . ident == v. ast ( ) . ident {
107
+ let bindings = variant_info. bindings ( ) ;
108
+ let binding_idents: Vec < & syn:: Ident > =
109
+ bindings. iter ( ) . map ( |b| & b. binding ) . collect ( ) ;
110
+ quote ! { Some ( ( #( #binding_idents) , * ) ) }
111
+ } else {
112
+ quote ! { None }
113
+ }
114
+ } ) ;
115
+
116
+ let as_impl = quote_spanned ! { v. ast( ) . ident. span( ) =>
117
+ #[ allow( dead_code) ]
118
+ impl #impl_generics #type_name #type_generics
119
+ where #where_clauses
120
+ {
121
+ pub fn #as_method_name( & self ) -> Option <& #binding_ty> {
122
+ match self {
123
+ #match_arms
124
+ }
125
+ }
126
+ }
127
+ } ;
128
+
129
+ ts. extend ( as_impl) ;
130
+ }
131
+
132
+ ts
93
133
}
0 commit comments