1
- use std:: collections:: { HashMap , HashSet } ;
1
+ use std:: collections:: HashMap ;
2
2
3
3
use proc_macro:: TokenStream ;
4
4
use quote:: quote;
5
- use syn:: { fold :: Fold , punctuated:: Punctuated , spanned:: Spanned , * } ;
5
+ use syn:: { punctuated:: Punctuated , spanned:: Spanned , * } ;
6
6
7
7
#[ derive( Copy , Clone ) ]
8
8
// All conversions we support. Check references to this type for an idea how to add more.
@@ -13,14 +13,6 @@ enum Conversion<'a> {
13
13
}
14
14
15
15
impl < ' a > Conversion < ' a > {
16
- fn target_type ( & self ) -> Type {
17
- match * self {
18
- Conversion :: Into ( ty) => ty. clone ( ) ,
19
- Conversion :: AsRef ( ty) => parse_quote ! ( & #ty) ,
20
- Conversion :: AsMut ( ty) => parse_quote ! ( & mut #ty) ,
21
- }
22
- }
23
-
24
16
fn conversion_expr ( & self , i : Ident ) -> Expr {
25
17
match * self {
26
18
Conversion :: Into ( _) => parse_quote ! ( #i. into( ) ) ,
@@ -62,58 +54,29 @@ fn parse_bounds(bounds: &Punctuated<TypeParamBound, Token![+]>) -> Option<Conver
62
54
}
63
55
64
56
// create a map from generic type to Conversion
65
- fn parse_generics ( decl : & Signature ) -> ( HashMap < Ident , Conversion < ' _ > > , Generics ) {
57
+ fn parse_generics ( decl : & Signature ) -> HashMap < Ident , Conversion < ' _ > > {
66
58
let mut ty_conversions = HashMap :: new ( ) ;
67
- let mut params = Punctuated :: new ( ) ;
68
59
for gp in decl. generics . params . iter ( ) {
69
60
if let GenericParam :: Type ( ref tp) = gp {
70
61
if let Some ( conversion) = parse_bounds ( & tp. bounds ) {
71
62
ty_conversions. insert ( tp. ident . clone ( ) , conversion) ;
72
63
continue ;
73
64
}
74
65
}
75
- params. push ( gp. clone ( ) ) ;
76
66
}
77
- let where_clause = if let Some ( ref wc) = decl. generics . where_clause {
78
- let mut idents_to_remove = HashSet :: new ( ) ;
79
- let mut predicates = Punctuated :: new ( ) ;
67
+ if let Some ( ref wc) = decl. generics . where_clause {
80
68
for wp in wc. predicates . iter ( ) {
81
69
if let WherePredicate :: Type ( ref pt) = wp {
82
70
if let Some ( ident) = parse_bounded_type ( & pt. bounded_ty ) {
83
71
if let Some ( conversion) = parse_bounds ( & pt. bounds ) {
84
- idents_to_remove. insert ( ident. clone ( ) ) ;
85
72
ty_conversions. insert ( ident, conversion) ;
86
73
continue ;
87
74
}
88
75
}
89
76
}
90
- predicates. push ( wp. clone ( ) ) ;
91
77
}
92
- params = params
93
- . into_iter ( )
94
- . filter ( |param| {
95
- if let GenericParam :: Type ( type_param) = param {
96
- !idents_to_remove. contains ( & type_param. ident )
97
- } else {
98
- true
99
- }
100
- } )
101
- . collect ( ) ;
102
- Some ( WhereClause {
103
- predicates,
104
- ..wc. clone ( )
105
- } )
106
- } else {
107
- None
108
- } ;
109
- (
110
- ty_conversions,
111
- Generics {
112
- params,
113
- where_clause,
114
- ..decl. generics . clone ( )
115
- } ,
116
- )
78
+ }
79
+ ty_conversions
117
80
}
118
81
119
82
fn pat_to_ident ( pat : & Pat ) -> Ident {
@@ -131,140 +94,36 @@ fn pat_to_expr(pat: &Pat) -> Expr {
131
94
fn convert < ' a > (
132
95
inputs : & ' a Punctuated < FnArg , Token ! [ , ] > ,
133
96
ty_conversions : & HashMap < Ident , Conversion < ' a > > ,
134
- ) -> (
135
- Punctuated < FnArg , Token ! [ , ] > ,
136
- Conversions ,
137
- Punctuated < Expr , Token ! [ , ] > ,
138
- bool ,
139
- ) {
140
- let mut argtypes = Punctuated :: new ( ) ;
141
- let mut conversions = Conversions {
142
- intos : Vec :: new ( ) ,
143
- as_refs : Vec :: new ( ) ,
144
- as_muts : Vec :: new ( ) ,
145
- } ;
97
+ ) -> ( Punctuated < Expr , Token ! [ , ] > , bool ) {
146
98
let mut argexprs = Punctuated :: new ( ) ;
147
99
let mut has_self = false ;
148
100
inputs. iter ( ) . for_each ( |input| match input {
149
101
FnArg :: Receiver ( ..) => {
150
102
has_self = true ;
151
- argtypes. push ( input. clone ( ) ) ;
152
103
}
153
- FnArg :: Typed ( PatType {
154
- ref pat,
155
- ref ty,
156
- ref colon_token,
157
- ..
158
- } ) => match * * ty {
104
+ FnArg :: Typed ( PatType { ref pat, ref ty, .. } ) => match * * ty {
159
105
Type :: ImplTrait ( TypeImplTrait { ref bounds, .. } ) => {
160
106
if let Some ( conv) = parse_bounds ( bounds) {
161
- argtypes. push ( FnArg :: Typed ( PatType {
162
- attrs : Vec :: new ( ) ,
163
- pat : pat. clone ( ) ,
164
- colon_token : * colon_token,
165
- ty : Box :: new ( conv. target_type ( ) ) ,
166
- } ) ) ;
167
107
let ident = pat_to_ident ( pat) ;
168
- conversions. add ( ident. clone ( ) , conv) ;
169
108
argexprs. push ( conv. conversion_expr ( ident) ) ;
170
109
} else {
171
- argtypes. push ( input. clone ( ) ) ;
172
110
argexprs. push ( pat_to_expr ( pat) ) ;
173
111
}
174
112
}
175
113
Type :: Path ( ..) => {
176
114
if let Some ( conv) = parse_bounded_type ( ty) . and_then ( |ident| ty_conversions. get ( & ident) ) {
177
- argtypes. push ( FnArg :: Typed ( PatType {
178
- attrs : Vec :: new ( ) ,
179
- pat : pat. clone ( ) ,
180
- colon_token : * colon_token,
181
- ty : Box :: new ( conv. target_type ( ) ) ,
182
- } ) ) ;
183
115
let ident = pat_to_ident ( pat) ;
184
- conversions. add ( ident. clone ( ) , * conv) ;
185
116
argexprs. push ( conv. conversion_expr ( ident) ) ;
186
117
} else {
187
- argtypes. push ( input. clone ( ) ) ;
188
118
argexprs. push ( pat_to_expr ( pat) ) ;
189
119
}
190
120
}
191
121
_ => {
192
- argtypes. push ( input. clone ( ) ) ;
193
122
argexprs. push ( pat_to_expr ( pat) ) ;
194
123
}
195
124
} ,
196
125
} ) ;
197
- ( argtypes, conversions, argexprs, has_self)
198
- }
199
-
200
- struct Conversions {
201
- intos : Vec < Ident > ,
202
- as_refs : Vec < Ident > ,
203
- as_muts : Vec < Ident > ,
204
- }
205
-
206
- impl Conversions {
207
- fn add ( & mut self , ident : Ident , conv : Conversion ) {
208
- match conv {
209
- Conversion :: Into ( _) => self . intos . push ( ident) ,
210
- Conversion :: AsRef ( _) => self . as_refs . push ( ident) ,
211
- Conversion :: AsMut ( _) => self . as_muts . push ( ident) ,
212
- }
213
- }
214
- }
215
-
216
- fn has_conversion ( idents : & [ Ident ] , expr : & Expr ) -> bool {
217
- if let Expr :: Path ( ExprPath { ref path, .. } ) = * expr {
218
- if path. segments . len ( ) == 1 {
219
- let seg = path. segments . iter ( ) . last ( ) . unwrap ( ) ;
220
- return idents. iter ( ) . any ( |i| i == & seg. ident ) ;
221
- }
222
- }
223
- false
224
- }
225
-
226
- #[ allow( clippy:: collapsible_if) ]
227
- impl Fold for Conversions {
228
- fn fold_expr ( & mut self , expr : Expr ) -> Expr {
229
- //TODO: Also catch `Expr::Call` with suitable paths & args
230
- match expr {
231
- Expr :: MethodCall ( mc) if mc. args . is_empty ( ) => match & * mc. method . to_string ( ) {
232
- "into" if has_conversion ( & self . intos , & mc. receiver ) => * mc. receiver ,
233
-
234
- "as_ref" if has_conversion ( & self . as_refs , & mc. receiver ) => * mc. receiver ,
235
- "as_mut" if has_conversion ( & self . as_muts , & mc. receiver ) => * mc. receiver ,
236
-
237
- _ => syn:: fold:: fold_expr ( self , Expr :: MethodCall ( mc) ) ,
238
- } ,
239
- Expr :: Call ( call) if call. args . len ( ) == 1 => match & * call. func {
240
- Expr :: Path ( ExprPath {
241
- path : Path { segments, .. } ,
242
- ..
243
- } ) if segments. len ( ) == 2 => match ( & * segments[ 0 ] . ident . to_string ( ) , & * segments[ 1 ] . ident . to_string ( ) ) {
244
- ( "Into" , "into" ) if has_conversion ( & self . intos , & call. args [ 0 ] ) => call. args [ 0 ] . clone ( ) ,
245
-
246
- ( "AsRef" , "as_ref" ) if matches ! ( & call. args[ 0 ] , Expr :: Reference ( ExprReference { expr, mutability: None , .. } ) if has_conversion( & self . as_refs, expr) ) => {
247
- if let Expr :: Reference ( ExprReference { expr, .. } ) = & call. args [ 0 ] {
248
- ( * * expr) . clone ( )
249
- } else {
250
- panic ! ( "expr must be Reference" )
251
- }
252
- }
253
- ( "AsMut" , "as_mut" ) if matches ! ( & call. args[ 0 ] , Expr :: Reference ( ExprReference { expr, mutability: Some ( _) , .. } ) if has_conversion( & self . as_muts, expr) ) => {
254
- if let Expr :: Reference ( ExprReference { expr, .. } ) = & call. args [ 0 ] {
255
- ( * * expr) . clone ( )
256
- } else {
257
- panic ! ( "expr must be Reference" )
258
- }
259
- }
260
-
261
- _ => syn:: fold:: fold_expr ( self , Expr :: Call ( call) ) ,
262
- } ,
263
- _ => syn:: fold:: fold_expr ( self , Expr :: Call ( call) ) ,
264
- } ,
265
- _ => syn:: fold:: fold_expr ( self , expr) ,
266
- }
267
- }
126
+ ( argexprs, has_self)
268
127
}
269
128
270
129
fn contains_self_type_path ( path : & Path ) -> bool {
@@ -339,8 +198,8 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
339
198
} ;
340
199
341
200
if let Item :: Fn ( item_fn) = fn_item {
342
- let ( ty_conversions, generics ) = parse_generics ( & item_fn. sig ) ;
343
- let ( argtypes , mut conversions , argexprs, has_self) = convert ( & item_fn. sig . inputs , & ty_conversions) ;
201
+ let ty_conversions = parse_generics ( & item_fn. sig ) ;
202
+ let ( argexprs, has_self) = convert ( & item_fn. sig . inputs , & ty_conversions) ;
344
203
345
204
let uses_self = has_self
346
205
|| item_fn. sig . inputs . iter ( ) . any ( has_self_type)
@@ -367,11 +226,9 @@ fn momo_inner(code: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
367
226
vis : Visibility :: Inherited ,
368
227
sig : Signature {
369
228
ident : inner_ident. clone ( ) ,
370
- generics,
371
- inputs : argtypes,
372
229
..item_fn. sig . clone ( )
373
230
} ,
374
- block : Box :: new ( conversions . fold_block ( * item_fn. block ) ) ,
231
+ block : item_fn. block ,
375
232
} ) ;
376
233
377
234
if uses_self {
0 commit comments