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