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, ConstParam, GenericParam, Generics, LifetimeParam, PredicateLifetime,
9    PredicateType, TraitBound, TraitBoundModifier, TypeParam, TypeParamBound, WhereClause,
10    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                let tilde_const = false;
109                self.trait_bound(trait_bound, tilde_const);
110            }
111            TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime),
112            TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound),
113            _ => unimplemented!("unknown TypeParamBound"),
114        }
115    }
116
117    fn trait_bound(&mut self, trait_bound: &TraitBound, tilde_const: bool) {
118        if trait_bound.paren_token.is_some() {
119            self.word("(");
120        }
121        if tilde_const {
122            self.word("~const ");
123        }
124        self.trait_bound_modifier(&trait_bound.modifier);
125        if let Some(bound_lifetimes) = &trait_bound.lifetimes {
126            self.bound_lifetimes(bound_lifetimes);
127        }
128        for segment in trait_bound.path.segments.iter().delimited() {
129            if !segment.is_first || trait_bound.path.leading_colon.is_some() {
130                self.word("::");
131            }
132            self.path_segment(&segment, PathKind::Type);
133        }
134        if trait_bound.paren_token.is_some() {
135            self.word(")");
136        }
137    }
138
139    fn trait_bound_modifier(&mut self, trait_bound_modifier: &TraitBoundModifier) {
140        match trait_bound_modifier {
141            TraitBoundModifier::None => {}
142            TraitBoundModifier::Maybe(_question_mark) => self.word("?"),
143        }
144    }
145
146    #[cfg(not(feature = "verbatim"))]
147    fn type_param_bound_verbatim(&mut self, bound: &TokenStream) {
148        unimplemented!("TypeParamBound::Verbatim `{}`", bound);
149    }
150
151    #[cfg(feature = "verbatim")]
152    fn type_param_bound_verbatim(&mut self, tokens: &TokenStream) {
153        use syn::parse::{Parse, ParseStream, Result};
154        use syn::{parenthesized, token, Ident, Lifetime, Token};
155
156        enum TypeParamBoundVerbatim {
157            Ellipsis,
158            PreciseCapture(Vec<Capture>),
159            TildeConst(TraitBound),
160        }
161
162        enum Capture {
163            Lifetime(Lifetime),
164            Type(Ident),
165        }
166
167        impl Parse for TypeParamBoundVerbatim {
168            fn parse(input: ParseStream) -> Result<Self> {
169                let content;
170                let (paren_token, content) = if input.peek(token::Paren) {
171                    (Some(parenthesized!(content in input)), &content)
172                } else {
173                    (None, input)
174                };
175                let lookahead = content.lookahead1();
176                if lookahead.peek(Token![use]) {
177                    input.parse::<Token![use]>()?;
178                    input.parse::<Token![<]>()?;
179                    let mut captures = Vec::new();
180                    loop {
181                        let lookahead = input.lookahead1();
182                        captures.push(if lookahead.peek(Lifetime) {
183                            input.parse().map(Capture::Lifetime)?
184                        } else if lookahead.peek(Ident) {
185                            input.parse().map(Capture::Type)?
186                        } else if lookahead.peek(Token![>]) {
187                            break;
188                        } else {
189                            return Err(lookahead.error());
190                        });
191                        let lookahead = input.lookahead1();
192                        if lookahead.peek(Token![,]) {
193                            input.parse::<Token![,]>()?;
194                        } else if lookahead.peek(Token![>]) {
195                            break;
196                        } else {
197                            return Err(lookahead.error());
198                        }
199                    }
200                    input.parse::<Token![>]>()?;
201                    Ok(TypeParamBoundVerbatim::PreciseCapture(captures))
202                } else if lookahead.peek(Token![~]) {
203                    content.parse::<Token![~]>()?;
204                    content.parse::<Token![const]>()?;
205                    let mut bound: TraitBound = content.parse()?;
206                    bound.paren_token = paren_token;
207                    Ok(TypeParamBoundVerbatim::TildeConst(bound))
208                } else if lookahead.peek(Token![...]) {
209                    content.parse::<Token![...]>()?;
210                    Ok(TypeParamBoundVerbatim::Ellipsis)
211                } else {
212                    Err(lookahead.error())
213                }
214            }
215        }
216
217        let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) {
218            Ok(bound) => bound,
219            Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens),
220        };
221
222        match bound {
223            TypeParamBoundVerbatim::Ellipsis => {
224                self.word("...");
225            }
226            TypeParamBoundVerbatim::PreciseCapture(captures) => {
227                self.word("use<");
228                for capture in captures.iter().delimited() {
229                    match *capture {
230                        Capture::Lifetime(lifetime) => self.lifetime(lifetime),
231                        Capture::Type(ident) => self.ident(ident),
232                    }
233                    if !capture.is_last {
234                        self.word(", ");
235                    }
236                }
237                self.word(">");
238            }
239            TypeParamBoundVerbatim::TildeConst(trait_bound) => {
240                let tilde_const = true;
241                self.trait_bound(&trait_bound, tilde_const);
242            }
243        }
244    }
245
246    fn const_param(&mut self, const_param: &ConstParam) {
247        self.outer_attrs(&const_param.attrs);
248        self.word("const ");
249        self.ident(&const_param.ident);
250        self.word(": ");
251        self.ty(&const_param.ty);
252        if let Some(default) = &const_param.default {
253            self.word(" = ");
254            self.expr(default);
255        }
256    }
257
258    pub fn where_clause_for_body(&mut self, where_clause: &Option<WhereClause>) {
259        let hardbreaks = true;
260        let semi = false;
261        self.where_clause_impl(where_clause, hardbreaks, semi);
262    }
263
264    pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) {
265        let hardbreaks = true;
266        let semi = true;
267        self.where_clause_impl(where_clause, hardbreaks, semi);
268    }
269
270    pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) {
271        let hardbreaks = false;
272        let semi = false;
273        self.where_clause_impl(where_clause, hardbreaks, semi);
274    }
275
276    pub fn where_clause_oneline_semi(&mut self, where_clause: &Option<WhereClause>) {
277        let hardbreaks = false;
278        let semi = true;
279        self.where_clause_impl(where_clause, hardbreaks, semi);
280    }
281
282    fn where_clause_impl(
283        &mut self,
284        where_clause: &Option<WhereClause>,
285        hardbreaks: bool,
286        semi: bool,
287    ) {
288        let where_clause = match where_clause {
289            Some(where_clause) if !where_clause.predicates.is_empty() => where_clause,
290            _ => {
291                if semi {
292                    self.word(";");
293                } else {
294                    self.nbsp();
295                }
296                return;
297            }
298        };
299        if hardbreaks {
300            self.hardbreak();
301            self.offset(-INDENT);
302            self.word("where");
303            self.hardbreak();
304            for predicate in where_clause.predicates.iter().delimited() {
305                self.where_predicate(&predicate);
306                if predicate.is_last && semi {
307                    self.word(";");
308                } else {
309                    self.word(",");
310                    self.hardbreak();
311                }
312            }
313            if !semi {
314                self.offset(-INDENT);
315            }
316        } else {
317            self.space();
318            self.offset(-INDENT);
319            self.word("where");
320            self.space();
321            for predicate in where_clause.predicates.iter().delimited() {
322                self.where_predicate(&predicate);
323                if predicate.is_last && semi {
324                    self.word(";");
325                } else {
326                    self.trailing_comma_or_space(predicate.is_last);
327                }
328            }
329            if !semi {
330                self.offset(-INDENT);
331            }
332        }
333    }
334
335    fn where_predicate(&mut self, predicate: &WherePredicate) {
336        match predicate {
337            #![cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
338            WherePredicate::Type(predicate) => self.predicate_type(predicate),
339            WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate),
340            _ => unimplemented!("unknown WherePredicate"),
341        }
342    }
343
344    fn predicate_type(&mut self, predicate: &PredicateType) {
345        if let Some(bound_lifetimes) = &predicate.lifetimes {
346            self.bound_lifetimes(bound_lifetimes);
347        }
348        self.ty(&predicate.bounded_ty);
349        self.word(":");
350        if predicate.bounds.len() == 1 {
351            self.ibox(0);
352        } else {
353            self.ibox(INDENT);
354        }
355        for type_param_bound in predicate.bounds.iter().delimited() {
356            if type_param_bound.is_first {
357                self.nbsp();
358            } else {
359                self.space();
360                self.word("+ ");
361            }
362            self.type_param_bound(&type_param_bound);
363        }
364        self.end();
365    }
366
367    fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) {
368        self.lifetime(&predicate.lifetime);
369        self.word(":");
370        self.ibox(INDENT);
371        for lifetime in predicate.bounds.iter().delimited() {
372            if lifetime.is_first {
373                self.nbsp();
374            } else {
375                self.space();
376                self.word("+ ");
377            }
378            self.lifetime(&lifetime);
379        }
380        self.end();
381    }
382}