Skip to content

Commit 90c80bd

Browse files
committed
Add support for traits with generic parameters
1 parent 6a5e7ab commit 90c80bd

File tree

2 files changed

+66
-11
lines changed

2 files changed

+66
-11
lines changed

trait-variant/examples/variant.rs

+11
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,15 @@ 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+
where
35+
Y: Sync,
36+
{
37+
const CONST: usize = 3;
38+
type F;
39+
40+
async fn take(&self, s: S);
41+
}
42+
3243
fn main() {}

trait-variant/src/variant.rs

+55-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,60 @@ 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));
187+
let where_clauses = tr.generics.where_clause.as_ref().map(|wh| &wh.predicates);
167188
quote! {
168-
impl<T> #orig for T where T: #variant {
189+
impl<#generics #trailing_comma TraitVariantBlanketType> #orig<#generic_names>
190+
for TraitVariantBlanketType
191+
where TraitVariantBlanketType: #variant<#generic_names>, #where_clauses
192+
{
169193
#(#items)*
170194
}
171195
}
172196
}
173197

174-
fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
198+
enum GenericParamName<'s> {
199+
Lifetime(&'s Lifetime),
200+
Type(&'s Ident),
201+
Const(&'s Ident),
202+
}
203+
204+
impl ToTokens for GenericParamName<'_> {
205+
fn to_tokens(&self, tokens: &mut TokenStream) {
206+
match self {
207+
GenericParamName::Lifetime(lt) => lt.to_tokens(tokens),
208+
GenericParamName::Type(ty) => ty.to_tokens(tokens),
209+
GenericParamName::Const(co) => co.to_tokens(tokens),
210+
}
211+
}
212+
}
213+
214+
fn blanket_impl_item(
215+
item: &TraitItem,
216+
variant: &Ident,
217+
generic_names: &Punctuated<GenericParamName<'_>, Comma>,
218+
) -> TokenStream {
175219
// impl<T> IntFactory for T where T: SendIntFactory {
176220
// const NAME: &'static str = <Self as SendIntFactory>::NAME;
177221
// type MyFut<'a> = <Self as SendIntFactory>::MyFut<'a> where Self: 'a;
@@ -187,7 +231,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
187231
..
188232
}) => {
189233
quote! {
190-
const #ident #generics: #ty = <Self as #variant>::#ident;
234+
const #ident #generics: #ty = <Self as #variant<#generic_names>>::#ident;
191235
}
192236
}
193237
TraitItem::Fn(TraitItemFn { sig, .. }) => {
@@ -207,7 +251,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
207251
};
208252
quote! {
209253
#sig {
210-
<Self as #variant>::#ident(#(#args),*)#maybe_await
254+
<Self as #variant<#generic_names>>::#ident(#(#args),*)#maybe_await
211255
}
212256
}
213257
}
@@ -222,7 +266,7 @@ fn blanket_impl_item(item: &TraitItem, variant: &Ident) -> TokenStream {
222266
..
223267
}) => {
224268
quote! {
225-
type #ident<#params> = <Self as #variant>::#ident<#params> #where_clause;
269+
type #ident<#params> = <Self as #variant<#generic_names>>::#ident<#params> #where_clause;
226270
}
227271
}
228272
_ => Error::new_spanned(item, "unsupported item type").into_compile_error(),

0 commit comments

Comments
 (0)