Skip to content

Commit b7f8ae4

Browse files
committed
Add blanket impl
1 parent c1c531e commit b7f8ae4

File tree

2 files changed

+77
-4
lines changed

2 files changed

+77
-4
lines changed

trait_transformer/examples/variant.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@
66
// option. This file may not be copied, modified, or distributed
77
// except according to those terms.
88

9+
use std::future::Future;
10+
911
use trait_transformer::variant;
1012

1113
#[variant(SendIntFactory: Send)]
1214
trait IntFactory {
13-
async fn make(&self) -> i32;
14-
// ..or..
15+
const NAME: &'static str;
16+
17+
type MyFut<'a>: Future
18+
where
19+
Self: 'a;
20+
21+
async fn make(&self, x: u32, y: &str) -> i32;
1522
fn stream(&self) -> impl Iterator<Item = i32>;
1623
fn call(&self) -> u32;
24+
fn another_async(&self, input: Result<(), &str>) -> Self::MyFut<'_>;
1725
}
1826

1927
fn main() {}

trait_transformer/src/variant.rs

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@ use syn::{
1515
parse_macro_input,
1616
punctuated::Punctuated,
1717
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,
2021
};
2122

2223
struct Attrs {
@@ -56,9 +57,11 @@ pub fn variant(
5657
let item = parse_macro_input!(item as ItemTrait);
5758

5859
let variant = make_variant(&attrs, &item);
60+
let blanket_impl = make_blanket_impl(&attrs, &item);
5961
let output = quote! {
6062
#item
6163
#variant
64+
#blanket_impl
6265
};
6366

6467
output.into()
@@ -128,3 +131,65 @@ fn transform_item(item: &TraitItem, bounds: &Vec<TypeParamBound>) -> TraitItem {
128131
..fn_item.clone()
129132
})
130133
}
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

Comments
 (0)