9
9
use std:: iter;
10
10
11
11
use proc_macro2:: TokenStream ;
12
- use quote:: quote;
12
+ use quote:: { quote, ToTokens } ;
13
13
use syn:: {
14
14
parse:: { Parse , ParseStream } ,
15
15
parse_macro_input,
16
16
punctuated:: Punctuated ,
17
- token:: Plus ,
18
- Error , FnArg , Generics , Ident , ItemTrait , Pat , PatType , Result , ReturnType , Signature , Token ,
19
- TraitBound , TraitItem , TraitItemConst , TraitItemFn , TraitItemType , Type , TypeImplTrait ,
20
- TypeParamBound ,
17
+ token:: { Comma , Plus } ,
18
+ Error , FnArg , GenericParam , Generics , Ident , ItemTrait , Lifetime , Pat , PatType , Result ,
19
+ ReturnType , Signature , Token , TraitBound , TraitItem , TraitItemConst , TraitItemFn ,
20
+ TraitItemType , Type , TypeImplTrait , TypeParamBound ,
21
21
} ;
22
22
23
23
struct Attrs {
@@ -162,16 +162,58 @@ fn transform_item(item: &TraitItem, bounds: &Vec<TypeParamBound>) -> TraitItem {
162
162
163
163
fn mk_blanket_impl ( attrs : & Attrs , tr : & ItemTrait ) -> TokenStream {
164
164
let orig = & tr. ident ;
165
+ let generics = & tr. generics . params ;
166
+ let mut generic_names = tr
167
+ . generics
168
+ . params
169
+ . iter ( )
170
+ . map ( |generic| match generic {
171
+ GenericParam :: Lifetime ( lt) => GenericParamName :: Lifetime ( & lt. lifetime ) ,
172
+ GenericParam :: Type ( ty) => GenericParamName :: Type ( & ty. ident ) ,
173
+ GenericParam :: Const ( co) => GenericParamName :: Const ( & co. ident ) ,
174
+ } )
175
+ . collect :: < Punctuated < _ , Comma > > ( ) ;
176
+ let trailing_comma = if !generic_names. is_empty ( ) {
177
+ generic_names. push_punct ( Comma :: default ( ) ) ;
178
+ quote ! { , }
179
+ } else {
180
+ quote ! { }
181
+ } ;
165
182
let variant = & attrs. variant . name ;
166
- let items = tr. items . iter ( ) . map ( |item| blanket_impl_item ( item, variant) ) ;
183
+ let items = tr
184
+ . items
185
+ . iter ( )
186
+ . map ( |item| blanket_impl_item ( item, variant, & generic_names) ) ;
167
187
quote ! {
168
- impl <T > #orig for T where T : #variant {
188
+ impl <#generics #trailing_comma T > #orig<#generic_names> for T
189
+ where T : #variant<#generic_names>
190
+ {
169
191
#( #items) *
170
192
}
171
193
}
172
194
}
173
195
174
- fn blanket_impl_item ( item : & TraitItem , variant : & Ident ) -> TokenStream {
196
+ enum GenericParamName < ' s > {
197
+ Lifetime ( & ' s Lifetime ) ,
198
+ Type ( & ' s Ident ) ,
199
+ Const ( & ' s Ident ) ,
200
+ }
201
+
202
+ impl ToTokens for GenericParamName < ' _ > {
203
+ fn to_tokens ( & self , tokens : & mut TokenStream ) {
204
+ match self {
205
+ GenericParamName :: Lifetime ( lt) => lt. to_tokens ( tokens) ,
206
+ GenericParamName :: Type ( ty) => ty. to_tokens ( tokens) ,
207
+ GenericParamName :: Const ( co) => co. to_tokens ( tokens) ,
208
+ }
209
+ }
210
+ }
211
+
212
+ fn blanket_impl_item (
213
+ item : & TraitItem ,
214
+ variant : & Ident ,
215
+ generic_names : & Punctuated < GenericParamName < ' _ > , Comma > ,
216
+ ) -> TokenStream {
175
217
// impl<T> IntFactory for T where T: SendIntFactory {
176
218
// const NAME: &'static str = <Self as SendIntFactory>::NAME;
177
219
// type MyFut<'a> = <Self as SendIntFactory>::MyFut<'a> where Self: 'a;
@@ -187,7 +229,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
187
229
..
188
230
} ) => {
189
231
quote ! {
190
- const #ident #generics: #ty = <Self as #variant>:: #ident;
232
+ const #ident #generics: #ty = <Self as #variant<#generic_names> >:: #ident;
191
233
}
192
234
}
193
235
TraitItem :: Fn ( TraitItemFn { sig, .. } ) => {
@@ -207,7 +249,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
207
249
} ;
208
250
quote ! {
209
251
#sig {
210
- <Self as #variant>:: #ident( #( #args) , * ) #maybe_await
252
+ <Self as #variant<#generic_names> >:: #ident( #( #args) , * ) #maybe_await
211
253
}
212
254
}
213
255
}
@@ -222,7 +264,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
222
264
..
223
265
} ) => {
224
266
quote ! {
225
- type #ident<#params> = <Self as #variant>:: #ident<#params> #where_clause;
267
+ type #ident<#params> = <Self as #variant<#generic_names> >:: #ident<#params> #where_clause;
226
268
}
227
269
}
228
270
_ => Error :: new_spanned ( item, "unsupported item type" ) . into_compile_error ( ) ,
0 commit comments