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 #[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 TypeParamBound::Trait(trait_bound) => {
107 let tilde_const = false;
108 self.trait_bound(trait_bound, tilde_const);
109 }
110 TypeParamBound::Lifetime(lifetime) => self.lifetime(lifetime),
111 TypeParamBound::Verbatim(bound) => self.type_param_bound_verbatim(bound),
112 #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
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, Token};
155
156 enum TypeParamBoundVerbatim {
157 TildeConst(TraitBound),
158 }
159
160 impl Parse for TypeParamBoundVerbatim {
161 fn parse(input: ParseStream) -> Result<Self> {
162 let content;
163 let (paren_token, content) = if input.peek(token::Paren) {
164 (Some(parenthesized!(content in input)), &content)
165 } else {
166 (None, input)
167 };
168 content.parse::<Token![~]>()?;
169 content.parse::<Token![const]>()?;
170 let mut bound: TraitBound = content.parse()?;
171 bound.paren_token = paren_token;
172 Ok(TypeParamBoundVerbatim::TildeConst(bound))
173 }
174 }
175
176 let bound: TypeParamBoundVerbatim = match syn::parse2(tokens.clone()) {
177 Ok(bound) => bound,
178 Err(_) => unimplemented!("TypeParamBound::Verbatim `{}`", tokens),
179 };
180
181 match bound {
182 TypeParamBoundVerbatim::TildeConst(trait_bound) => {
183 let tilde_const = true;
184 self.trait_bound(&trait_bound, tilde_const);
185 }
186 }
187 }
188
189 fn const_param(&mut self, const_param: &ConstParam) {
190 self.outer_attrs(&const_param.attrs);
191 self.word("const ");
192 self.ident(&const_param.ident);
193 self.word(": ");
194 self.ty(&const_param.ty);
195 if let Some(default) = &const_param.default {
196 self.word(" = ");
197 self.expr(default);
198 }
199 }
200
201 pub fn where_clause_for_body(&mut self, where_clause: &Option<WhereClause>) {
202 let hardbreaks = true;
203 let semi = false;
204 self.where_clause_impl(where_clause, hardbreaks, semi);
205 }
206
207 pub fn where_clause_semi(&mut self, where_clause: &Option<WhereClause>) {
208 let hardbreaks = true;
209 let semi = true;
210 self.where_clause_impl(where_clause, hardbreaks, semi);
211 }
212
213 pub fn where_clause_oneline(&mut self, where_clause: &Option<WhereClause>) {
214 let hardbreaks = false;
215 let semi = false;
216 self.where_clause_impl(where_clause, hardbreaks, semi);
217 }
218
219 pub fn where_clause_oneline_semi(&mut self, where_clause: &Option<WhereClause>) {
220 let hardbreaks = false;
221 let semi = true;
222 self.where_clause_impl(where_clause, hardbreaks, semi);
223 }
224
225 fn where_clause_impl(
226 &mut self,
227 where_clause: &Option<WhereClause>,
228 hardbreaks: bool,
229 semi: bool,
230 ) {
231 let where_clause = match where_clause {
232 Some(where_clause) if !where_clause.predicates.is_empty() => where_clause,
233 _ => {
234 if semi {
235 self.word(";");
236 } else {
237 self.nbsp();
238 }
239 return;
240 }
241 };
242 if hardbreaks {
243 self.hardbreak();
244 self.offset(-INDENT);
245 self.word("where");
246 self.hardbreak();
247 for predicate in where_clause.predicates.iter().delimited() {
248 self.where_predicate(&predicate);
249 if predicate.is_last && semi {
250 self.word(";");
251 } else {
252 self.word(",");
253 self.hardbreak();
254 }
255 }
256 if !semi {
257 self.offset(-INDENT);
258 }
259 } else {
260 self.space();
261 self.offset(-INDENT);
262 self.word("where");
263 self.space();
264 for predicate in where_clause.predicates.iter().delimited() {
265 self.where_predicate(&predicate);
266 if predicate.is_last && semi {
267 self.word(";");
268 } else {
269 self.trailing_comma_or_space(predicate.is_last);
270 }
271 }
272 if !semi {
273 self.offset(-INDENT);
274 }
275 }
276 }
277
278 fn where_predicate(&mut self, predicate: &WherePredicate) {
279 match predicate {
280 WherePredicate::Type(predicate) => self.predicate_type(predicate),
281 WherePredicate::Lifetime(predicate) => self.predicate_lifetime(predicate),
282 #[cfg_attr(all(test, exhaustive), deny(non_exhaustive_omitted_patterns))]
283 _ => unimplemented!("unknown WherePredicate"),
284 }
285 }
286
287 fn predicate_type(&mut self, predicate: &PredicateType) {
288 if let Some(bound_lifetimes) = &predicate.lifetimes {
289 self.bound_lifetimes(bound_lifetimes);
290 }
291 self.ty(&predicate.bounded_ty);
292 self.word(":");
293 if predicate.bounds.len() == 1 {
294 self.ibox(0);
295 } else {
296 self.ibox(INDENT);
297 }
298 for type_param_bound in predicate.bounds.iter().delimited() {
299 if type_param_bound.is_first {
300 self.nbsp();
301 } else {
302 self.space();
303 self.word("+ ");
304 }
305 self.type_param_bound(&type_param_bound);
306 }
307 self.end();
308 }
309
310 fn predicate_lifetime(&mut self, predicate: &PredicateLifetime) {
311 self.lifetime(&predicate.lifetime);
312 self.word(":");
313 self.ibox(INDENT);
314 for lifetime in predicate.bounds.iter().delimited() {
315 if lifetime.is_first {
316 self.nbsp();
317 } else {
318 self.space();
319 self.word("+ ");
320 }
321 self.lifetime(&lifetime);
322 }
323 self.end();
324 }
325}