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