1 | use crate::algorithm::Printer; |
2 | use crate::iter::IterDelimited; |
3 | use crate::path::PathKind; |
4 | use crate::INDENT; |
5 | use proc_macro2::TokenStream; |
6 | use std::ptr; |
7 | use syn::{ |
8 | BoundLifetimes, CapturedParam, ConstParam, Expr, GenericParam, Generics, LifetimeParam, |
9 | PreciseCapture, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam, |
10 | TypeParamBound, WhereClause, WherePredicate, |
11 | }; |
12 | |
13 | impl Printer { |
14 | pub fn generics(&mut self, generics: &Generics) { |
15 | if generics.params.is_empty() { |
16 | return; |
17 | } |
18 | |
19 | self.word("<" ); |
20 | self.cbox(0); |
21 | self.zerobreak(); |
22 | |
23 | // Print lifetimes before types and consts, regardless of their |
24 | // order in self.params. |
25 | #[derive (Ord, PartialOrd, Eq, PartialEq)] |
26 | enum Group { |
27 | First, |
28 | Second, |
29 | } |
30 | fn group(param: &GenericParam) -> Group { |
31 | match param { |
32 | GenericParam::Lifetime(_) => Group::First, |
33 | GenericParam::Type(_) | GenericParam::Const(_) => Group::Second, |
34 | } |
35 | } |
36 | let last = generics.params.iter().max_by_key(|param| group(param)); |
37 | for current_group in [Group::First, Group::Second] { |
38 | for param in &generics.params { |
39 | if group(param) == current_group { |
40 | self.generic_param(param); |
41 | self.trailing_comma(ptr::eq(param, last.unwrap())); |
42 | } |
43 | } |
44 | } |
45 | |
46 | self.offset(-INDENT); |
47 | self.end(); |
48 | self.word(">" ); |
49 | } |
50 | |
51 | fn generic_param(&mut self, generic_param: &GenericParam) { |
52 | match generic_param { |
53 | GenericParam::Type(type_param) => self.type_param(type_param), |
54 | GenericParam::Lifetime(lifetime_param) => self.lifetime_param(lifetime_param), |
55 | GenericParam::Const(const_param) => self.const_param(const_param), |
56 | } |
57 | } |
58 | |
59 | pub fn bound_lifetimes(&mut self, bound_lifetimes: &BoundLifetimes) { |
60 | self.word("for<" ); |
61 | for param in bound_lifetimes.lifetimes.iter().delimited() { |
62 | self.generic_param(¶m); |
63 | if !param.is_last { |
64 | self.word(", " ); |
65 | } |
66 | } |
67 | self.word("> " ); |
68 | } |
69 | |
70 | fn lifetime_param(&mut self, lifetime_param: &LifetimeParam) { |
71 | self.outer_attrs(&lifetime_param.attrs); |
72 | self.lifetime(&lifetime_param.lifetime); |
73 | for lifetime in lifetime_param.bounds.iter().delimited() { |
74 | if lifetime.is_first { |
75 | self.word(": " ); |
76 | } else { |
77 | self.word(" + " ); |
78 | } |
79 | self.lifetime(&lifetime); |
80 | } |
81 | } |
82 | |
83 | fn type_param(&mut self, type_param: &TypeParam) { |
84 | self.outer_attrs(&type_param.attrs); |
85 | self.ident(&type_param.ident); |
86 | self.ibox(INDENT); |
87 | for type_param_bound in type_param.bounds.iter().delimited() { |
88 | if type_param_bound.is_first { |
89 | self.word(": " ); |
90 | } else { |
91 | self.space(); |
92 | self.word("+ " ); |
93 | } |
94 | self.type_param_bound(&type_param_bound); |
95 | } |
96 | if let Some(default) = &type_param.default { |
97 | self.space(); |
98 | self.word("= " ); |
99 | self.ty(default); |
100 | } |
101 | self.end(); |
102 | } |
103 | |
104 | pub fn type_param_bound(&mut self, type_param_bound: &TypeParamBound) { |
105 | match type_param_bound { |
106 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
107 | TypeParamBound::Trait(trait_bound) => { |
108 | let tilde_const = false; |
109 | self.trait_bound(trait_bound, tilde_const); |
110 | } |
111 | TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime), |
112 | TypeParamBound::PreciseCapture(precise_capture) => { |
113 | self.precise_capture(precise_capture); |
114 | } |
115 | TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound), |
116 | _ => unimplemented!("unknown TypeParamBound" ), |
117 | } |
118 | } |
119 | |
120 | fn trait_bound(&mut self, trait_bound: &TraitBound, tilde_const: bool) { |
121 | if trait_bound.paren_token.is_some() { |
122 | self.word("(" ); |
123 | } |
124 | if tilde_const { |
125 | self.word("~const " ); |
126 | } |
127 | self.trait_bound_modifier(&trait_bound.modifier); |
128 | if let Some(bound_lifetimes) = &trait_bound.lifetimes { |
129 | self.bound_lifetimes(bound_lifetimes); |
130 | } |
131 | for segment in trait_bound.path.segments.iter().delimited() { |
132 | if !segment.is_first || trait_bound.path.leading_colon.is_some() { |
133 | self.word("::" ); |
134 | } |
135 | self.path_segment(&segment, PathKind::Type); |
136 | } |
137 | if trait_bound.paren_token.is_some() { |
138 | self.word(")" ); |
139 | } |
140 | } |
141 | |
142 | fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) { |
143 | match trait_bound_modifier { |
144 | TraitBoundModifier::None => {} |
145 | TraitBoundModifier::Maybe(_question_mark) => self.word("?" ), |
146 | } |
147 | } |
148 | |
149 | #[cfg (not(feature = "verbatim" ))] |
150 | fn type_param_bound_verbatim(&mut self, bound: &TokenStream) { |
151 | unimplemented!("TypeParamBound::Verbatim `{}`" , bound); |
152 | } |
153 | |
154 | #[cfg (feature = "verbatim" )] |
155 | fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) { |
156 | use syn::parse::{Parse, ParseStream, Result}; |
157 | use syn::{parenthesized, token, Token}; |
158 | |
159 | enum TypeParamBoundVerbatim { |
160 | Ellipsis, |
161 | TildeConst(TraitBound), |
162 | } |
163 | |
164 | impl Parse for TypeParamBoundVerbatim { |
165 | fn parse(input: ParseStream) -> Result<Self> { |
166 | let content; |
167 | let (paren_token, content) = if input.peek(token::Paren) { |
168 | (Some(parenthesized!(content in input)), &content) |
169 | } else { |
170 | (None, input) |
171 | }; |
172 | let lookahead = content.lookahead1(); |
173 | if lookahead.peek(Token![~]) { |
174 | content.parse::<Token![~]>()?; |
175 | content.parse::<Token![const]>()?; |
176 | let mut bound: TraitBound = content.parse()?; |
177 | bound.paren_token = paren_token; |
178 | Ok(TypeParamBoundVerbatim::TildeConst(bound)) |
179 | } else if lookahead.peek(Token![...]) { |
180 | content.parse::<Token![...]>()?; |
181 | Ok(TypeParamBoundVerbatim::Ellipsis) |
182 | } else { |
183 | Err(lookahead.error()) |
184 | } |
185 | } |
186 | } |
187 | |
188 | let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) { |
189 | Ok(bound) => bound, |
190 | Err(_) => unimplemented!("TypeParamBound::Verbatim ` {}`" , tokens), |
191 | }; |
192 | |
193 | match bound { |
194 | TypeParamBoundVerbatim::Ellipsis => { |
195 | self.word("..." ); |
196 | } |
197 | TypeParamBoundVerbatim::TildeConst(trait_bound) => { |
198 | let tilde_const = true; |
199 | self.trait_bound(&trait_bound, tilde_const); |
200 | } |
201 | } |
202 | } |
203 | |
204 | fn const_param(&mut self, const_param: &ConstParam) { |
205 | self.outer_attrs(&const_param.attrs); |
206 | self.word("const " ); |
207 | self.ident(&const_param.ident); |
208 | self.word(": " ); |
209 | self.ty(&const_param.ty); |
210 | if let Some(default) = &const_param.default { |
211 | self.word(" = " ); |
212 | self.const_argument(default); |
213 | } |
214 | } |
215 | |
216 | pub fn where_clause_for_body(&mut self, where_clause: &Option<WhereClause>) { |
217 | let hardbreaks = true; |
218 | let semi = false; |
219 | self.where_clause_impl(where_clause, hardbreaks, semi); |
220 | } |
221 | |
222 | pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) { |
223 | let hardbreaks = true; |
224 | let semi = true; |
225 | self.where_clause_impl(where_clause, hardbreaks, semi); |
226 | } |
227 | |
228 | pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) { |
229 | let hardbreaks = false; |
230 | let semi = false; |
231 | self.where_clause_impl(where_clause, hardbreaks, semi); |
232 | } |
233 | |
234 | pub fn where_clause_oneline_semi(&mut self, where_clause: &Option<WhereClause>) { |
235 | let hardbreaks = false; |
236 | let semi = true; |
237 | self.where_clause_impl(where_clause, hardbreaks, semi); |
238 | } |
239 | |
240 | fn where_clause_impl( |
241 | &mut self, |
242 | where_clause: &Option<WhereClause>, |
243 | hardbreaks: bool, |
244 | semi: bool, |
245 | ) { |
246 | let where_clause = match where_clause { |
247 | Some(where_clause) if !where_clause.predicates.is_empty() => where_clause, |
248 | _ => { |
249 | if semi { |
250 | self.word(";" ); |
251 | } else { |
252 | self.nbsp(); |
253 | } |
254 | return; |
255 | } |
256 | }; |
257 | if hardbreaks { |
258 | self.hardbreak(); |
259 | self.offset(-INDENT); |
260 | self.word("where" ); |
261 | self.hardbreak(); |
262 | for predicate in where_clause.predicates.iter().delimited() { |
263 | self.where_predicate(&predicate); |
264 | if predicate.is_last && semi { |
265 | self.word(";" ); |
266 | } else { |
267 | self.word("," ); |
268 | self.hardbreak(); |
269 | } |
270 | } |
271 | if !semi { |
272 | self.offset(-INDENT); |
273 | } |
274 | } else { |
275 | self.space(); |
276 | self.offset(-INDENT); |
277 | self.word("where" ); |
278 | self.space(); |
279 | for predicate in where_clause.predicates.iter().delimited() { |
280 | self.where_predicate(&predicate); |
281 | if predicate.is_last && semi { |
282 | self.word(";" ); |
283 | } else { |
284 | self.trailing_comma_or_space(predicate.is_last); |
285 | } |
286 | } |
287 | if !semi { |
288 | self.offset(-INDENT); |
289 | } |
290 | } |
291 | } |
292 | |
293 | fn where_predicate(&mut self, predicate: &WherePredicate) { |
294 | match predicate { |
295 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
296 | WherePredicate::Type(predicate) => self.predicate_type(predicate), |
297 | WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate), |
298 | _ => unimplemented!("unknown WherePredicate" ), |
299 | } |
300 | } |
301 | |
302 | fn predicate_type(&mut self, predicate: &PredicateType) { |
303 | if let Some(bound_lifetimes) = &predicate.lifetimes { |
304 | self.bound_lifetimes(bound_lifetimes); |
305 | } |
306 | self.ty(&predicate.bounded_ty); |
307 | self.word(":" ); |
308 | if predicate.bounds.len() == 1 { |
309 | self.ibox(0); |
310 | } else { |
311 | self.ibox(INDENT); |
312 | } |
313 | for type_param_bound in predicate.bounds.iter().delimited() { |
314 | if type_param_bound.is_first { |
315 | self.nbsp(); |
316 | } else { |
317 | self.space(); |
318 | self.word("+ " ); |
319 | } |
320 | self.type_param_bound(&type_param_bound); |
321 | } |
322 | self.end(); |
323 | } |
324 | |
325 | fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) { |
326 | self.lifetime(&predicate.lifetime); |
327 | self.word(":" ); |
328 | self.ibox(INDENT); |
329 | for lifetime in predicate.bounds.iter().delimited() { |
330 | if lifetime.is_first { |
331 | self.nbsp(); |
332 | } else { |
333 | self.space(); |
334 | self.word("+ " ); |
335 | } |
336 | self.lifetime(&lifetime); |
337 | } |
338 | self.end(); |
339 | } |
340 | |
341 | fn precise_capture(&mut self, precise_capture: &PreciseCapture) { |
342 | self.word("use<" ); |
343 | for capture in precise_capture.params.iter().delimited() { |
344 | self.captured_param(&capture); |
345 | if !capture.is_last { |
346 | self.word(", " ); |
347 | } |
348 | } |
349 | self.word(">" ); |
350 | } |
351 | |
352 | fn captured_param(&mut self, capture: &CapturedParam) { |
353 | match capture { |
354 | #![cfg_attr (all(test, exhaustive), deny(non_exhaustive_omitted_patterns))] |
355 | CapturedParam::Lifetime(lifetime) => self.lifetime(lifetime), |
356 | CapturedParam::Ident(ident) => self.ident(ident), |
357 | _ => unimplemented!("unknown CapturedParam" ), |
358 | } |
359 | } |
360 | |
361 | pub fn const_argument(&mut self, expr: &Expr) { |
362 | match expr { |
363 | #![cfg_attr (all(test, exhaustive), allow(non_exhaustive_omitted_patterns))] |
364 | Expr::Lit(expr) => self.expr_lit(expr), |
365 | |
366 | Expr::Path(expr) |
367 | if expr.attrs.is_empty() |
368 | && expr.qself.is_none() |
369 | && expr.path.get_ident().is_some() => |
370 | { |
371 | self.expr_path(expr); |
372 | } |
373 | |
374 | Expr::Block(expr) => self.expr_block(expr), |
375 | |
376 | _ => { |
377 | self.cbox(INDENT); |
378 | self.expr_as_small_block(expr, 0); |
379 | self.end(); |
380 | } |
381 | } |
382 | } |
383 | } |
384 | |