1use crate::algorithm::Printer;
2use crate::iter::IterDelimited;
3use crate::path::PathKind;
4use crate::INDENT;
5use proc_macro2::TokenStream;
6use std::ptr;
7use syn::{
8 BoundLifetimes, CapturedParam, ConstParam, Expr, GenericParam, Generics, LifetimeParam,
9 PreciseCapture, PredicateLifetime, PredicateType, TraitBound, TraitBoundModifier, TypeParam,
10 TypeParamBound, WhereClause, WherePredicate,
11};
12
13impl 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 #[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 self.trait_bound(trait_bound, TraitBoundConst::None);
109 }
110 TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime),
111 TypeParamBound::PreciseCapture(precise_capture) => {
112 self.precise_capture(precise_capture);
113 }
114 TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound),
115 _ => unimplemented!("unknown TypeParamBound"),
116 }
117 }
118
119 fn trait_bound(&mut self, trait_bound: &TraitBound, constness: TraitBoundConst) {
120 if trait_bound.paren_token.is_some() {
121 self.word("(");
122 }
123 if let Some(bound_lifetimes) = &trait_bound.lifetimes {
124 self.bound_lifetimes(bound_lifetimes);
125 }
126 match constness {
127 TraitBoundConst::None => {}
128 #[cfg(feature = "verbatim")]
129 TraitBoundConst::Conditional => self.word("[const] "),
130 #[cfg(feature = "verbatim")]
131 TraitBoundConst::Unconditional => self.word("const "),
132 }
133 self.trait_bound_modifier(&trait_bound.modifier);
134 for segment in trait_bound.path.segments.iter().delimited() {
135 if !segment.is_first || trait_bound.path.leading_colon.is_some() {
136 self.word("::");
137 }
138 self.path_segment(&segment, PathKind::Type);
139 }
140 if trait_bound.paren_token.is_some() {
141 self.word(")");
142 }
143 }
144
145 fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) {
146 match trait_bound_modifier {
147 TraitBoundModifier::None => {}
148 TraitBoundModifier::Maybe(_question_mark) => self.word("?"),
149 }
150 }
151
152 #[cfg(not(feature = "verbatim"))]
153 fn type_param_bound_verbatim(&mut self, bound: &TokenStream) {
154 unimplemented!("TypeParamBound::Verbatim `{}`", bound);
155 }
156
157 #[cfg(feature = "verbatim")]
158 fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) {
159 use syn::parse::{Parse, ParseStream, Result};
160 use syn::{
161 bracketed, parenthesized, token, ParenthesizedGenericArguments, Path, PathArguments,
162 Token,
163 };
164
165 enum TypeParamBoundVerbatim {
166 Ellipsis,
167 Const(TraitBound, TraitBoundConst),
168 }
169
170 impl Parse for TypeParamBoundVerbatim {
171 fn parse(input: ParseStream) -> Result<Self> {
172 if input.peek(Token![...]) {
173 input.parse::<Token![...]>()?;
174 return Ok(TypeParamBoundVerbatim::Ellipsis);
175 }
176
177 let content;
178 let content = if input.peek(token::Paren) {
179 parenthesized!(content in input);
180 &content
181 } else {
182 input
183 };
184
185 let lifetimes: Option<BoundLifetimes> = content.parse()?;
186
187 let constness = if content.peek(token::Bracket) {
188 let conditionally_const;
189 bracketed!(conditionally_const in content);
190 conditionally_const.parse::<Token![const]>()?;
191 TraitBoundConst::Conditional
192 } else if content.peek(Token![const]) {
193 content.parse::<Token![const]>()?;
194 TraitBoundConst::Unconditional
195 } else {
196 TraitBoundConst::None
197 };
198
199 let modifier: TraitBoundModifier = content.parse()?;
200
201 let mut path: Path = content.parse()?;
202 if path.segments.last().unwrap().arguments.is_empty()
203 && (content.peek(token::Paren)
204 || content.peek(Token![::]) && content.peek3(token::Paren))
205 {
206 content.parse::<Option<Token![::]>>()?;
207 let args: ParenthesizedGenericArguments = content.parse()?;
208 let parenthesized = PathArguments::Parenthesized(args);
209 path.segments.last_mut().unwrap().arguments = parenthesized;
210 }
211
212 Ok(TypeParamBoundVerbatim::Const(
213 TraitBound {
214 paren_token: None,
215 modifier,
216 lifetimes,
217 path,
218 },
219 constness,
220 ))
221 }
222 }
223
224 let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) {
225 Ok(bound) => bound,
226 Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens),
227 };
228
229 match bound {
230 TypeParamBoundVerbatim::Ellipsis => {
231 self.word("...");
232 }
233 TypeParamBoundVerbatim::Const(trait_bound, constness) => {
234 self.trait_bound(&trait_bound, constness);
235 }
236 }
237 }
238
239 fn const_param(&mut self, const_param: &ConstParam) {
240 self.outer_attrs(&const_param.attrs);
241 self.word("const ");
242 self.ident(&const_param.ident);
243 self.word(": ");
244 self.ty(&const_param.ty);
245 if let Some(default) = &const_param.default {
246 self.word(" = ");
247 self.const_argument(default);
248 }
249 }
250
251 pub fn where_clause_for_body(&mut self, where_clause: &Option<WhereClause>) {
252 let hardbreaks = true;
253 let semi = false;
254 self.where_clause_impl(where_clause, hardbreaks, semi);
255 }
256
257 pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) {
258 let hardbreaks = true;
259 let semi = true;
260 self.where_clause_impl(where_clause, hardbreaks, semi);
261 }
262
263 pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) {
264 let hardbreaks = false;
265 let semi = false;
266 self.where_clause_impl(where_clause, hardbreaks, semi);
267 }
268
269 pub fn where_clause_oneline_semi(&mut self, where_clause: &Option<WhereClause>) {
270 let hardbreaks = false;
271 let semi = true;
272 self.where_clause_impl(where_clause, hardbreaks, semi);
273 }
274
275 fn where_clause_impl(
276 &mut self,
277 where_clause: &Option<WhereClause>,
278 hardbreaks: bool,
279 semi: bool,
280 ) {
281 let where_clause = match where_clause {
282 Some(where_clause) if !where_clause.predicates.is_empty() => where_clause,
283 _ => {
284 if semi {
285 self.word(";");
286 } else {
287 self.nbsp();
288 }
289 return;
290 }
291 };
292 if hardbreaks {
293 self.hardbreak();
294 self.offset(-INDENT);
295 self.word("where");
296 self.hardbreak();
297 for predicate in where_clause.predicates.iter().delimited() {
298 self.where_predicate(&predicate);
299 if predicate.is_last && semi {
300 self.word(";");
301 } else {
302 self.word(",");
303 self.hardbreak();
304 }
305 }
306 if !semi {
307 self.offset(-INDENT);
308 }
309 } else {
310 self.space();
311 self.offset(-INDENT);
312 self.word("where");
313 self.space();
314 for predicate in where_clause.predicates.iter().delimited() {
315 self.where_predicate(&predicate);
316 if predicate.is_last && semi {
317 self.word(";");
318 } else {
319 self.trailing_comma_or_space(predicate.is_last);
320 }
321 }
322 if !semi {
323 self.offset(-INDENT);
324 }
325 }
326 }
327
328 fn where_predicate(&mut self, predicate: &WherePredicate) {
329 match predicate {
330 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
331 WherePredicate::Type(predicate) => self.predicate_type(predicate),
332 WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate),
333 _ => unimplemented!("unknown WherePredicate"),
334 }
335 }
336
337 fn predicate_type(&mut self, predicate: &PredicateType) {
338 if let Some(bound_lifetimes) = &predicate.lifetimes {
339 self.bound_lifetimes(bound_lifetimes);
340 }
341 self.ty(&predicate.bounded_ty);
342 self.word(":");
343 if predicate.bounds.len() == 1 {
344 self.ibox(0);
345 } else {
346 self.ibox(INDENT);
347 }
348 for type_param_bound in predicate.bounds.iter().delimited() {
349 if type_param_bound.is_first {
350 self.nbsp();
351 } else {
352 self.space();
353 self.word("+ ");
354 }
355 self.type_param_bound(&type_param_bound);
356 }
357 self.end();
358 }
359
360 fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) {
361 self.lifetime(&predicate.lifetime);
362 self.word(":");
363 self.ibox(INDENT);
364 for lifetime in predicate.bounds.iter().delimited() {
365 if lifetime.is_first {
366 self.nbsp();
367 } else {
368 self.space();
369 self.word("+ ");
370 }
371 self.lifetime(&lifetime);
372 }
373 self.end();
374 }
375
376 fn precise_capture(&mut self, precise_capture: &PreciseCapture) {
377 self.word("use<");
378 for capture in precise_capture.params.iter().delimited() {
379 self.captured_param(&capture);
380 if !capture.is_last {
381 self.word(", ");
382 }
383 }
384 self.word(">");
385 }
386
387 fn captured_param(&mut self, capture: &CapturedParam) {
388 match capture {
389 #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
390 CapturedParam::Lifetime(lifetime) => self.lifetime(lifetime),
391 CapturedParam::Ident(ident) => self.ident(ident),
392 _ => unimplemented!("unknown CapturedParam"),
393 }
394 }
395
396 pub fn const_argument(&mut self, expr: &Expr) {
397 match expr {
398 #![cfg_attr(all(test, exhaustive), allow(non_exhaustive_omitted_patterns))]
399 Expr::Lit(expr) => self.expr_lit(expr),
400
401 Expr::Path(expr)
402 if expr.attrs.is_empty()
403 && expr.qself.is_none()
404 && expr.path.get_ident().is_some() =>
405 {
406 self.expr_path(expr);
407 }
408
409 Expr::Block(expr) => self.expr_block(expr),
410
411 _ => {
412 self.cbox(INDENT);
413 self.expr_as_small_block(expr, 0);
414 self.end();
415 }
416 }
417 }
418}
419
420enum TraitBoundConst {
421 None,
422 #[cfg(feature = "verbatim")]
423 Conditional,
424 #[cfg(feature = "verbatim")]
425 Unconditional,
426}