@@ -15,8 +15,9 @@ use syn::{
15
15
parse_macro_input,
16
16
punctuated:: Punctuated ,
17
17
token:: Plus ,
18
- Ident , ItemTrait , Result , ReturnType , Signature , Token , TraitBound , TraitItem , TraitItemFn ,
19
- Type , TypeImplTrait , TypeParamBound ,
18
+ Error , FnArg , Generics , Ident , ItemTrait , Pat , PatType , Result , ReturnType , Signature , Token ,
19
+ TraitBound , TraitItem , TraitItemConst , TraitItemFn , TraitItemType , Type , TypeImplTrait ,
20
+ TypeParamBound ,
20
21
} ;
21
22
22
23
struct Attrs {
@@ -56,9 +57,11 @@ pub fn variant(
56
57
let item = parse_macro_input ! ( item as ItemTrait ) ;
57
58
58
59
let variant = make_variant ( & attrs, & item) ;
60
+ let blanket_impl = make_blanket_impl ( & attrs, & item) ;
59
61
let output = quote ! {
60
62
#item
61
63
#variant
64
+ #blanket_impl
62
65
} ;
63
66
64
67
output. into ( )
@@ -128,3 +131,65 @@ fn transform_item(item: &TraitItem, bounds: &Vec<TypeParamBound>) -> TraitItem {
128
131
..fn_item. clone ( )
129
132
} )
130
133
}
134
+
135
+ fn make_blanket_impl ( attrs : & Attrs , tr : & ItemTrait ) -> TokenStream {
136
+ let orig = & tr. ident ;
137
+ let variant = & attrs. variant . name ;
138
+ let items = tr. items . iter ( ) . map ( |item| blanket_impl_item ( item, variant) ) ;
139
+ quote ! {
140
+ impl <T > #orig for T where T : #variant {
141
+ #( #items) *
142
+ }
143
+ }
144
+ }
145
+
146
+ fn blanket_impl_item ( item : & TraitItem , variant : & Ident ) -> TokenStream {
147
+ match item {
148
+ TraitItem :: Const ( TraitItemConst {
149
+ ident,
150
+ generics,
151
+ ty,
152
+ ..
153
+ } ) => {
154
+ quote ! {
155
+ const #ident #generics: #ty = <Self as #variant>:: #ident;
156
+ }
157
+ }
158
+ TraitItem :: Fn ( TraitItemFn { sig, .. } ) => {
159
+ let ident = & sig. ident ;
160
+ let args = sig. inputs . iter ( ) . map ( |arg| match arg {
161
+ FnArg :: Receiver ( _) => quote ! { self } ,
162
+ FnArg :: Typed ( PatType { pat, .. } ) => match & * * pat {
163
+ Pat :: Ident ( arg) => quote ! { #arg } ,
164
+ _ => Error :: new_spanned ( pat, "patterns are not supported in arguments" )
165
+ . to_compile_error ( ) ,
166
+ } ,
167
+ } ) ;
168
+ let maybe_await = if sig. asyncness . is_some ( ) {
169
+ quote ! { . await }
170
+ } else {
171
+ quote ! { }
172
+ } ;
173
+ quote ! {
174
+ #sig {
175
+ <Self as #variant>:: #ident( #( #args) , * ) #maybe_await
176
+ }
177
+ }
178
+ }
179
+ TraitItem :: Type ( TraitItemType {
180
+ ident,
181
+ generics :
182
+ Generics {
183
+ params,
184
+ where_clause,
185
+ ..
186
+ } ,
187
+ ..
188
+ } ) => {
189
+ quote ! {
190
+ type #ident<#params> = <Self as #variant>:: #ident<#params> #where_clause;
191
+ }
192
+ }
193
+ _ => Error :: new_spanned ( item, "unsupported item type" ) . into_compile_error ( ) ,
194
+ }
195
+ }
0 commit comments