6
6
// option. This file may not be copied, modified, or distributed
7
7
// except according to those terms.
8
8
9
+ use std:: iter;
10
+
9
11
use proc_macro2:: TokenStream ;
10
12
use quote:: quote;
11
13
use syn:: {
12
14
parse:: { Parse , ParseStream } ,
13
15
parse_macro_input,
14
16
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 ,
18
20
} ;
19
21
20
22
struct Attrs {
@@ -33,15 +35,15 @@ struct Variant {
33
35
name : Ident ,
34
36
#[ allow( unused) ]
35
37
colon : Token ! [ : ] ,
36
- supertrait : Path ,
38
+ bounds : Punctuated < TraitBound , Plus > ,
37
39
}
38
40
39
41
impl Parse for Variant {
40
42
fn parse ( input : ParseStream ) -> Result < Self > {
41
43
Ok ( Self {
42
44
name : input. parse ( ) ?,
43
45
colon : input. parse ( ) ?,
44
- supertrait : input. parse ( ) ?,
46
+ bounds : input. parse_terminated ( TraitBound :: parse , Token ! [ + ] ) ?,
45
47
} )
46
48
}
47
49
}
@@ -53,5 +55,76 @@ pub fn variant(
53
55
let attrs = parse_macro_input ! ( attr as Attrs ) ;
54
56
let item = parse_macro_input ! ( item as ItemTrait ) ;
55
57
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
+ } )
57
130
}
0 commit comments