Skip to content

Commit 9e159d1

Browse files
committed
Add support for traits with generic parameters
1 parent 6a5e7ab commit 9e159d1

File tree

2 files changed

+61
-11
lines changed

2 files changed

+61
-11
lines changed

trait-variant/examples/variant.rs

+8
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,12 @@ fn spawn_task(factory: impl IntFactory + 'static) {
2929
});
3030
}
3131

32+
#[trait_variant::make(GenericTrait: Send)]
33+
pub trait LocalGenericTrait<'x, S: Sync, Y, const X: usize> {
34+
const CONST: usize = 3;
35+
type F;
36+
37+
async fn take(&self, s: S);
38+
}
39+
3240
fn main() {}

trait-variant/src/variant.rs

+53-11
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,15 @@
99
use std::iter;
1010

1111
use proc_macro2::TokenStream;
12-
use quote::quote;
12+
use quote::{quote, ToTokens};
1313
use syn::{
1414
parse::{Parse, ParseStream},
1515
parse_macro_input,
1616
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,
2121
};
2222

2323
struct Attrs {
@@ -162,16 +162,58 @@ fn transform_item(item: &TraitItem, bounds: &Vec<TypeParamBound>) -> TraitItem {
162162

163163
fn mk_blanket_impl(attrs: &Attrs, tr: &ItemTrait) -> TokenStream {
164164
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+
};
165182
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));
167187
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+
{
169191
#(#items)*
170192
}
171193
}
172194
}
173195

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 {
175217
// impl<T> IntFactory for T where T: SendIntFactory {
176218
// const NAME: &'static str = <Self as SendIntFactory>::NAME;
177219
// type MyFut<'a> = <Self as SendIntFactory>::MyFut<'a> where Self: 'a;
@@ -187,7 +229,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
187229
..
188230
}) => {
189231
quote! {
190-
const #ident #generics: #ty = <Self as #variant>::#ident;
232+
const #ident #generics: #ty = <Self as #variant<#generic_names>>::#ident;
191233
}
192234
}
193235
TraitItem::Fn(TraitItemFn { sig, .. }) => {
@@ -207,7 +249,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
207249
};
208250
quote! {
209251
#sig {
210-
<Self as #variant>::#ident(#(#args),*)#maybe_await
252+
<Self as #variant<#generic_names>>::#ident(#(#args),*)#maybe_await
211253
}
212254
}
213255
}
@@ -222,7 +264,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
222264
..
223265
}) => {
224266
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;
226268
}
227269
}
228270
_ => Error::new_spanned(item, "unsupported item type").into_compile_error(),

0 commit comments

Comments
 (0)