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 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}