prettyplease/
generics.rs

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        // 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(&param);
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}