66// option. This file may not be copied, modified, or distributed
77// except according to those terms.
88
9+ use std:: iter;
10+
911use proc_macro2:: TokenStream ;
1012use quote:: quote;
1113use syn:: {
1214 parse:: { Parse , ParseStream } ,
1315 parse_macro_input,
1416 punctuated:: Punctuated ,
15- token:: Comma ,
16- Ident , ItemTrait , Path , Result , ReturnType , Token , TraitBound , TraitBoundModifier , TraitItem ,
17- Type ,
17+ token:: Plus ,
18+ Ident , ItemTrait , Result , ReturnType , Signature , Token , TraitBound , TraitItem , TraitItemFn ,
19+ Type , TypeImplTrait , TypeParamBound ,
1820} ;
1921
2022struct Attrs {
@@ -33,15 +35,15 @@ struct Variant {
3335 name : Ident ,
3436 #[ allow( unused) ]
3537 colon : Token ! [ : ] ,
36- supertrait : Path ,
38+ bounds : Punctuated < TraitBound , Plus > ,
3739}
3840
3941impl Parse for Variant {
4042 fn parse ( input : ParseStream ) -> Result < Self > {
4143 Ok ( Self {
4244 name : input. parse ( ) ?,
4345 colon : input. parse ( ) ?,
44- supertrait : input. parse ( ) ?,
46+ bounds : input. parse_terminated ( TraitBound :: parse , Token ! [ + ] ) ?,
4547 } )
4648 }
4749}
@@ -53,5 +55,76 @@ pub fn variant(
5355 let attrs = parse_macro_input ! ( attr as Attrs ) ;
5456 let item = parse_macro_input ! ( item as ItemTrait ) ;
5557
56- quote ! { } . into ( )
58+ let variant = make_variant ( & attrs, & item) ;
59+ let output = quote ! {
60+ #item
61+ #variant
62+ } ;
63+
64+ output. into ( )
65+ }
66+
67+ fn make_variant ( attrs : & Attrs , tr : & ItemTrait ) -> TokenStream {
68+ let Variant {
69+ ref name,
70+ colon : _,
71+ ref bounds,
72+ } = attrs. variant ;
73+ let bounds: Vec < _ > = bounds
74+ . into_iter ( )
75+ . map ( |b| TypeParamBound :: Trait ( b. clone ( ) ) )
76+ . collect ( ) ;
77+ let variant = ItemTrait {
78+ ident : name. clone ( ) ,
79+ supertraits : tr. supertraits . iter ( ) . chain ( & bounds) . cloned ( ) . collect ( ) ,
80+ items : tr
81+ . items
82+ . iter ( )
83+ . map ( |item| transform_item ( item, & bounds) )
84+ . collect ( ) ,
85+ ..tr. clone ( )
86+ } ;
87+ quote ! { #variant }
88+ }
89+
90+ fn transform_item ( item : & TraitItem , bounds : & Vec < TypeParamBound > ) -> TraitItem {
91+ let TraitItem :: Fn ( fn_item @ TraitItemFn { sig, .. } ) = item else {
92+ return item. clone ( ) ;
93+ } ;
94+ let ( arrow, output) = if sig. asyncness . is_some ( ) {
95+ let orig = match & sig. output {
96+ ReturnType :: Default => quote ! { ( ) } ,
97+ ReturnType :: Type ( _, ty) => quote ! { #ty } ,
98+ } ;
99+ let future = syn:: parse2 ( quote ! { :: core:: future:: Future <Output = #orig> } ) . unwrap ( ) ;
100+ let ty = Type :: ImplTrait ( TypeImplTrait {
101+ impl_token : syn:: parse2 ( quote ! { impl } ) . unwrap ( ) ,
102+ bounds : iter:: once ( TypeParamBound :: Trait ( future) )
103+ . chain ( bounds. iter ( ) . cloned ( ) )
104+ . collect ( ) ,
105+ } ) ;
106+ ( syn:: parse2 ( quote ! { -> } ) . unwrap ( ) , ty)
107+ } else {
108+ match & sig. output {
109+ ReturnType :: Type ( arrow, ty) => match & * * ty {
110+ Type :: ImplTrait ( it) => {
111+ let ty = Type :: ImplTrait ( TypeImplTrait {
112+ impl_token : it. impl_token . clone ( ) ,
113+ bounds : it. bounds . iter ( ) . chain ( bounds) . cloned ( ) . collect ( ) ,
114+ } ) ;
115+ ( arrow. clone ( ) , ty)
116+ }
117+ _ => return item. clone ( ) ,
118+ } ,
119+ ReturnType :: Default => return item. clone ( ) ,
120+ }
121+ } ;
122+ TraitItem :: Fn ( TraitItemFn {
123+ sig : Signature {
124+ asyncness : None ,
125+ output : ReturnType :: Type ( arrow, Box :: new ( output) ) ,
126+ ..sig. clone ( )
127+ } ,
128+ ..fn_item. clone ( )
129+ } )
57130}
0 commit comments