@@ -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
2223struct 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