1use std::borrow::Cow;
4use std::cmp::{Ordering, max, min};
5
6use regex::Regex;
7use rustc_ast::ast;
8use rustc_ast::visit;
9use rustc_span::{BytePos, DUMMY_SP, Ident, Span, symbol};
10use tracing::debug;
11
12use crate::attr::filter_inline_attrs;
13use crate::comment::{
14 FindUncommented, combine_strs_with_missing_comments, contains_comment, is_last_comment_block,
15 recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment,
16};
17use crate::config::lists::*;
18use crate::config::{BraceStyle, Config, IndentStyle, StyleEdition};
19use crate::expr::{
20 RhsAssignKind, RhsTactics, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
21 rewrite_assign_rhs_with, rewrite_assign_rhs_with_comments, rewrite_else_kw_with_comments,
22 rewrite_let_else_block,
23};
24use crate::lists::{ListFormatting, Separator, definitive_tactic, itemize_list, write_list};
25use crate::macros::{MacroPosition, rewrite_macro};
26use crate::overflow;
27use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, RewriteResult};
28use crate::shape::{Indent, Shape};
29use crate::source_map::{LineRangeUtils, SpanUtils};
30use crate::spanned::Spanned;
31use crate::stmt::Stmt;
32use crate::types::opaque_ty;
33use crate::utils::*;
34use crate::vertical::rewrite_with_alignment;
35use crate::visitor::FmtVisitor;
36
37const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
38 kind: ast::VisibilityKind::Inherited,
39 span: DUMMY_SP,
40 tokens: None,
41};
42
43fn type_annotation_separator(config: &Config) -> &str {
44 colon_spaces(config)
45}
46
47impl Rewrite for ast::Local {
50 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
51 self.rewrite_result(context, shape).ok()
52 }
53
54 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
55 debug!(
56 "Local::rewrite {:?} {} {:?}",
57 self, shape.width, shape.indent
58 );
59
60 skip_out_of_file_lines_range_err!(context, self.span);
61
62 if contains_skip(&self.attrs) {
63 return Err(RewriteError::SkipFormatting);
64 }
65
66 if self.super_.is_some() {
68 return Err(RewriteError::SkipFormatting);
69 }
70
71 let attrs_str = self.attrs.rewrite_result(context, shape)?;
72 let mut result = if attrs_str.is_empty() {
73 "let ".to_owned()
74 } else {
75 combine_strs_with_missing_comments(
76 context,
77 &attrs_str,
78 "let ",
79 mk_sp(
80 self.attrs.last().map(|a| a.span.hi()).unwrap(),
81 self.span.lo(),
82 ),
83 shape,
84 false,
85 )?
86 };
87 let let_kw_offset = result.len() - "let ".len();
88
89 let pat_shape = shape
91 .offset_left(4)
92 .max_width_error(shape.width, self.span())?;
93 let pat_shape = pat_shape
95 .sub_width(1)
96 .max_width_error(shape.width, self.span())?;
97 let pat_str = self.pat.rewrite_result(context, pat_shape)?;
98
99 result.push_str(&pat_str);
100
101 let infix = {
103 let mut infix = String::with_capacity(32);
104
105 if let Some(ref ty) = self.ty {
106 let separator = type_annotation_separator(context.config);
107 let ty_shape = if pat_str.contains('\n') {
108 shape.with_max_width(context.config)
109 } else {
110 shape
111 }
112 .offset_left(last_line_width(&result) + separator.len())
113 .max_width_error(shape.width, self.span())?
114 .sub_width(2)
116 .max_width_error(shape.width, self.span())?;
117
118 let rewrite = ty.rewrite_result(context, ty_shape)?;
119
120 infix.push_str(separator);
121 infix.push_str(&rewrite);
122 }
123
124 if self.kind.init().is_some() {
125 infix.push_str(" =");
126 }
127
128 infix
129 };
130
131 result.push_str(&infix);
132
133 if let Some((init, else_block)) = self.kind.init_else_opt() {
134 let nested_shape = shape
136 .sub_width(1)
137 .max_width_error(shape.width, self.span())?;
138
139 result = rewrite_assign_rhs(
140 context,
141 result,
142 init,
143 &RhsAssignKind::Expr(&init.kind, init.span),
144 nested_shape,
145 )?;
146
147 if let Some(block) = else_block {
148 let else_kw_span = init.span.between(block.span);
149 let style_edition = context.config.style_edition();
152 let init_str = if style_edition >= StyleEdition::Edition2024 {
153 &result[let_kw_offset..]
154 } else {
155 result.as_str()
156 };
157 let force_newline_else = pat_str.contains('\n')
158 || !same_line_else_kw_and_brace(init_str, context, else_kw_span, nested_shape);
159 let else_kw = rewrite_else_kw_with_comments(
160 force_newline_else,
161 true,
162 context,
163 else_kw_span,
164 shape,
165 );
166 result.push_str(&else_kw);
167
168 let max_width =
173 std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
174
175 let style_edition = context.config.style_edition();
177 let assign_str_with_else_kw = if style_edition >= StyleEdition::Edition2024 {
178 &result[let_kw_offset..]
179 } else {
180 result.as_str()
181 };
182 let available_space = max_width.saturating_sub(assign_str_with_else_kw.len());
183
184 let allow_single_line = !force_newline_else
185 && available_space > 0
186 && allow_single_line_let_else_block(assign_str_with_else_kw, block);
187
188 let mut rw_else_block =
189 rewrite_let_else_block(block, allow_single_line, context, shape)?;
190
191 let single_line_else = !rw_else_block.contains('\n');
192 let else_block_exceeds_width = rw_else_block.len() + 1 > available_space;
194
195 if allow_single_line && single_line_else && else_block_exceeds_width {
196 rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
199 }
200
201 result.push_str(&rw_else_block);
202 };
203 }
204
205 result.push(';');
206 Ok(result)
207 }
208}
209
210fn same_line_else_kw_and_brace(
219 init_str: &str,
220 context: &RewriteContext<'_>,
221 else_kw_span: Span,
222 init_shape: Shape,
223) -> bool {
224 if !init_str.contains('\n') {
225 return init_shape.width.saturating_sub(init_str.len()) >= 7;
229 }
230
231 if !init_str.ends_with([')', ']', '}']) {
233 return false;
234 }
235
236 let else_kw_snippet = context.snippet(else_kw_span).trim();
239 if else_kw_snippet != "else" {
240 return false;
241 }
242
243 let indent = init_shape.indent.to_string(context.config);
245 init_str
246 .lines()
247 .last()
248 .expect("initializer expression is multi-lined")
249 .strip_prefix(indent.as_ref())
250 .map_or(false, |l| !l.starts_with(char::is_whitespace))
251}
252
253fn allow_single_line_let_else_block(result: &str, block: &ast::Block) -> bool {
254 if result.contains('\n') {
255 return false;
256 }
257
258 if block.stmts.len() <= 1 {
259 return true;
260 }
261
262 false
263}
264
265#[allow(dead_code)]
268#[derive(Debug)]
269struct Item<'a> {
270 safety: ast::Safety,
271 abi: Cow<'static, str>,
272 vis: Option<&'a ast::Visibility>,
273 body: Vec<BodyElement<'a>>,
274 span: Span,
275}
276
277impl<'a> Item<'a> {
278 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
279 Item {
280 safety: fm.safety,
281 abi: format_extern(
282 ast::Extern::from_abi(fm.abi, DUMMY_SP),
283 config.force_explicit_abi(),
284 ),
285 vis: None,
286 body: fm
287 .items
288 .iter()
289 .map(|i| BodyElement::ForeignItem(i))
290 .collect(),
291 span,
292 }
293 }
294}
295
296#[derive(Debug)]
297enum BodyElement<'a> {
298 ForeignItem(&'a ast::ForeignItem),
303}
304
305pub(crate) struct FnSig<'a> {
307 decl: &'a ast::FnDecl,
308 generics: &'a ast::Generics,
309 ext: ast::Extern,
310 coroutine_kind: Cow<'a, Option<ast::CoroutineKind>>,
311 constness: ast::Const,
312 defaultness: ast::Defaultness,
313 safety: ast::Safety,
314 visibility: &'a ast::Visibility,
315}
316
317impl<'a> FnSig<'a> {
318 pub(crate) fn from_method_sig(
319 method_sig: &'a ast::FnSig,
320 generics: &'a ast::Generics,
321 visibility: &'a ast::Visibility,
322 ) -> FnSig<'a> {
323 FnSig {
324 safety: method_sig.header.safety,
325 coroutine_kind: Cow::Borrowed(&method_sig.header.coroutine_kind),
326 constness: method_sig.header.constness,
327 defaultness: ast::Defaultness::Final,
328 ext: method_sig.header.ext,
329 decl: &*method_sig.decl,
330 generics,
331 visibility,
332 }
333 }
334
335 pub(crate) fn from_fn_kind(
336 fn_kind: &'a visit::FnKind<'_>,
337 decl: &'a ast::FnDecl,
338 defaultness: ast::Defaultness,
339 ) -> FnSig<'a> {
340 match *fn_kind {
341 visit::FnKind::Fn(visit::FnCtxt::Assoc(..), vis, ast::Fn { sig, generics, .. }) => {
342 let mut fn_sig = FnSig::from_method_sig(sig, generics, vis);
343 fn_sig.defaultness = defaultness;
344 fn_sig
345 }
346 visit::FnKind::Fn(_, vis, ast::Fn { sig, generics, .. }) => FnSig {
347 decl,
348 generics,
349 ext: sig.header.ext,
350 constness: sig.header.constness,
351 coroutine_kind: Cow::Borrowed(&sig.header.coroutine_kind),
352 defaultness,
353 safety: sig.header.safety,
354 visibility: vis,
355 },
356 _ => unreachable!(),
357 }
358 }
359
360 fn to_str(&self, context: &RewriteContext<'_>) -> String {
361 let mut result = String::with_capacity(128);
362 result.push_str(&*format_visibility(context, self.visibility));
364 result.push_str(format_defaultness(self.defaultness));
365 result.push_str(format_constness(self.constness));
366 self.coroutine_kind
367 .map(|coroutine_kind| result.push_str(format_coro(&coroutine_kind)));
368 result.push_str(format_safety(self.safety));
369 result.push_str(&format_extern(
370 self.ext,
371 context.config.force_explicit_abi(),
372 ));
373 result
374 }
375}
376
377impl<'a> FmtVisitor<'a> {
378 fn format_item(&mut self, item: &Item<'_>) {
379 self.buffer.push_str(format_safety(item.safety));
380 self.buffer.push_str(&item.abi);
381
382 let snippet = self.snippet(item.span);
383 let brace_pos = snippet.find_uncommented("{").unwrap();
384
385 self.push_str("{");
386 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
387 self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
390 self.block_indent = self.block_indent.block_indent(self.config);
391
392 if !item.body.is_empty() {
393 for item in &item.body {
394 self.format_body_element(item);
395 }
396 }
397
398 self.format_missing_no_indent(item.span.hi() - BytePos(1));
399 self.block_indent = self.block_indent.block_unindent(self.config);
400 let indent_str = self.block_indent.to_string(self.config);
401 self.push_str(&indent_str);
402 }
403
404 self.push_str("}");
405 self.last_pos = item.span.hi();
406 }
407
408 fn format_body_element(&mut self, element: &BodyElement<'_>) {
409 match *element {
410 BodyElement::ForeignItem(item) => self.format_foreign_item(item),
411 }
412 }
413
414 pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
415 let item = Item::from_foreign_mod(fm, span, self.config);
416 self.format_item(&item);
417 }
418
419 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
420 let rewrite = item.rewrite(&self.get_context(), self.shape());
421 let hi = item.span.hi();
422 let span = if item.attrs.is_empty() {
423 item.span
424 } else {
425 mk_sp(item.attrs[0].span.lo(), hi)
426 };
427 self.push_rewrite(span, rewrite);
428 self.last_pos = hi;
429 }
430
431 pub(crate) fn rewrite_fn_before_block(
432 &mut self,
433 indent: Indent,
434 ident: symbol::Ident,
435 fn_sig: &FnSig<'_>,
436 span: Span,
437 ) -> Option<(String, FnBraceStyle)> {
438 let context = self.get_context();
439
440 let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
441 let (result, _, force_newline_brace) =
442 rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style).ok()?;
443
444 if self.config.brace_style() == BraceStyle::AlwaysNextLine
446 || force_newline_brace
447 || last_line_width(&result) + 2 > self.shape().width
448 {
449 fn_brace_style = FnBraceStyle::NextLine
450 }
451
452 Some((result, fn_brace_style))
453 }
454
455 pub(crate) fn rewrite_required_fn(
456 &mut self,
457 indent: Indent,
458 ident: symbol::Ident,
459 sig: &ast::FnSig,
460 vis: &ast::Visibility,
461 generics: &ast::Generics,
462 span: Span,
463 ) -> RewriteResult {
464 let span = mk_sp(span.lo(), span.hi() - BytePos(1));
466 let context = self.get_context();
467
468 let (mut result, ends_with_comment, _) = rewrite_fn_base(
469 &context,
470 indent,
471 ident,
472 &FnSig::from_method_sig(sig, generics, vis),
473 span,
474 FnBraceStyle::None,
475 )?;
476
477 if ends_with_comment {
479 result.push_str(&indent.to_string_with_newline(context.config));
480 }
481
482 result.push(';');
484
485 Ok(result)
486 }
487
488 pub(crate) fn single_line_fn(
489 &self,
490 fn_str: &str,
491 block: &ast::Block,
492 inner_attrs: Option<&[ast::Attribute]>,
493 ) -> Option<String> {
494 if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
495 return None;
496 }
497
498 let context = self.get_context();
499
500 if self.config.empty_item_single_line()
501 && is_empty_block(&context, block, None)
502 && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
503 && !last_line_contains_single_line_comment(fn_str)
504 {
505 return Some(format!("{fn_str} {{}}"));
506 }
507
508 if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
509 return None;
510 }
511
512 let res = Stmt::from_ast_node(block.stmts.first()?, true)
513 .rewrite(&self.get_context(), self.shape())?;
514
515 let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
516 if !res.contains('\n') && width <= self.config.max_width() {
517 Some(format!("{fn_str} {{ {res} }}"))
518 } else {
519 None
520 }
521 }
522
523 pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
524 let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
525 self.push_rewrite(static_parts.span, rewrite);
526 }
527
528 pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
529 let is_tuple = match struct_parts.def {
530 ast::VariantData::Tuple(..) => true,
531 _ => false,
532 };
533 let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
534 .map(|s| if is_tuple { s + ";" } else { s });
535 self.push_rewrite(struct_parts.span, rewrite);
536 }
537
538 pub(crate) fn visit_enum(
539 &mut self,
540 ident: symbol::Ident,
541 vis: &ast::Visibility,
542 enum_def: &ast::EnumDef,
543 generics: &ast::Generics,
544 span: Span,
545 ) {
546 let enum_header =
547 format_header(&self.get_context(), "enum ", ident, vis, self.block_indent);
548 self.push_str(&enum_header);
549
550 let enum_snippet = self.snippet(span);
551 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
552 let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
553 let generics_str = format_generics(
554 &self.get_context(),
555 generics,
556 self.config.brace_style(),
557 if enum_def.variants.is_empty() {
558 BracePos::ForceSameLine
559 } else {
560 BracePos::Auto
561 },
562 self.block_indent,
563 mk_sp(ident.span.hi(), body_start),
565 last_line_width(&enum_header),
566 )
567 .unwrap();
568 self.push_str(&generics_str);
569
570 self.last_pos = body_start;
571
572 match self.format_variant_list(enum_def, body_start, span.hi()) {
573 Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
574 rw => {
575 self.push_rewrite(mk_sp(body_start, span.hi()), rw);
576 self.block_indent = self.block_indent.block_unindent(self.config);
577 }
578 }
579 }
580
581 fn format_variant_list(
583 &mut self,
584 enum_def: &ast::EnumDef,
585 body_lo: BytePos,
586 body_hi: BytePos,
587 ) -> Option<String> {
588 if enum_def.variants.is_empty() {
589 let mut buffer = String::with_capacity(128);
590 let span = mk_sp(body_lo, body_hi - BytePos(1));
592 format_empty_struct_or_tuple(
593 &self.get_context(),
594 span,
595 self.block_indent,
596 &mut buffer,
597 "",
598 "}",
599 );
600 return Some(buffer);
601 }
602 let mut result = String::with_capacity(1024);
603 let original_offset = self.block_indent;
604 self.block_indent = self.block_indent.block_indent(self.config);
605
606 let align_threshold: usize = self.config.enum_discrim_align_threshold();
609 let discr_ident_lens: Vec<usize> = enum_def
610 .variants
611 .iter()
612 .filter(|var| var.disr_expr.is_some())
613 .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
614 .collect();
615 let pad_discrim_ident_to = *discr_ident_lens
618 .iter()
619 .filter(|&l| *l <= align_threshold)
620 .max()
621 .unwrap_or(&0);
622
623 let itemize_list_with = |one_line_width: usize| {
624 itemize_list(
625 self.snippet_provider,
626 enum_def.variants.iter(),
627 "}",
628 ",",
629 |f| {
630 if !f.attrs.is_empty() {
631 f.attrs[0].span.lo()
632 } else {
633 f.span.lo()
634 }
635 },
636 |f| f.span.hi(),
637 |f| {
638 self.format_variant(f, one_line_width, pad_discrim_ident_to)
639 .unknown_error()
640 },
641 body_lo,
642 body_hi,
643 false,
644 )
645 .collect()
646 };
647 let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width());
648
649 let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
651 let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
652 if has_multiline_variant && has_single_line_variant {
653 items = itemize_list_with(0);
654 }
655
656 let shape = self.shape().sub_width(2)?;
657 let fmt = ListFormatting::new(shape, self.config)
658 .trailing_separator(self.config.trailing_comma())
659 .preserve_newline(true);
660
661 let list = write_list(&items, &fmt).ok()?;
662 result.push_str(&list);
663 result.push_str(&original_offset.to_string_with_newline(self.config));
664 result.push('}');
665 Some(result)
666 }
667
668 fn format_variant(
670 &self,
671 field: &ast::Variant,
672 one_line_width: usize,
673 pad_discrim_ident_to: usize,
674 ) -> Option<String> {
675 if contains_skip(&field.attrs) {
676 let lo = field.attrs[0].span.lo();
677 let span = mk_sp(lo, field.span.hi());
678 return Some(self.snippet(span).to_owned());
679 }
680
681 let context = self.get_context();
682 let shape = self.shape();
683 let attrs_str = if context.config.style_edition() >= StyleEdition::Edition2024 {
684 field.attrs.rewrite(&context, shape)?
685 } else {
686 field.attrs.rewrite(&context, shape.sub_width(1)?)?
688 };
689 let shape = shape.sub_width(1)?;
691
692 let lo = field
693 .attrs
694 .last()
695 .map_or(field.span.lo(), |attr| attr.span.hi());
696 let span = mk_sp(lo, field.span.lo());
697
698 let variant_body = match field.data {
699 ast::VariantData::Tuple(..) | ast::VariantData::Struct { .. } => format_struct(
700 &context,
701 &StructParts::from_variant(field, &context),
702 self.block_indent,
703 Some(one_line_width),
704 )?,
705 ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
706 };
707
708 let variant_body = if let Some(ref expr) = field.disr_expr {
709 let lhs = format!("{variant_body:pad_discrim_ident_to$} =");
710 let ex = &*expr.value;
711 rewrite_assign_rhs_with(
712 &context,
713 lhs,
714 ex,
715 shape,
716 &RhsAssignKind::Expr(&ex.kind, ex.span),
717 RhsTactics::AllowOverflow,
718 )
719 .ok()?
720 } else {
721 variant_body
722 };
723
724 combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
725 .ok()
726 }
727
728 fn visit_impl_items(&mut self, items: &[Box<ast::AssocItem>]) {
729 if self.get_context().config.reorder_impl_items() {
730 type TyOpt = Option<Box<ast::Ty>>;
731 use crate::ast::AssocItemKind::*;
732 let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
733 let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
734 let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
735 let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
736 let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
737 (Type(lty), Type(rty))
738 if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
739 {
740 false
741 }
742 (Const(..), Const(..)) => false,
743 _ => true,
744 };
745
746 let mut buffer = vec![];
748 for item in items {
749 self.visit_impl_item(item);
750 buffer.push((self.buffer.clone(), item.clone()));
751 self.buffer.clear();
752 }
753
754 buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
755 (Type(lty), Type(rty))
756 if both_type(<y.ty, &rty.ty) || both_opaque(<y.ty, &rty.ty) =>
757 {
758 lty.ident.as_str().cmp(rty.ident.as_str())
759 }
760 (Const(ca), Const(cb)) => ca.ident.as_str().cmp(cb.ident.as_str()),
761 (MacCall(..), MacCall(..)) => Ordering::Equal,
762 (Fn(..), Fn(..)) | (Delegation(..), Delegation(..)) => {
763 a.span.lo().cmp(&b.span.lo())
764 }
765 (Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
766 (_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
767 (Type(..), _) => Ordering::Less,
768 (_, Type(..)) => Ordering::Greater,
769 (Const(..), _) => Ordering::Less,
770 (_, Const(..)) => Ordering::Greater,
771 (MacCall(..), _) => Ordering::Less,
772 (_, MacCall(..)) => Ordering::Greater,
773 (Delegation(..), _) | (DelegationMac(..), _) => Ordering::Less,
774 (_, Delegation(..)) | (_, DelegationMac(..)) => Ordering::Greater,
775 });
776 let mut prev_kind = None;
777 for (buf, item) in buffer {
778 if prev_kind
781 .as_ref()
782 .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
783 {
784 self.push_str("\n");
785 }
786 let indent_str = self.block_indent.to_string_with_newline(self.config);
787 self.push_str(&indent_str);
788 self.push_str(buf.trim());
789 prev_kind = Some(item.kind.clone());
790 }
791 } else {
792 for item in items {
793 self.visit_impl_item(item);
794 }
795 }
796 }
797}
798
799pub(crate) fn format_impl(
800 context: &RewriteContext<'_>,
801 item: &ast::Item,
802 iimpl: &ast::Impl,
803 offset: Indent,
804) -> Option<String> {
805 let ast::Impl {
806 generics,
807 self_ty,
808 items,
809 ..
810 } = iimpl;
811 let mut result = String::with_capacity(128);
812 let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
813 let sep = offset.to_string_with_newline(context.config);
814 result.push_str(&ref_and_type);
815
816 let where_budget = if result.contains('\n') {
817 context.config.max_width()
818 } else {
819 context.budget(last_line_width(&result))
820 };
821
822 let mut option = WhereClauseOption::snuggled(&ref_and_type);
823 let snippet = context.snippet(item.span);
824 let open_pos = snippet.find_uncommented("{")? + 1;
825 if !contains_comment(&snippet[open_pos..])
826 && items.is_empty()
827 && generics.where_clause.predicates.len() == 1
828 && !result.contains('\n')
829 {
830 option.suppress_comma();
831 option.snuggle();
832 option.allow_single_line();
833 }
834
835 let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
836 let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
837 let where_clause_str = rewrite_where_clause(
838 context,
839 &generics.where_clause.predicates,
840 generics.where_clause.span,
841 context.config.brace_style(),
842 Shape::legacy(where_budget, offset.block_only()),
843 false,
844 "{",
845 where_span_end,
846 self_ty.span.hi(),
847 option,
848 )
849 .ok()?;
850
851 if generics.where_clause.predicates.is_empty() {
854 if let Some(hi) = where_span_end {
855 match recover_missing_comment_in_span(
856 mk_sp(self_ty.span.hi(), hi),
857 Shape::indented(offset, context.config),
858 context,
859 last_line_width(&result),
860 ) {
861 Ok(ref missing_comment) if !missing_comment.is_empty() => {
862 result.push_str(missing_comment);
863 }
864 _ => (),
865 }
866 }
867 }
868
869 if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
870 result.push_str(&where_clause_str);
871 if where_clause_str.contains('\n') {
872 if generics.where_clause.predicates.len() == 1 {
876 result.push(',');
877 }
878 }
879 if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
880 result.push_str(&format!("{sep}{{{sep}}}"));
881 } else {
882 result.push_str(" {}");
883 }
884 return Some(result);
885 }
886
887 result.push_str(&where_clause_str);
888
889 let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
890 match context.config.brace_style() {
891 _ if need_newline => result.push_str(&sep),
892 BraceStyle::AlwaysNextLine => result.push_str(&sep),
893 BraceStyle::PreferSameLine => result.push(' '),
894 BraceStyle::SameLineWhere => {
895 if !where_clause_str.is_empty() {
896 result.push_str(&sep);
897 } else {
898 result.push(' ');
899 }
900 }
901 }
902
903 result.push('{');
904 let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
906 let snippet = context.snippet(mk_sp(lo, item.span.hi()));
907 let open_pos = snippet.find_uncommented("{")? + 1;
908
909 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
910 let mut visitor = FmtVisitor::from_context(context);
911 let item_indent = offset.block_only().block_indent(context.config);
912 visitor.block_indent = item_indent;
913 visitor.last_pos = lo + BytePos(open_pos as u32);
914
915 visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
916 visitor.visit_impl_items(items);
917
918 visitor.format_missing(item.span.hi() - BytePos(1));
919
920 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
921 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
922
923 result.push_str(&inner_indent_str);
924 result.push_str(visitor.buffer.trim());
925 result.push_str(&outer_indent_str);
926 } else if need_newline || !context.config.empty_item_single_line() {
927 result.push_str(&sep);
928 }
929
930 result.push('}');
931
932 Some(result)
933}
934
935fn is_impl_single_line(
936 context: &RewriteContext<'_>,
937 items: &[Box<ast::AssocItem>],
938 result: &str,
939 where_clause_str: &str,
940 item: &ast::Item,
941) -> Option<bool> {
942 let snippet = context.snippet(item.span);
943 let open_pos = snippet.find_uncommented("{")? + 1;
944
945 Some(
946 context.config.empty_item_single_line()
947 && items.is_empty()
948 && !result.contains('\n')
949 && result.len() + where_clause_str.len() <= context.config.max_width()
950 && !contains_comment(&snippet[open_pos..]),
951 )
952}
953
954fn format_impl_ref_and_type(
955 context: &RewriteContext<'_>,
956 item: &ast::Item,
957 iimpl: &ast::Impl,
958 offset: Indent,
959) -> Option<String> {
960 let ast::Impl {
961 generics,
962 of_trait,
963 self_ty,
964 items: _,
965 } = iimpl;
966 let mut result = String::with_capacity(128);
967
968 result.push_str(&format_visibility(context, &item.vis));
969
970 if let Some(of_trait) = of_trait.as_deref() {
971 result.push_str(format_defaultness(of_trait.defaultness));
972 result.push_str(format_safety(of_trait.safety));
973 }
974
975 let shape = if context.config.style_edition() >= StyleEdition::Edition2024 {
976 Shape::indented(offset + last_line_width(&result), context.config)
977 } else {
978 generics_shape_from_config(
979 context.config,
980 Shape::indented(offset + last_line_width(&result), context.config),
981 0,
982 )?
983 };
984 let generics_str = rewrite_generics(context, "impl", generics, shape).ok()?;
985 result.push_str(&generics_str);
986
987 let trait_ref_overhead;
988 if let Some(of_trait) = of_trait.as_deref() {
989 result.push_str(format_constness_right(of_trait.constness));
990 let polarity_str = match of_trait.polarity {
991 ast::ImplPolarity::Negative(_) => "!",
992 ast::ImplPolarity::Positive => "",
993 };
994 let result_len = last_line_width(&result);
995 result.push_str(&rewrite_trait_ref(
996 context,
997 &of_trait.trait_ref,
998 offset,
999 polarity_str,
1000 result_len,
1001 )?);
1002 trait_ref_overhead = " for".len();
1003 } else {
1004 trait_ref_overhead = 0;
1005 }
1006
1007 let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
1009 match context.config.brace_style() {
1012 BraceStyle::AlwaysNextLine => 0,
1013 _ => 2,
1014 }
1015 } else {
1016 0
1017 };
1018 let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
1019 let budget = context.budget(used_space + 1);
1021 if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
1022 if !self_ty_str.contains('\n') {
1023 if of_trait.is_some() {
1024 result.push_str(" for ");
1025 } else {
1026 result.push(' ');
1027 }
1028 result.push_str(&self_ty_str);
1029 return Some(result);
1030 }
1031 }
1032
1033 result.push('\n');
1035 let new_line_offset = offset.block_indent(context.config);
1037 result.push_str(&new_line_offset.to_string(context.config));
1038 if of_trait.is_some() {
1039 result.push_str("for ");
1040 }
1041 let budget = context.budget(last_line_width(&result));
1042 let type_offset = match context.config.indent_style() {
1043 IndentStyle::Visual => new_line_offset + trait_ref_overhead,
1044 IndentStyle::Block => new_line_offset,
1045 };
1046 result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
1047 Some(result)
1048}
1049
1050fn rewrite_trait_ref(
1051 context: &RewriteContext<'_>,
1052 trait_ref: &ast::TraitRef,
1053 offset: Indent,
1054 polarity_str: &str,
1055 result_len: usize,
1056) -> Option<String> {
1057 let used_space = 1 + polarity_str.len() + result_len;
1059 let shape = Shape::indented(offset + used_space, context.config);
1060 if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
1061 if !trait_ref_str.contains('\n') {
1062 return Some(format!(" {polarity_str}{trait_ref_str}"));
1063 }
1064 }
1065 let offset = offset.block_indent(context.config);
1067 let shape = Shape::indented(offset, context.config);
1068 let trait_ref_str = trait_ref.rewrite(context, shape)?;
1069 Some(format!(
1070 "{}{}{}",
1071 offset.to_string_with_newline(context.config),
1072 polarity_str,
1073 trait_ref_str
1074 ))
1075}
1076
1077pub(crate) struct StructParts<'a> {
1078 prefix: &'a str,
1079 ident: symbol::Ident,
1080 vis: &'a ast::Visibility,
1081 def: &'a ast::VariantData,
1082 generics: Option<&'a ast::Generics>,
1083 span: Span,
1084}
1085
1086impl<'a> StructParts<'a> {
1087 fn format_header(&self, context: &RewriteContext<'_>, offset: Indent) -> String {
1088 format_header(context, self.prefix, self.ident, self.vis, offset)
1089 }
1090
1091 fn from_variant(variant: &'a ast::Variant, context: &RewriteContext<'_>) -> Self {
1092 StructParts {
1093 prefix: "",
1094 ident: variant.ident,
1095 vis: &DEFAULT_VISIBILITY,
1096 def: &variant.data,
1097 generics: None,
1098 span: enum_variant_span(variant, context),
1099 }
1100 }
1101
1102 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
1103 let (prefix, def, ident, generics) = match item.kind {
1104 ast::ItemKind::Struct(ident, ref generics, ref def) => {
1105 ("struct ", def, ident, generics)
1106 }
1107 ast::ItemKind::Union(ident, ref generics, ref def) => ("union ", def, ident, generics),
1108 _ => unreachable!(),
1109 };
1110 StructParts {
1111 prefix,
1112 ident,
1113 vis: &item.vis,
1114 def,
1115 generics: Some(generics),
1116 span: item.span,
1117 }
1118 }
1119}
1120
1121fn enum_variant_span(variant: &ast::Variant, context: &RewriteContext<'_>) -> Span {
1122 use ast::VariantData::*;
1123 if let Some(ref anon_const) = variant.disr_expr {
1124 let span_before_consts = variant.span.until(anon_const.value.span);
1125 let hi = match &variant.data {
1126 Struct { .. } => context
1127 .snippet_provider
1128 .span_after_last(span_before_consts, "}"),
1129 Tuple(..) => context
1130 .snippet_provider
1131 .span_after_last(span_before_consts, ")"),
1132 Unit(..) => variant.ident.span.hi(),
1133 };
1134 mk_sp(span_before_consts.lo(), hi)
1135 } else {
1136 variant.span
1137 }
1138}
1139
1140fn format_struct(
1141 context: &RewriteContext<'_>,
1142 struct_parts: &StructParts<'_>,
1143 offset: Indent,
1144 one_line_width: Option<usize>,
1145) -> Option<String> {
1146 match struct_parts.def {
1147 ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
1148 ast::VariantData::Tuple(fields, _) => {
1149 format_tuple_struct(context, struct_parts, fields, offset)
1150 }
1151 ast::VariantData::Struct { fields, .. } => {
1152 format_struct_struct(context, struct_parts, fields, offset, one_line_width)
1153 }
1154 }
1155}
1156
1157pub(crate) fn format_trait(
1158 context: &RewriteContext<'_>,
1159 item: &ast::Item,
1160 offset: Indent,
1161) -> Option<String> {
1162 let ast::ItemKind::Trait(trait_kind) = &item.kind else {
1163 unreachable!();
1164 };
1165 let ast::Trait {
1166 constness,
1167 is_auto,
1168 safety,
1169 ident,
1170 ref generics,
1171 ref bounds,
1172 ref items,
1173 } = **trait_kind;
1174
1175 let mut result = String::with_capacity(128);
1176 let header = format!(
1177 "{}{}{}{}trait ",
1178 format_constness(constness),
1179 format_visibility(context, &item.vis),
1180 format_safety(safety),
1181 format_auto(is_auto),
1182 );
1183 result.push_str(&header);
1184
1185 let body_lo = context.snippet_provider.span_after(item.span, "{");
1186
1187 let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
1188 let generics_str =
1189 rewrite_generics(context, rewrite_ident(context, ident), generics, shape).ok()?;
1190 result.push_str(&generics_str);
1191
1192 if !bounds.is_empty() {
1194 let source_ident = context.snippet(ident.span);
1196 let ident_hi = context.snippet_provider.span_after(item.span, source_ident);
1197 let bound_hi = bounds.last().unwrap().span().hi();
1198 let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
1199 if contains_comment(snippet) {
1200 return None;
1201 }
1202
1203 result = rewrite_assign_rhs_with(
1204 context,
1205 result + ":",
1206 bounds,
1207 shape,
1208 &RhsAssignKind::Bounds,
1209 RhsTactics::ForceNextLineWithoutIndent,
1210 )
1211 .ok()?;
1212 }
1213
1214 if !generics.where_clause.predicates.is_empty() {
1216 let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
1217
1218 let where_budget = context.budget(last_line_width(&result));
1219 let pos_before_where = if bounds.is_empty() {
1220 generics.where_clause.span.lo()
1221 } else {
1222 bounds[bounds.len() - 1].span().hi()
1223 };
1224 let option = WhereClauseOption::snuggled(&generics_str);
1225 let where_clause_str = rewrite_where_clause(
1226 context,
1227 &generics.where_clause.predicates,
1228 generics.where_clause.span,
1229 context.config.brace_style(),
1230 Shape::legacy(where_budget, offset.block_only()),
1231 where_on_new_line,
1232 "{",
1233 None,
1234 pos_before_where,
1235 option,
1236 )
1237 .ok()?;
1238 if !where_clause_str.contains('\n')
1241 && last_line_width(&result) + where_clause_str.len() + offset.width()
1242 > context.config.comment_width()
1243 {
1244 let width = offset.block_indent + context.config.tab_spaces() - 1;
1245 let where_indent = Indent::new(0, width);
1246 result.push_str(&where_indent.to_string_with_newline(context.config));
1247 }
1248 result.push_str(&where_clause_str);
1249 } else {
1250 let item_snippet = context.snippet(item.span);
1251 if let Some(lo) = item_snippet.find('/') {
1252 let comment_hi = if generics.params.len() > 0 {
1254 generics.span.lo() - BytePos(1)
1255 } else {
1256 body_lo - BytePos(1)
1257 };
1258 let comment_lo = item.span.lo() + BytePos(lo as u32);
1259 if comment_lo < comment_hi {
1260 match recover_missing_comment_in_span(
1261 mk_sp(comment_lo, comment_hi),
1262 Shape::indented(offset, context.config),
1263 context,
1264 last_line_width(&result),
1265 ) {
1266 Ok(ref missing_comment) if !missing_comment.is_empty() => {
1267 result.push_str(missing_comment);
1268 }
1269 _ => (),
1270 }
1271 }
1272 }
1273 }
1274
1275 let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
1276 let snippet = context.snippet(block_span);
1277 let open_pos = snippet.find_uncommented("{")? + 1;
1278
1279 match context.config.brace_style() {
1280 _ if last_line_contains_single_line_comment(&result)
1281 || last_line_width(&result) + 2 > context.budget(offset.width()) =>
1282 {
1283 result.push_str(&offset.to_string_with_newline(context.config));
1284 }
1285 _ if context.config.empty_item_single_line()
1286 && items.is_empty()
1287 && !result.contains('\n')
1288 && !contains_comment(&snippet[open_pos..]) =>
1289 {
1290 result.push_str(" {}");
1291 return Some(result);
1292 }
1293 BraceStyle::AlwaysNextLine => {
1294 result.push_str(&offset.to_string_with_newline(context.config));
1295 }
1296 BraceStyle::PreferSameLine => result.push(' '),
1297 BraceStyle::SameLineWhere => {
1298 if result.contains('\n')
1299 || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
1300 {
1301 result.push_str(&offset.to_string_with_newline(context.config));
1302 } else {
1303 result.push(' ');
1304 }
1305 }
1306 }
1307 result.push('{');
1308
1309 let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
1310
1311 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
1312 let mut visitor = FmtVisitor::from_context(context);
1313 visitor.block_indent = offset.block_only().block_indent(context.config);
1314 visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
1315
1316 for item in items {
1317 visitor.visit_trait_item(item);
1318 }
1319
1320 visitor.format_missing(item.span.hi() - BytePos(1));
1321
1322 let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
1323
1324 result.push_str(&inner_indent_str);
1325 result.push_str(visitor.buffer.trim());
1326 result.push_str(&outer_indent_str);
1327 } else if result.contains('\n') {
1328 result.push_str(&outer_indent_str);
1329 }
1330
1331 result.push('}');
1332 Some(result)
1333}
1334
1335pub(crate) struct TraitAliasBounds<'a> {
1336 generic_bounds: &'a ast::GenericBounds,
1337 generics: &'a ast::Generics,
1338}
1339
1340impl<'a> Rewrite for TraitAliasBounds<'a> {
1341 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1342 self.rewrite_result(context, shape).ok()
1343 }
1344
1345 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1346 let generic_bounds_str = self.generic_bounds.rewrite_result(context, shape)?;
1347
1348 let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
1349 option.allow_single_line();
1350
1351 let where_str = rewrite_where_clause(
1352 context,
1353 &self.generics.where_clause.predicates,
1354 self.generics.where_clause.span,
1355 context.config.brace_style(),
1356 shape,
1357 false,
1358 ";",
1359 None,
1360 self.generics.where_clause.span.lo(),
1361 option,
1362 )?;
1363
1364 let fits_single_line = !generic_bounds_str.contains('\n')
1365 && !where_str.contains('\n')
1366 && generic_bounds_str.len() + where_str.len() < shape.width;
1367 let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
1368 Cow::from("")
1369 } else if fits_single_line {
1370 Cow::from(" ")
1371 } else {
1372 shape.indent.to_string_with_newline(context.config)
1373 };
1374
1375 Ok(format!("{generic_bounds_str}{space}{where_str}"))
1376 }
1377}
1378
1379pub(crate) fn format_trait_alias(
1380 context: &RewriteContext<'_>,
1381 ident: symbol::Ident,
1382 vis: &ast::Visibility,
1383 generics: &ast::Generics,
1384 generic_bounds: &ast::GenericBounds,
1385 shape: Shape,
1386) -> Option<String> {
1387 let alias = rewrite_ident(context, ident);
1388 let g_shape = shape.offset_left(6)?.sub_width(2)?;
1390 let generics_str = rewrite_generics(context, alias, generics, g_shape).ok()?;
1391 let vis_str = format_visibility(context, vis);
1392 let lhs = format!("{vis_str}trait {generics_str} =");
1393 let trait_alias_bounds = TraitAliasBounds {
1395 generic_bounds,
1396 generics,
1397 };
1398 rewrite_assign_rhs(
1399 context,
1400 lhs,
1401 &trait_alias_bounds,
1402 &RhsAssignKind::Bounds,
1403 shape.sub_width(1)?,
1404 )
1405 .map(|s| s + ";")
1406 .ok()
1407}
1408
1409fn format_unit_struct(
1410 context: &RewriteContext<'_>,
1411 p: &StructParts<'_>,
1412 offset: Indent,
1413) -> Option<String> {
1414 let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
1415 let generics_str = if let Some(generics) = p.generics {
1416 let hi = context.snippet_provider.span_before_last(p.span, ";");
1417 format_generics(
1418 context,
1419 generics,
1420 context.config.brace_style(),
1421 BracePos::None,
1422 offset,
1423 mk_sp(p.ident.span.hi(), hi),
1425 last_line_width(&header_str),
1426 )?
1427 } else {
1428 String::new()
1429 };
1430 Some(format!("{header_str}{generics_str};"))
1431}
1432
1433pub(crate) fn format_struct_struct(
1434 context: &RewriteContext<'_>,
1435 struct_parts: &StructParts<'_>,
1436 fields: &[ast::FieldDef],
1437 offset: Indent,
1438 one_line_width: Option<usize>,
1439) -> Option<String> {
1440 let mut result = String::with_capacity(1024);
1441 let span = struct_parts.span;
1442
1443 let header_str = struct_parts.format_header(context, offset);
1444 result.push_str(&header_str);
1445
1446 let header_hi = struct_parts.ident.span.hi();
1447 let body_lo = if let Some(generics) = struct_parts.generics {
1448 let span = span.with_lo(generics.where_clause.span.hi());
1450 context.snippet_provider.span_after(span, "{")
1451 } else {
1452 context.snippet_provider.span_after(span, "{")
1453 };
1454
1455 let generics_str = match struct_parts.generics {
1456 Some(g) => format_generics(
1457 context,
1458 g,
1459 context.config.brace_style(),
1460 if fields.is_empty() {
1461 BracePos::ForceSameLine
1462 } else {
1463 BracePos::Auto
1464 },
1465 offset,
1466 mk_sp(header_hi, body_lo),
1468 last_line_width(&result),
1469 )?,
1470 None => {
1471 let overhead = if fields.is_empty() { 3 } else { 2 };
1473 if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
1474 || context.config.max_width() < overhead + result.len()
1475 {
1476 format!("\n{}{{", offset.block_only().to_string(context.config))
1477 } else {
1478 " {".to_owned()
1479 }
1480 }
1481 };
1482 let overhead = if fields.is_empty() { 1 } else { 0 };
1484 let total_width = result.len() + generics_str.len() + overhead;
1485 if !generics_str.is_empty()
1486 && !generics_str.contains('\n')
1487 && total_width > context.config.max_width()
1488 {
1489 result.push('\n');
1490 result.push_str(&offset.to_string(context.config));
1491 result.push_str(generics_str.trim_start());
1492 } else {
1493 result.push_str(&generics_str);
1494 }
1495
1496 if fields.is_empty() {
1497 let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
1498 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
1499 return Some(result);
1500 }
1501
1502 let one_line_budget = context.budget(result.len() + 3 + offset.width());
1504 let one_line_budget =
1505 one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1506
1507 let items_str = rewrite_with_alignment(
1508 fields,
1509 context,
1510 Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
1511 mk_sp(body_lo, span.hi()),
1512 one_line_budget,
1513 )?;
1514
1515 if !items_str.contains('\n')
1516 && !result.contains('\n')
1517 && items_str.len() <= one_line_budget
1518 && !last_line_contains_single_line_comment(&items_str)
1519 {
1520 Some(format!("{result} {items_str} }}"))
1521 } else {
1522 Some(format!(
1523 "{}\n{}{}\n{}}}",
1524 result,
1525 offset
1526 .block_indent(context.config)
1527 .to_string(context.config),
1528 items_str,
1529 offset.to_string(context.config)
1530 ))
1531 }
1532}
1533
1534fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
1535 match vis.kind {
1536 ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
1537 _ => default_span.lo(),
1538 }
1539}
1540
1541fn format_empty_struct_or_tuple(
1544 context: &RewriteContext<'_>,
1545 span: Span,
1546 offset: Indent,
1547 result: &mut String,
1548 opener: &str,
1549 closer: &str,
1550) {
1551 let used_width = last_line_used_width(result, offset.width()) + 3;
1553 if used_width > context.config.max_width() {
1554 result.push_str(&offset.to_string_with_newline(context.config))
1555 }
1556 result.push_str(opener);
1557
1558 let shape = Shape::indented(offset.block_indent(context.config), context.config);
1560 match rewrite_missing_comment(span, shape, context) {
1561 Ok(ref s) if s.is_empty() => (),
1562 Ok(ref s) => {
1563 let is_multi_line = !is_single_line(s);
1564 if is_multi_line || first_line_contains_single_line_comment(s) {
1565 let nested_indent_str = offset
1566 .block_indent(context.config)
1567 .to_string_with_newline(context.config);
1568 result.push_str(&nested_indent_str);
1569 }
1570 result.push_str(s);
1571 if is_multi_line || last_line_contains_single_line_comment(s) {
1572 result.push_str(&offset.to_string_with_newline(context.config));
1573 }
1574 }
1575 Err(_) => result.push_str(context.snippet(span)),
1576 }
1577 result.push_str(closer);
1578}
1579
1580fn format_tuple_struct(
1581 context: &RewriteContext<'_>,
1582 struct_parts: &StructParts<'_>,
1583 fields: &[ast::FieldDef],
1584 offset: Indent,
1585) -> Option<String> {
1586 let mut result = String::with_capacity(1024);
1587 let span = struct_parts.span;
1588
1589 let header_str = struct_parts.format_header(context, offset);
1590 result.push_str(&header_str);
1591
1592 let body_lo = if fields.is_empty() {
1593 let lo = get_bytepos_after_visibility(struct_parts.vis, span);
1594 context
1595 .snippet_provider
1596 .span_after(mk_sp(lo, span.hi()), "(")
1597 } else {
1598 fields[0].span.lo()
1599 };
1600 let body_hi = if fields.is_empty() {
1601 context
1602 .snippet_provider
1603 .span_after(mk_sp(body_lo, span.hi()), ")")
1604 } else {
1605 let last_arg_span = fields[fields.len() - 1].span;
1607 context
1608 .snippet_provider
1609 .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
1610 .unwrap_or_else(|| last_arg_span.hi())
1611 };
1612
1613 let where_clause_str = match struct_parts.generics {
1614 Some(generics) => {
1615 let budget = context.budget(last_line_width(&header_str));
1616 let shape = Shape::legacy(budget, offset);
1617 let generics_str = rewrite_generics(context, "", generics, shape).ok()?;
1618 result.push_str(&generics_str);
1619
1620 let where_budget = context.budget(last_line_width(&result));
1621 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1622 rewrite_where_clause(
1623 context,
1624 &generics.where_clause.predicates,
1625 generics.where_clause.span,
1626 context.config.brace_style(),
1627 Shape::legacy(where_budget, offset.block_only()),
1628 false,
1629 ";",
1630 None,
1631 body_hi,
1632 option,
1633 )
1634 .ok()?
1635 }
1636 None => "".to_owned(),
1637 };
1638
1639 if fields.is_empty() {
1640 let body_hi = context
1641 .snippet_provider
1642 .span_before(mk_sp(body_lo, span.hi()), ")");
1643 let inner_span = mk_sp(body_lo, body_hi);
1644 format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
1645 } else {
1646 let shape = Shape::indented(offset, context.config).sub_width(1)?;
1647 let lo = if let Some(generics) = struct_parts.generics {
1648 generics.span.hi()
1649 } else {
1650 struct_parts.ident.span.hi()
1651 };
1652 result = overflow::rewrite_with_parens(
1653 context,
1654 &result,
1655 fields.iter(),
1656 shape,
1657 mk_sp(lo, span.hi()),
1658 context.config.fn_call_width(),
1659 None,
1660 )
1661 .ok()?;
1662 }
1663
1664 if !where_clause_str.is_empty()
1665 && !where_clause_str.contains('\n')
1666 && (result.contains('\n')
1667 || offset.block_indent + result.len() + where_clause_str.len() + 1
1668 > context.config.max_width())
1669 {
1670 result.push('\n');
1673 result.push_str(
1674 &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
1675 );
1676 }
1677 result.push_str(&where_clause_str);
1678
1679 Some(result)
1680}
1681
1682#[derive(Clone, Copy)]
1683pub(crate) enum ItemVisitorKind {
1684 Item,
1685 AssocTraitItem,
1686 AssocImplItem,
1687 ForeignItem,
1688}
1689
1690struct TyAliasRewriteInfo<'c, 'g>(
1691 &'c RewriteContext<'c>,
1692 Indent,
1693 &'g ast::Generics,
1694 ast::TyAliasWhereClauses,
1695 symbol::Ident,
1696 Span,
1697);
1698
1699pub(crate) fn rewrite_type_alias<'a>(
1700 ty_alias_kind: &ast::TyAlias,
1701 vis: &ast::Visibility,
1702 context: &RewriteContext<'a>,
1703 indent: Indent,
1704 visitor_kind: ItemVisitorKind,
1705 span: Span,
1706) -> RewriteResult {
1707 use ItemVisitorKind::*;
1708
1709 let ast::TyAlias {
1710 defaultness,
1711 ident,
1712 ref generics,
1713 ref bounds,
1714 ref ty,
1715 where_clauses,
1716 } = *ty_alias_kind;
1717 let ty_opt = ty.as_ref();
1718 let rhs_hi = ty
1719 .as_ref()
1720 .map_or(where_clauses.before.span.hi(), |ty| ty.span.hi());
1721 let rw_info = &TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span);
1722 let op_ty = opaque_ty(ty);
1723 match (visitor_kind, &op_ty) {
1728 (Item | AssocTraitItem | ForeignItem, Some(op_bounds)) => {
1729 let op = OpaqueType { bounds: op_bounds };
1730 rewrite_ty(rw_info, Some(bounds), Some(&op), rhs_hi, vis)
1731 }
1732 (Item | AssocTraitItem | ForeignItem, None) => {
1733 rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis)
1734 }
1735 (AssocImplItem, _) => {
1736 let result = if let Some(op_bounds) = op_ty {
1737 let op = OpaqueType { bounds: op_bounds };
1738 rewrite_ty(
1739 rw_info,
1740 Some(bounds),
1741 Some(&op),
1742 rhs_hi,
1743 &DEFAULT_VISIBILITY,
1744 )
1745 } else {
1746 rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis)
1747 }?;
1748 match defaultness {
1749 ast::Defaultness::Default(..) => Ok(format!("default {result}")),
1750 _ => Ok(result),
1751 }
1752 }
1753 }
1754}
1755
1756fn rewrite_ty<R: Rewrite>(
1757 rw_info: &TyAliasRewriteInfo<'_, '_>,
1758 generic_bounds_opt: Option<&ast::GenericBounds>,
1759 rhs: Option<&R>,
1760 rhs_hi: BytePos,
1762 vis: &ast::Visibility,
1763) -> RewriteResult {
1764 let mut result = String::with_capacity(128);
1765 let TyAliasRewriteInfo(context, indent, generics, where_clauses, ident, span) = *rw_info;
1766 let (before_where_predicates, after_where_predicates) = generics
1767 .where_clause
1768 .predicates
1769 .split_at(where_clauses.split);
1770 result.push_str(&format!("{}type ", format_visibility(context, vis)));
1771 let ident_str = rewrite_ident(context, ident);
1772
1773 if generics.params.is_empty() {
1774 result.push_str(ident_str)
1775 } else {
1776 let g_shape = Shape::indented(indent, context.config);
1778 let g_shape = g_shape
1779 .offset_left(result.len())
1780 .and_then(|s| s.sub_width(2))
1781 .max_width_error(g_shape.width, span)?;
1782 let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
1783 result.push_str(&generics_str);
1784 }
1785
1786 if let Some(bounds) = generic_bounds_opt {
1787 if !bounds.is_empty() {
1788 let shape = Shape::indented(indent, context.config);
1790 let shape = shape
1791 .offset_left(result.len() + 2)
1792 .max_width_error(shape.width, span)?;
1793 let type_bounds = bounds
1794 .rewrite_result(context, shape)
1795 .map(|s| format!(": {}", s))?;
1796 result.push_str(&type_bounds);
1797 }
1798 }
1799
1800 let where_budget = context.budget(last_line_width(&result));
1801 let mut option = WhereClauseOption::snuggled(&result);
1802 if rhs.is_none() {
1803 option.suppress_comma();
1804 }
1805 let before_where_clause_str = rewrite_where_clause(
1806 context,
1807 before_where_predicates,
1808 where_clauses.before.span,
1809 context.config.brace_style(),
1810 Shape::legacy(where_budget, indent),
1811 false,
1812 "=",
1813 None,
1814 generics.span.hi(),
1815 option,
1816 )?;
1817 result.push_str(&before_where_clause_str);
1818
1819 let mut result = if let Some(ty) = rhs {
1820 if !before_where_predicates.is_empty() {
1824 result.push_str(&indent.to_string_with_newline(context.config));
1825 } else if !after_where_predicates.is_empty() {
1826 result.push_str(
1827 &indent
1828 .block_indent(context.config)
1829 .to_string_with_newline(context.config),
1830 );
1831 } else {
1832 result.push(' ');
1833 }
1834
1835 let comment_span = context
1836 .snippet_provider
1837 .opt_span_before(span, "=")
1838 .map(|op_lo| mk_sp(where_clauses.before.span.hi(), op_lo));
1839
1840 let lhs = match comment_span {
1841 Some(comment_span)
1842 if contains_comment(
1843 context
1844 .snippet_provider
1845 .span_to_snippet(comment_span)
1846 .unknown_error()?,
1847 ) =>
1848 {
1849 let comment_shape = if !before_where_predicates.is_empty() {
1850 Shape::indented(indent, context.config)
1851 } else {
1852 let shape = Shape::indented(indent, context.config);
1853 shape
1854 .block_left(context.config.tab_spaces())
1855 .max_width_error(shape.width, span)?
1856 };
1857
1858 combine_strs_with_missing_comments(
1859 context,
1860 result.trim_end(),
1861 "=",
1862 comment_span,
1863 comment_shape,
1864 true,
1865 )?
1866 }
1867 _ => format!("{result}="),
1868 };
1869
1870 let shape = Shape::indented(indent, context.config);
1872 let shape = if after_where_predicates.is_empty() {
1873 Shape::indented(indent, context.config)
1874 .sub_width(1)
1875 .max_width_error(shape.width, span)?
1876 } else {
1877 shape
1878 };
1879 rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape)?
1880 } else {
1881 result
1882 };
1883
1884 if !after_where_predicates.is_empty() {
1885 let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
1886 let after_where_clause_str = rewrite_where_clause(
1887 context,
1888 after_where_predicates,
1889 where_clauses.after.span,
1890 context.config.brace_style(),
1891 Shape::indented(indent, context.config),
1892 false,
1893 ";",
1894 None,
1895 rhs_hi,
1896 option,
1897 )?;
1898 result.push_str(&after_where_clause_str);
1899 }
1900
1901 result += ";";
1902 Ok(result)
1903}
1904
1905fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1906 (
1907 if config.space_before_colon() { " " } else { "" },
1908 if config.space_after_colon() { " " } else { "" },
1909 )
1910}
1911
1912pub(crate) fn rewrite_struct_field_prefix(
1913 context: &RewriteContext<'_>,
1914 field: &ast::FieldDef,
1915) -> RewriteResult {
1916 let vis = format_visibility(context, &field.vis);
1917 let safety = format_safety(field.safety);
1918 let type_annotation_spacing = type_annotation_spacing(context.config);
1919 Ok(match field.ident {
1920 Some(name) => format!(
1921 "{vis}{safety}{}{}:",
1922 rewrite_ident(context, name),
1923 type_annotation_spacing.0
1924 ),
1925 None => format!("{vis}{safety}"),
1926 })
1927}
1928
1929impl Rewrite for ast::FieldDef {
1930 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
1931 self.rewrite_result(context, shape).ok()
1932 }
1933
1934 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
1935 rewrite_struct_field(context, self, shape, 0)
1936 }
1937}
1938
1939pub(crate) fn rewrite_struct_field(
1940 context: &RewriteContext<'_>,
1941 field: &ast::FieldDef,
1942 shape: Shape,
1943 lhs_max_width: usize,
1944) -> RewriteResult {
1945 if field.default.is_some() {
1947 return Err(RewriteError::Unknown);
1948 }
1949
1950 if contains_skip(&field.attrs) {
1951 return Ok(context.snippet(field.span()).to_owned());
1952 }
1953
1954 let type_annotation_spacing = type_annotation_spacing(context.config);
1955 let prefix = rewrite_struct_field_prefix(context, field)?;
1956
1957 let attrs_str = field.attrs.rewrite_result(context, shape)?;
1958 let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
1959 let missing_span = if field.attrs.is_empty() {
1960 mk_sp(field.span.lo(), field.span.lo())
1961 } else {
1962 mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
1963 };
1964 let mut spacing = String::from(if field.ident.is_some() {
1965 type_annotation_spacing.1
1966 } else {
1967 ""
1968 });
1969 let attr_prefix = combine_strs_with_missing_comments(
1971 context,
1972 &attrs_str,
1973 &prefix,
1974 missing_span,
1975 shape,
1976 attrs_extendable,
1977 )?;
1978 let overhead = trimmed_last_line_width(&attr_prefix);
1979 let lhs_offset = lhs_max_width.saturating_sub(overhead);
1980 for _ in 0..lhs_offset {
1981 spacing.push(' ');
1982 }
1983 if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1985 spacing.push(' ');
1986 }
1987
1988 let orig_ty = shape
1989 .offset_left(overhead + spacing.len())
1990 .and_then(|ty_shape| field.ty.rewrite_result(context, ty_shape).ok());
1991
1992 if let Some(ref ty) = orig_ty {
1993 if !ty.contains('\n') && !contains_comment(context.snippet(missing_span)) {
1994 return Ok(attr_prefix + &spacing + ty);
1995 }
1996 }
1997
1998 let is_prefix_empty = prefix.is_empty();
1999 let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
2001 let field_str = if is_prefix_empty {
2003 field_str.trim_start()
2004 } else {
2005 &field_str
2006 };
2007 combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
2008}
2009
2010pub(crate) struct StaticParts<'a> {
2011 prefix: &'a str,
2012 safety: ast::Safety,
2013 vis: &'a ast::Visibility,
2014 ident: symbol::Ident,
2015 generics: Option<&'a ast::Generics>,
2016 ty: &'a ast::Ty,
2017 mutability: ast::Mutability,
2018 expr_opt: Option<&'a Box<ast::Expr>>,
2019 defaultness: Option<ast::Defaultness>,
2020 span: Span,
2021}
2022
2023impl<'a> StaticParts<'a> {
2024 pub(crate) fn from_item(item: &'a ast::Item) -> Self {
2025 let (defaultness, prefix, safety, ident, ty, mutability, expr, generics) = match &item.kind
2026 {
2027 ast::ItemKind::Static(s) => (
2028 None,
2029 "static",
2030 s.safety,
2031 s.ident,
2032 &s.ty,
2033 s.mutability,
2034 &s.expr,
2035 None,
2036 ),
2037 ast::ItemKind::Const(c) => (
2038 Some(c.defaultness),
2039 "const",
2040 ast::Safety::Default,
2041 c.ident,
2042 &c.ty,
2043 ast::Mutability::Not,
2044 &c.expr,
2045 Some(&c.generics),
2046 ),
2047 _ => unreachable!(),
2048 };
2049 StaticParts {
2050 prefix,
2051 safety,
2052 vis: &item.vis,
2053 ident,
2054 generics,
2055 ty,
2056 mutability,
2057 expr_opt: expr.as_ref(),
2058 defaultness,
2059 span: item.span,
2060 }
2061 }
2062
2063 pub(crate) fn from_trait_item(ti: &'a ast::AssocItem, ident: Ident) -> Self {
2064 let (defaultness, ty, expr_opt, generics) = match &ti.kind {
2065 ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)),
2066 _ => unreachable!(),
2067 };
2068 StaticParts {
2069 prefix: "const",
2070 safety: ast::Safety::Default,
2071 vis: &ti.vis,
2072 ident,
2073 generics,
2074 ty,
2075 mutability: ast::Mutability::Not,
2076 expr_opt: expr_opt.as_ref(),
2077 defaultness: Some(defaultness),
2078 span: ti.span,
2079 }
2080 }
2081
2082 pub(crate) fn from_impl_item(ii: &'a ast::AssocItem, ident: Ident) -> Self {
2083 let (defaultness, ty, expr, generics) = match &ii.kind {
2084 ast::AssocItemKind::Const(c) => (c.defaultness, &c.ty, &c.expr, Some(&c.generics)),
2085 _ => unreachable!(),
2086 };
2087 StaticParts {
2088 prefix: "const",
2089 safety: ast::Safety::Default,
2090 vis: &ii.vis,
2091 ident,
2092 generics,
2093 ty,
2094 mutability: ast::Mutability::Not,
2095 expr_opt: expr.as_ref(),
2096 defaultness: Some(defaultness),
2097 span: ii.span,
2098 }
2099 }
2100}
2101
2102fn rewrite_static(
2103 context: &RewriteContext<'_>,
2104 static_parts: &StaticParts<'_>,
2105 offset: Indent,
2106) -> Option<String> {
2107 if static_parts
2109 .generics
2110 .is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty())
2111 {
2112 return None;
2113 }
2114
2115 let colon = colon_spaces(context.config);
2116 let mut prefix = format!(
2117 "{}{}{}{} {}{}{}",
2118 format_visibility(context, static_parts.vis),
2119 static_parts.defaultness.map_or("", format_defaultness),
2120 format_safety(static_parts.safety),
2121 static_parts.prefix,
2122 format_mutability(static_parts.mutability),
2123 rewrite_ident(context, static_parts.ident),
2124 colon,
2125 );
2126 let ty_shape =
2128 Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
2129 let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
2130 Some(ty_str) => ty_str,
2131 None => {
2132 if prefix.ends_with(' ') {
2133 prefix.pop();
2134 }
2135 let nested_indent = offset.block_indent(context.config);
2136 let nested_shape = Shape::indented(nested_indent, context.config);
2137 let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
2138 format!(
2139 "{}{}",
2140 nested_indent.to_string_with_newline(context.config),
2141 ty_str
2142 )
2143 }
2144 };
2145
2146 if let Some(expr) = static_parts.expr_opt {
2147 let comments_lo = context.snippet_provider.span_after(static_parts.span, "=");
2148 let expr_lo = expr.span.lo();
2149 let comments_span = mk_sp(comments_lo, expr_lo);
2150
2151 let lhs = format!("{prefix}{ty_str} =");
2152
2153 let remaining_width = context.budget(offset.block_indent + 1);
2155 rewrite_assign_rhs_with_comments(
2156 context,
2157 &lhs,
2158 &**expr,
2159 Shape::legacy(remaining_width, offset.block_only()),
2160 &RhsAssignKind::Expr(&expr.kind, expr.span),
2161 RhsTactics::Default,
2162 comments_span,
2163 true,
2164 )
2165 .ok()
2166 .map(|res| recover_comment_removed(res, static_parts.span, context))
2167 .map(|s| if s.ends_with(';') { s } else { s + ";" })
2168 } else {
2169 Some(format!("{prefix}{ty_str};"))
2170 }
2171}
2172
2173struct OpaqueType<'a> {
2179 bounds: &'a ast::GenericBounds,
2180}
2181
2182impl<'a> Rewrite for OpaqueType<'a> {
2183 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2184 let shape = shape.offset_left(5)?; self.bounds
2186 .rewrite(context, shape)
2187 .map(|s| format!("impl {}", s))
2188 }
2189}
2190
2191impl Rewrite for ast::FnRetTy {
2192 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2193 self.rewrite_result(context, shape).ok()
2194 }
2195
2196 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
2197 match *self {
2198 ast::FnRetTy::Default(_) => Ok(String::new()),
2199 ast::FnRetTy::Ty(ref ty) => {
2200 let arrow_width = "-> ".len();
2201 if context.config.style_edition() <= StyleEdition::Edition2021
2202 || context.config.indent_style() == IndentStyle::Visual
2203 {
2204 let inner_width = shape
2205 .width
2206 .checked_sub(arrow_width)
2207 .max_width_error(shape.width, self.span())?;
2208 return ty
2209 .rewrite_result(
2210 context,
2211 Shape::legacy(inner_width, shape.indent + arrow_width),
2212 )
2213 .map(|r| format!("-> {}", r));
2214 }
2215
2216 let shape = shape
2217 .offset_left(arrow_width)
2218 .max_width_error(shape.width, self.span())?;
2219
2220 ty.rewrite_result(context, shape)
2221 .map(|s| format!("-> {}", s))
2222 }
2223 }
2224 }
2225}
2226
2227fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
2228 match ty.kind {
2229 ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
2230 _ => false,
2231 }
2232}
2233
2234fn get_missing_param_comments(
2241 context: &RewriteContext<'_>,
2242 pat_span: Span,
2243 ty_span: Span,
2244 shape: Shape,
2245) -> (String, String) {
2246 let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
2247
2248 let span_before_colon = {
2249 let missing_comment_span_hi = context
2250 .snippet_provider
2251 .span_before(missing_comment_span, ":");
2252 mk_sp(pat_span.hi(), missing_comment_span_hi)
2253 };
2254 let span_after_colon = {
2255 let missing_comment_span_lo = context
2256 .snippet_provider
2257 .span_after(missing_comment_span, ":");
2258 mk_sp(missing_comment_span_lo, ty_span.lo())
2259 };
2260
2261 let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
2262 .ok()
2263 .filter(|comment| !comment.is_empty())
2264 .map_or(String::new(), |comment| format!(" {}", comment));
2265 let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
2266 .ok()
2267 .filter(|comment| !comment.is_empty())
2268 .map_or(String::new(), |comment| format!("{} ", comment));
2269 (comment_before_colon, comment_after_colon)
2270}
2271
2272impl Rewrite for ast::Param {
2273 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
2274 self.rewrite_result(context, shape).ok()
2275 }
2276
2277 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
2278 let param_attrs_result = self
2279 .attrs
2280 .rewrite_result(context, Shape::legacy(shape.width, shape.indent))?;
2281 let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
2284 let num_attrs = self.attrs.len();
2285 (
2286 mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
2287 param_attrs_result.contains('\n'),
2288 self.attrs.iter().any(|a| a.is_doc_comment()),
2289 )
2290 } else {
2291 (mk_sp(self.span.lo(), self.span.lo()), false, false)
2292 };
2293
2294 if let Some(ref explicit_self) = self.to_self() {
2295 rewrite_explicit_self(
2296 context,
2297 explicit_self,
2298 ¶m_attrs_result,
2299 span,
2300 shape,
2301 has_multiple_attr_lines,
2302 )
2303 } else if is_named_param(self) {
2304 let param_name = &self
2305 .pat
2306 .rewrite_result(context, Shape::legacy(shape.width, shape.indent))?;
2307 let mut result = combine_strs_with_missing_comments(
2308 context,
2309 ¶m_attrs_result,
2310 param_name,
2311 span,
2312 shape,
2313 !has_multiple_attr_lines && !has_doc_comments,
2314 )?;
2315
2316 if !is_empty_infer(&*self.ty, self.pat.span) {
2317 let (before_comment, after_comment) =
2318 get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
2319 result.push_str(&before_comment);
2320 result.push_str(colon_spaces(context.config));
2321 result.push_str(&after_comment);
2322 let overhead = last_line_width(&result);
2323 let max_width = shape
2324 .width
2325 .checked_sub(overhead)
2326 .max_width_error(shape.width, self.span())?;
2327 if let Ok(ty_str) = self
2328 .ty
2329 .rewrite_result(context, Shape::legacy(max_width, shape.indent))
2330 {
2331 result.push_str(&ty_str);
2332 } else {
2333 let prev_str = if param_attrs_result.is_empty() {
2334 param_attrs_result
2335 } else {
2336 param_attrs_result + &shape.to_string_with_newline(context.config)
2337 };
2338
2339 result = combine_strs_with_missing_comments(
2340 context,
2341 &prev_str,
2342 param_name,
2343 span,
2344 shape,
2345 !has_multiple_attr_lines,
2346 )?;
2347 result.push_str(&before_comment);
2348 result.push_str(colon_spaces(context.config));
2349 result.push_str(&after_comment);
2350 let overhead = last_line_width(&result);
2351 let max_width = shape
2352 .width
2353 .checked_sub(overhead)
2354 .max_width_error(shape.width, self.span())?;
2355 let ty_str = self
2356 .ty
2357 .rewrite_result(context, Shape::legacy(max_width, shape.indent))?;
2358 result.push_str(&ty_str);
2359 }
2360 }
2361
2362 Ok(result)
2363 } else {
2364 self.ty.rewrite_result(context, shape)
2365 }
2366 }
2367}
2368
2369fn rewrite_opt_lifetime(
2370 context: &RewriteContext<'_>,
2371 lifetime: Option<ast::Lifetime>,
2372) -> RewriteResult {
2373 let Some(l) = lifetime else {
2374 return Ok(String::new());
2375 };
2376 let mut result = l.rewrite_result(
2377 context,
2378 Shape::legacy(context.config.max_width(), Indent::empty()),
2379 )?;
2380 result.push(' ');
2381 Ok(result)
2382}
2383
2384fn rewrite_explicit_self(
2385 context: &RewriteContext<'_>,
2386 explicit_self: &ast::ExplicitSelf,
2387 param_attrs: &str,
2388 span: Span,
2389 shape: Shape,
2390 has_multiple_attr_lines: bool,
2391) -> RewriteResult {
2392 let self_str = match explicit_self.node {
2393 ast::SelfKind::Region(lt, m) => {
2394 let mut_str = format_mutability(m);
2395 let lifetime_str = rewrite_opt_lifetime(context, lt)?;
2396 format!("&{lifetime_str}{mut_str}self")
2397 }
2398 ast::SelfKind::Pinned(lt, m) => {
2399 let mut_str = m.ptr_str();
2400 let lifetime_str = rewrite_opt_lifetime(context, lt)?;
2401 format!("&{lifetime_str}pin {mut_str} self")
2402 }
2403 ast::SelfKind::Explicit(ref ty, mutability) => {
2404 let type_str = ty.rewrite_result(
2405 context,
2406 Shape::legacy(context.config.max_width(), Indent::empty()),
2407 )?;
2408 format!("{}self: {}", format_mutability(mutability), type_str)
2409 }
2410 ast::SelfKind::Value(mutability) => format!("{}self", format_mutability(mutability)),
2411 };
2412 Ok(combine_strs_with_missing_comments(
2413 context,
2414 param_attrs,
2415 &self_str,
2416 span,
2417 shape,
2418 !has_multiple_attr_lines,
2419 )?)
2420}
2421
2422pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
2423 if param.attrs.is_empty() {
2424 if is_named_param(param) {
2425 param.pat.span.lo()
2426 } else {
2427 param.ty.span.lo()
2428 }
2429 } else {
2430 param.attrs[0].span.lo()
2431 }
2432}
2433
2434pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
2435 match param.ty.kind {
2436 ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
2437 ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
2438 _ => param.ty.span.hi(),
2439 }
2440}
2441
2442pub(crate) fn is_named_param(param: &ast::Param) -> bool {
2443 !matches!(param.pat.kind, ast::PatKind::Missing)
2444}
2445
2446#[derive(Copy, Clone, Debug, PartialEq, Eq)]
2447pub(crate) enum FnBraceStyle {
2448 SameLine,
2449 NextLine,
2450 None,
2451}
2452
2453fn rewrite_fn_base(
2455 context: &RewriteContext<'_>,
2456 indent: Indent,
2457 ident: symbol::Ident,
2458 fn_sig: &FnSig<'_>,
2459 span: Span,
2460 fn_brace_style: FnBraceStyle,
2461) -> Result<(String, bool, bool), RewriteError> {
2462 let mut force_new_line_for_brace = false;
2463
2464 let where_clause = &fn_sig.generics.where_clause;
2465
2466 let mut result = String::with_capacity(1024);
2467 result.push_str(&fn_sig.to_str(context));
2468
2469 result.push_str("fn ");
2471
2472 let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
2474 4
2476 } else {
2477 2
2479 };
2480 let used_width = last_line_used_width(&result, indent.width());
2481 let one_line_budget = context.budget(used_width + overhead);
2482 let shape = Shape {
2483 width: one_line_budget,
2484 indent,
2485 offset: used_width,
2486 };
2487 let fd = fn_sig.decl;
2488 let generics_str = rewrite_generics(
2489 context,
2490 rewrite_ident(context, ident),
2491 &fn_sig.generics,
2492 shape,
2493 )?;
2494 result.push_str(&generics_str);
2495
2496 let snuggle_angle_bracket = generics_str
2497 .lines()
2498 .last()
2499 .map_or(false, |l| l.trim_start().len() == 1);
2500
2501 let ret_str = fd
2504 .output
2505 .rewrite_result(context, Shape::indented(indent, context.config))?;
2506
2507 let multi_line_ret_str = ret_str.contains('\n');
2508 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
2509
2510 let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
2512 context,
2513 &result,
2514 indent,
2515 ret_str_len,
2516 fn_brace_style,
2517 multi_line_ret_str,
2518 );
2519
2520 debug!(
2521 "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
2522 one_line_budget, multi_line_budget, param_indent
2523 );
2524
2525 result.push('(');
2526 if one_line_budget == 0
2528 && !snuggle_angle_bracket
2529 && context.config.indent_style() == IndentStyle::Visual
2530 {
2531 result.push_str(¶m_indent.to_string_with_newline(context.config));
2532 }
2533
2534 let params_end = if fd.inputs.is_empty() {
2535 context
2536 .snippet_provider
2537 .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
2538 } else {
2539 let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
2540 context.snippet_provider.span_after(last_span, ")")
2541 };
2542 let params_span = mk_sp(
2543 context
2544 .snippet_provider
2545 .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
2546 params_end,
2547 );
2548 let param_str = rewrite_params(
2549 context,
2550 &fd.inputs,
2551 one_line_budget,
2552 multi_line_budget,
2553 indent,
2554 param_indent,
2555 params_span,
2556 fd.c_variadic(),
2557 )?;
2558
2559 let put_params_in_block = match context.config.indent_style() {
2560 IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
2561 _ => false,
2562 } && !fd.inputs.is_empty();
2563
2564 let mut params_last_line_contains_comment = false;
2565 let mut no_params_and_over_max_width = false;
2566
2567 if put_params_in_block {
2568 param_indent = indent.block_indent(context.config);
2569 result.push_str(¶m_indent.to_string_with_newline(context.config));
2570 result.push_str(¶m_str);
2571 result.push_str(&indent.to_string_with_newline(context.config));
2572 result.push(')');
2573 } else {
2574 result.push_str(¶m_str);
2575 let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
2576 let closing_paren_overflow_max_width =
2579 fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
2580 params_last_line_contains_comment = param_str
2583 .lines()
2584 .last()
2585 .map_or(false, |last_line| last_line.contains("//"));
2586
2587 if context.config.style_edition() >= StyleEdition::Edition2024 {
2588 if closing_paren_overflow_max_width {
2589 result.push(')');
2590 result.push_str(&indent.to_string_with_newline(context.config));
2591 no_params_and_over_max_width = true;
2592 } else if params_last_line_contains_comment {
2593 result.push_str(&indent.to_string_with_newline(context.config));
2594 result.push(')');
2595 no_params_and_over_max_width = true;
2596 } else {
2597 result.push(')');
2598 }
2599 } else {
2600 if closing_paren_overflow_max_width || params_last_line_contains_comment {
2601 result.push_str(&indent.to_string_with_newline(context.config));
2602 }
2603 result.push(')');
2604 }
2605 }
2606
2607 if let ast::FnRetTy::Ty(..) = fd.output {
2609 let ret_should_indent = match context.config.indent_style() {
2610 IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
2612 _ if params_last_line_contains_comment => false,
2613 _ if result.contains('\n') || multi_line_ret_str => true,
2614 _ => {
2615 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
2619
2620 if where_clause.predicates.is_empty() {
2623 sig_length += 2;
2624 }
2625
2626 sig_length > context.config.max_width()
2627 }
2628 };
2629 let ret_shape = if ret_should_indent {
2630 if context.config.style_edition() <= StyleEdition::Edition2021
2631 || context.config.indent_style() == IndentStyle::Visual
2632 {
2633 let indent = if param_str.is_empty() {
2634 force_new_line_for_brace = true;
2636 indent + 4
2637 } else {
2638 param_indent
2642 };
2643
2644 result.push_str(&indent.to_string_with_newline(context.config));
2645 Shape::indented(indent, context.config)
2646 } else {
2647 let mut ret_shape = Shape::indented(indent, context.config);
2648 if param_str.is_empty() {
2649 force_new_line_for_brace = true;
2651 ret_shape = if context.use_block_indent() {
2652 ret_shape.offset_left(4).unwrap_or(ret_shape)
2653 } else {
2654 ret_shape.indent = ret_shape.indent + 4;
2655 ret_shape
2656 };
2657 }
2658
2659 result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
2660 ret_shape
2661 }
2662 } else {
2663 if context.config.style_edition() >= StyleEdition::Edition2024 {
2664 if !param_str.is_empty() || !no_params_and_over_max_width {
2665 result.push(' ');
2666 }
2667 } else {
2668 result.push(' ');
2669 }
2670
2671 let ret_shape = Shape::indented(indent, context.config);
2672 ret_shape
2673 .offset_left(last_line_width(&result))
2674 .unwrap_or(ret_shape)
2675 };
2676
2677 if multi_line_ret_str || ret_should_indent {
2678 let ret_str = fd.output.rewrite_result(context, ret_shape)?;
2681 result.push_str(&ret_str);
2682 } else {
2683 result.push_str(&ret_str);
2684 }
2685
2686 let snippet_lo = fd.output.span().hi();
2688 if where_clause.predicates.is_empty() {
2689 let snippet_hi = span.hi();
2690 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
2691 let original_starts_with_newline = snippet
2693 .find(|c| c != ' ')
2694 .map_or(false, |i| starts_with_newline(&snippet[i..]));
2695 let original_ends_with_newline = snippet
2696 .rfind(|c| c != ' ')
2697 .map_or(false, |i| snippet[i..].ends_with('\n'));
2698 let snippet = snippet.trim();
2699 if !snippet.is_empty() {
2700 result.push(if original_starts_with_newline {
2701 '\n'
2702 } else {
2703 ' '
2704 });
2705 result.push_str(snippet);
2706 if original_ends_with_newline {
2707 force_new_line_for_brace = true;
2708 }
2709 }
2710 }
2711 }
2712
2713 let pos_before_where = match fd.output {
2714 ast::FnRetTy::Default(..) => params_span.hi(),
2715 ast::FnRetTy::Ty(ref ty) => ty.span.hi(),
2716 };
2717
2718 let is_params_multi_lined = param_str.contains('\n');
2719
2720 let space = if put_params_in_block && ret_str.is_empty() {
2721 WhereClauseSpace::Space
2722 } else {
2723 WhereClauseSpace::Newline
2724 };
2725 let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
2726 if is_params_multi_lined {
2727 option.veto_single_line();
2728 }
2729 let where_clause_str = rewrite_where_clause(
2730 context,
2731 &where_clause.predicates,
2732 where_clause.span,
2733 context.config.brace_style(),
2734 Shape::indented(indent, context.config),
2735 true,
2736 "{",
2737 Some(span.hi()),
2738 pos_before_where,
2739 option,
2740 )?;
2741 if where_clause_str.is_empty() {
2744 if let ast::FnRetTy::Default(ret_span) = fd.output {
2745 match recover_missing_comment_in_span(
2746 mk_sp(ret_span.lo(), span.hi()),
2748 shape,
2749 context,
2750 last_line_width(&result),
2751 ) {
2752 Ok(ref missing_comment) if !missing_comment.is_empty() => {
2753 result.push_str(missing_comment);
2754 force_new_line_for_brace = true;
2755 }
2756 _ => (),
2757 }
2758 }
2759 }
2760
2761 result.push_str(&where_clause_str);
2762
2763 let ends_with_comment = last_line_contains_single_line_comment(&result);
2764 force_new_line_for_brace |= ends_with_comment;
2765 force_new_line_for_brace |=
2766 is_params_multi_lined && context.config.where_single_line() && !where_clause_str.is_empty();
2767 Ok((result, ends_with_comment, force_new_line_for_brace))
2768}
2769
2770#[derive(Copy, Clone)]
2772enum WhereClauseSpace {
2773 Space,
2775 Newline,
2777 None,
2779}
2780
2781#[derive(Copy, Clone)]
2782struct WhereClauseOption {
2783 suppress_comma: bool, snuggle: WhereClauseSpace,
2785 allow_single_line: bool, veto_single_line: bool, }
2788
2789impl WhereClauseOption {
2790 fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
2791 WhereClauseOption {
2792 suppress_comma,
2793 snuggle,
2794 allow_single_line: false,
2795 veto_single_line: false,
2796 }
2797 }
2798
2799 fn snuggled(current: &str) -> WhereClauseOption {
2800 WhereClauseOption {
2801 suppress_comma: false,
2802 snuggle: if last_line_width(current) == 1 {
2803 WhereClauseSpace::Space
2804 } else {
2805 WhereClauseSpace::Newline
2806 },
2807 allow_single_line: false,
2808 veto_single_line: false,
2809 }
2810 }
2811
2812 fn suppress_comma(&mut self) {
2813 self.suppress_comma = true
2814 }
2815
2816 fn allow_single_line(&mut self) {
2817 self.allow_single_line = true
2818 }
2819
2820 fn snuggle(&mut self) {
2821 self.snuggle = WhereClauseSpace::Space
2822 }
2823
2824 fn veto_single_line(&mut self) {
2825 self.veto_single_line = true;
2826 }
2827}
2828
2829fn rewrite_params(
2830 context: &RewriteContext<'_>,
2831 params: &[ast::Param],
2832 one_line_budget: usize,
2833 multi_line_budget: usize,
2834 indent: Indent,
2835 param_indent: Indent,
2836 span: Span,
2837 variadic: bool,
2838) -> RewriteResult {
2839 if params.is_empty() {
2840 let comment = context
2841 .snippet(mk_sp(
2842 span.lo(),
2843 span.hi() - BytePos(1),
2845 ))
2846 .trim();
2847 return Ok(comment.to_owned());
2848 }
2849 let param_items: Vec<_> = itemize_list(
2850 context.snippet_provider,
2851 params.iter(),
2852 ")",
2853 ",",
2854 |param| span_lo_for_param(param),
2855 |param| param.ty.span.hi(),
2856 |param| {
2857 param
2858 .rewrite_result(context, Shape::legacy(multi_line_budget, param_indent))
2859 .or_else(|_| Ok(context.snippet(param.span()).to_owned()))
2860 },
2861 span.lo(),
2862 span.hi(),
2863 false,
2864 )
2865 .collect();
2866
2867 let tactic = definitive_tactic(
2868 ¶m_items,
2869 context
2870 .config
2871 .fn_params_layout()
2872 .to_list_tactic(param_items.len()),
2873 Separator::Comma,
2874 one_line_budget,
2875 );
2876 let budget = match tactic {
2877 DefinitiveListTactic::Horizontal => one_line_budget,
2878 _ => multi_line_budget,
2879 };
2880 let indent = match context.config.indent_style() {
2881 IndentStyle::Block => indent.block_indent(context.config),
2882 IndentStyle::Visual => param_indent,
2883 };
2884 let trailing_separator = if variadic {
2885 SeparatorTactic::Never
2886 } else {
2887 match context.config.indent_style() {
2888 IndentStyle::Block => context.config.trailing_comma(),
2889 IndentStyle::Visual => SeparatorTactic::Never,
2890 }
2891 };
2892 let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
2893 .tactic(tactic)
2894 .trailing_separator(trailing_separator)
2895 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
2896 .preserve_newline(true);
2897 write_list(¶m_items, &fmt)
2898}
2899
2900fn compute_budgets_for_params(
2901 context: &RewriteContext<'_>,
2902 result: &str,
2903 indent: Indent,
2904 ret_str_len: usize,
2905 fn_brace_style: FnBraceStyle,
2906 force_vertical_layout: bool,
2907) -> (usize, usize, Indent) {
2908 debug!(
2909 "compute_budgets_for_params {} {:?}, {}, {:?}",
2910 result.len(),
2911 indent,
2912 ret_str_len,
2913 fn_brace_style,
2914 );
2915 if !result.contains('\n') && !force_vertical_layout {
2917 let overhead = if ret_str_len == 0 { 2 } else { 3 };
2919 let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2920 match fn_brace_style {
2921 FnBraceStyle::None => used_space += 1, FnBraceStyle::SameLine => used_space += 2, FnBraceStyle::NextLine => (),
2924 }
2925 let one_line_budget = context.budget(used_space);
2926
2927 if one_line_budget > 0 {
2928 let (indent, multi_line_budget) = match context.config.indent_style() {
2930 IndentStyle::Block => {
2931 let indent = indent.block_indent(context.config);
2932 (indent, context.budget(indent.width() + 1))
2933 }
2934 IndentStyle::Visual => {
2935 let indent = indent + result.len() + 1;
2936 let multi_line_overhead = match fn_brace_style {
2937 FnBraceStyle::SameLine => 4,
2938 _ => 2,
2939 } + indent.width();
2940 (indent, context.budget(multi_line_overhead))
2941 }
2942 };
2943
2944 return (one_line_budget, multi_line_budget, indent);
2945 }
2946 }
2947
2948 let new_indent = indent.block_indent(context.config);
2950 let used_space = match context.config.indent_style() {
2951 IndentStyle::Block => new_indent.width() + 1,
2953 IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2955 };
2956 (0, context.budget(used_space), new_indent)
2957}
2958
2959fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
2960 let predicate_count = where_clause.predicates.len();
2961
2962 if config.where_single_line() && predicate_count == 1 {
2963 return FnBraceStyle::SameLine;
2964 }
2965 let brace_style = config.brace_style();
2966
2967 let use_next_line = brace_style == BraceStyle::AlwaysNextLine
2968 || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
2969 if use_next_line {
2970 FnBraceStyle::NextLine
2971 } else {
2972 FnBraceStyle::SameLine
2973 }
2974}
2975
2976fn rewrite_generics(
2977 context: &RewriteContext<'_>,
2978 ident: &str,
2979 generics: &ast::Generics,
2980 shape: Shape,
2981) -> RewriteResult {
2982 if generics.params.is_empty() {
2986 return Ok(ident.to_owned());
2987 }
2988
2989 let params = generics.params.iter();
2990 overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
2991}
2992
2993fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2994 match config.indent_style() {
2995 IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2996 IndentStyle::Block => {
2997 shape
2999 .block()
3000 .block_indent(config.tab_spaces())
3001 .with_max_width(config)
3002 .sub_width(1)
3003 }
3004 }
3005}
3006
3007fn rewrite_where_clause_rfc_style(
3008 context: &RewriteContext<'_>,
3009 predicates: &[ast::WherePredicate],
3010 where_span: Span,
3011 shape: Shape,
3012 terminator: &str,
3013 span_end: Option<BytePos>,
3014 span_end_before_where: BytePos,
3015 where_clause_option: WhereClauseOption,
3016) -> RewriteResult {
3017 let (where_keyword, allow_single_line) = rewrite_where_keyword(
3018 context,
3019 predicates,
3020 where_span,
3021 shape,
3022 span_end_before_where,
3023 where_clause_option,
3024 )?;
3025
3026 let clause_shape = shape
3028 .block()
3029 .with_max_width(context.config)
3030 .block_left(context.config.tab_spaces())
3031 .and_then(|s| s.sub_width(1))
3032 .max_width_error(shape.width, where_span)?;
3033 let force_single_line = context.config.where_single_line()
3034 && predicates.len() == 1
3035 && !where_clause_option.veto_single_line;
3036
3037 let preds_str = rewrite_bounds_on_where_clause(
3038 context,
3039 predicates,
3040 clause_shape,
3041 terminator,
3042 span_end,
3043 where_clause_option,
3044 force_single_line,
3045 )?;
3046
3047 let clause_sep =
3049 if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
3050 || force_single_line
3051 {
3052 Cow::from(" ")
3053 } else {
3054 clause_shape.indent.to_string_with_newline(context.config)
3055 };
3056
3057 Ok(format!("{where_keyword}{clause_sep}{preds_str}"))
3058}
3059
3060fn rewrite_where_keyword(
3062 context: &RewriteContext<'_>,
3063 predicates: &[ast::WherePredicate],
3064 where_span: Span,
3065 shape: Shape,
3066 span_end_before_where: BytePos,
3067 where_clause_option: WhereClauseOption,
3068) -> Result<(String, bool), RewriteError> {
3069 let block_shape = shape.block().with_max_width(context.config);
3070 let clause_shape = block_shape
3072 .block_left(context.config.tab_spaces())
3073 .and_then(|s| s.sub_width(1))
3074 .max_width_error(block_shape.width, where_span)?;
3075
3076 let comment_separator = |comment: &str, shape: Shape| {
3077 if comment.is_empty() {
3078 Cow::from("")
3079 } else {
3080 shape.indent.to_string_with_newline(context.config)
3081 }
3082 };
3083
3084 let (span_before, span_after) =
3085 missing_span_before_after_where(span_end_before_where, predicates, where_span);
3086 let (comment_before, comment_after) =
3087 rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
3088
3089 let starting_newline = match where_clause_option.snuggle {
3090 WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
3091 WhereClauseSpace::None => Cow::from(""),
3092 _ => block_shape.indent.to_string_with_newline(context.config),
3093 };
3094
3095 let newline_before_where = comment_separator(&comment_before, shape);
3096 let newline_after_where = comment_separator(&comment_after, clause_shape);
3097 let result = format!(
3098 "{starting_newline}{comment_before}{newline_before_where}where\
3099{newline_after_where}{comment_after}"
3100 );
3101 let allow_single_line = where_clause_option.allow_single_line
3102 && comment_before.is_empty()
3103 && comment_after.is_empty();
3104
3105 Ok((result, allow_single_line))
3106}
3107
3108fn rewrite_bounds_on_where_clause(
3110 context: &RewriteContext<'_>,
3111 predicates: &[ast::WherePredicate],
3112 shape: Shape,
3113 terminator: &str,
3114 span_end: Option<BytePos>,
3115 where_clause_option: WhereClauseOption,
3116 force_single_line: bool,
3117) -> RewriteResult {
3118 let span_start = predicates[0].span().lo();
3119 let len = predicates.len();
3122 let end_of_preds = predicates[len - 1].span().hi();
3123 let span_end = span_end.unwrap_or(end_of_preds);
3124 let items = itemize_list(
3125 context.snippet_provider,
3126 predicates.iter(),
3127 terminator,
3128 ",",
3129 |pred| pred.span().lo(),
3130 |pred| pred.span().hi(),
3131 |pred| pred.rewrite_result(context, shape),
3132 span_start,
3133 span_end,
3134 false,
3135 );
3136 let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
3137 SeparatorTactic::Never
3138 } else {
3139 context.config.trailing_comma()
3140 };
3141
3142 let shape_tactic = if force_single_line {
3145 DefinitiveListTactic::Horizontal
3146 } else {
3147 DefinitiveListTactic::Vertical
3148 };
3149
3150 let preserve_newline = context.config.style_edition() <= StyleEdition::Edition2021;
3151
3152 let fmt = ListFormatting::new(shape, context.config)
3153 .tactic(shape_tactic)
3154 .trailing_separator(comma_tactic)
3155 .preserve_newline(preserve_newline);
3156 write_list(&items.collect::<Vec<_>>(), &fmt)
3157}
3158
3159fn rewrite_where_clause(
3160 context: &RewriteContext<'_>,
3161 predicates: &[ast::WherePredicate],
3162 where_span: Span,
3163 brace_style: BraceStyle,
3164 shape: Shape,
3165 on_new_line: bool,
3166 terminator: &str,
3167 span_end: Option<BytePos>,
3168 span_end_before_where: BytePos,
3169 where_clause_option: WhereClauseOption,
3170) -> RewriteResult {
3171 if predicates.is_empty() {
3172 return Ok(String::new());
3173 }
3174
3175 if context.config.indent_style() == IndentStyle::Block {
3176 return rewrite_where_clause_rfc_style(
3177 context,
3178 predicates,
3179 where_span,
3180 shape,
3181 terminator,
3182 span_end,
3183 span_end_before_where,
3184 where_clause_option,
3185 );
3186 }
3187
3188 let extra_indent = Indent::new(context.config.tab_spaces(), 0);
3189
3190 let offset = match context.config.indent_style() {
3191 IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
3192 IndentStyle::Visual => shape.indent + extra_indent + 6,
3194 };
3195 let budget = context.config.max_width() - offset.width();
3199 let span_start = predicates[0].span().lo();
3200 let len = predicates.len();
3203 let end_of_preds = predicates[len - 1].span().hi();
3204 let span_end = span_end.unwrap_or(end_of_preds);
3205 let items = itemize_list(
3206 context.snippet_provider,
3207 predicates.iter(),
3208 terminator,
3209 ",",
3210 |pred| pred.span().lo(),
3211 |pred| pred.span().hi(),
3212 |pred| pred.rewrite_result(context, Shape::legacy(budget, offset)),
3213 span_start,
3214 span_end,
3215 false,
3216 );
3217 let item_vec = items.collect::<Vec<_>>();
3218 let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
3220
3221 let mut comma_tactic = context.config.trailing_comma();
3222 if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
3224 comma_tactic = SeparatorTactic::Never;
3225 }
3226
3227 let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
3228 .tactic(tactic)
3229 .trailing_separator(comma_tactic)
3230 .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
3231 .preserve_newline(true);
3232 let preds_str = write_list(&item_vec, &fmt)?;
3233
3234 let end_length = if terminator == "{" {
3235 match brace_style {
3238 BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
3239 BraceStyle::PreferSameLine => 2,
3240 }
3241 } else if terminator == "=" {
3242 2
3243 } else {
3244 terminator.len()
3245 };
3246 if on_new_line
3247 || preds_str.contains('\n')
3248 || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
3249 {
3250 Ok(format!(
3251 "\n{}where {}",
3252 (shape.indent + extra_indent).to_string(context.config),
3253 preds_str
3254 ))
3255 } else {
3256 Ok(format!(" where {preds_str}"))
3257 }
3258}
3259
3260fn missing_span_before_after_where(
3261 before_item_span_end: BytePos,
3262 predicates: &[ast::WherePredicate],
3263 where_span: Span,
3264) -> (Span, Span) {
3265 let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
3266 let pos_after_where = where_span.lo() + BytePos(5);
3268 let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
3269 (missing_span_before, missing_span_after)
3270}
3271
3272fn rewrite_comments_before_after_where(
3273 context: &RewriteContext<'_>,
3274 span_before_where: Span,
3275 span_after_where: Span,
3276 shape: Shape,
3277) -> Result<(String, String), RewriteError> {
3278 let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
3279 let after_comment = rewrite_missing_comment(
3280 span_after_where,
3281 shape.block_indent(context.config.tab_spaces()),
3282 context,
3283 )?;
3284 Ok((before_comment, after_comment))
3285}
3286
3287fn format_header(
3288 context: &RewriteContext<'_>,
3289 item_name: &str,
3290 ident: symbol::Ident,
3291 vis: &ast::Visibility,
3292 offset: Indent,
3293) -> String {
3294 let mut result = String::with_capacity(128);
3295 let shape = Shape::indented(offset, context.config);
3296
3297 result.push_str(format_visibility(context, vis).trim());
3298
3299 let after_vis = vis.span.hi();
3301 if let Some(before_item_name) = context
3302 .snippet_provider
3303 .opt_span_before(mk_sp(vis.span.lo(), ident.span.hi()), item_name.trim())
3304 {
3305 let missing_span = mk_sp(after_vis, before_item_name);
3306 if let Ok(result_with_comment) = combine_strs_with_missing_comments(
3307 context,
3308 &result,
3309 item_name,
3310 missing_span,
3311 shape,
3312 true,
3313 ) {
3314 result = result_with_comment;
3315 }
3316 }
3317
3318 result.push_str(rewrite_ident(context, ident));
3319
3320 result
3321}
3322
3323#[derive(PartialEq, Eq, Clone, Copy)]
3324enum BracePos {
3325 None,
3326 Auto,
3327 ForceSameLine,
3328}
3329
3330fn format_generics(
3331 context: &RewriteContext<'_>,
3332 generics: &ast::Generics,
3333 brace_style: BraceStyle,
3334 brace_pos: BracePos,
3335 offset: Indent,
3336 span: Span,
3337 used_width: usize,
3338) -> Option<String> {
3339 let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
3340 let mut result = rewrite_generics(context, "", generics, shape).ok()?;
3341
3342 let span_end_before_where = if !generics.params.is_empty() {
3345 generics.span.hi()
3346 } else {
3347 span.lo()
3348 };
3349 let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
3350 let budget = context.budget(last_line_used_width(&result, offset.width()));
3351 let mut option = WhereClauseOption::snuggled(&result);
3352 if brace_pos == BracePos::None {
3353 option.suppress_comma = true;
3354 }
3355 let where_clause_str = rewrite_where_clause(
3356 context,
3357 &generics.where_clause.predicates,
3358 generics.where_clause.span,
3359 brace_style,
3360 Shape::legacy(budget, offset.block_only()),
3361 true,
3362 "{",
3363 Some(span.hi()),
3364 span_end_before_where,
3365 option,
3366 )
3367 .ok()?;
3368 result.push_str(&where_clause_str);
3369 (
3370 brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
3371 None,
3373 )
3374 } else {
3375 (
3376 brace_pos == BracePos::ForceSameLine
3377 || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
3378 || brace_style != BraceStyle::AlwaysNextLine)
3379 || trimmed_last_line_width(&result) == 1,
3380 rewrite_missing_comment(
3381 mk_sp(
3382 span_end_before_where,
3383 if brace_pos == BracePos::None {
3384 span.hi()
3385 } else {
3386 context.snippet_provider.span_before_last(span, "{")
3387 },
3388 ),
3389 shape,
3390 context,
3391 )
3392 .ok(),
3393 )
3394 };
3395 let missed_line_comments = missed_comments
3397 .filter(|missed_comments| !missed_comments.is_empty())
3398 .map_or(false, |missed_comments| {
3399 let is_block = is_last_comment_block(&missed_comments);
3400 let sep = if is_block { " " } else { "\n" };
3401 result.push_str(sep);
3402 result.push_str(&missed_comments);
3403 !is_block
3404 });
3405 if brace_pos == BracePos::None {
3406 return Some(result);
3407 }
3408 let total_used_width = last_line_used_width(&result, used_width);
3409 let remaining_budget = context.budget(total_used_width);
3410 let overhead = if brace_pos == BracePos::ForceSameLine {
3414 3
3416 } else {
3417 2
3419 };
3420 let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
3421 if !forbid_same_line_brace && same_line_brace {
3422 result.push(' ');
3423 } else {
3424 result.push('\n');
3425 result.push_str(&offset.block_only().to_string(context.config));
3426 }
3427 result.push('{');
3428
3429 Some(result)
3430}
3431
3432impl Rewrite for ast::ForeignItem {
3433 fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
3434 self.rewrite_result(context, shape).ok()
3435 }
3436
3437 fn rewrite_result(&self, context: &RewriteContext<'_>, shape: Shape) -> RewriteResult {
3438 let attrs_str = self.attrs.rewrite_result(context, shape)?;
3439 let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
3442
3443 let item_str = match self.kind {
3444 ast::ForeignItemKind::Fn(ref fn_kind) => {
3445 let ast::Fn {
3446 defaultness,
3447 ref sig,
3448 ident,
3449 ref generics,
3450 ref body,
3451 ..
3452 } = **fn_kind;
3453 if body.is_some() {
3454 let mut visitor = FmtVisitor::from_context(context);
3455 visitor.block_indent = shape.indent;
3456 visitor.last_pos = self.span.lo();
3457 let inner_attrs = inner_attributes(&self.attrs);
3458 let fn_ctxt = visit::FnCtxt::Foreign;
3459 visitor.visit_fn(
3460 ident,
3461 visit::FnKind::Fn(fn_ctxt, &self.vis, fn_kind),
3462 &sig.decl,
3463 self.span,
3464 defaultness,
3465 Some(&inner_attrs),
3466 );
3467 Ok(visitor.buffer.to_owned())
3468 } else {
3469 rewrite_fn_base(
3470 context,
3471 shape.indent,
3472 ident,
3473 &FnSig::from_method_sig(sig, generics, &self.vis),
3474 span,
3475 FnBraceStyle::None,
3476 )
3477 .map(|(s, _, _)| format!("{};", s))
3478 }
3479 }
3480 ast::ForeignItemKind::Static(ref static_foreign_item) => {
3481 let vis = format_visibility(context, &self.vis);
3484 let safety = format_safety(static_foreign_item.safety);
3485 let mut_str = format_mutability(static_foreign_item.mutability);
3486 let prefix = format!(
3487 "{}{}static {}{}:",
3488 vis,
3489 safety,
3490 mut_str,
3491 rewrite_ident(context, static_foreign_item.ident)
3492 );
3493 rewrite_assign_rhs(
3495 context,
3496 prefix,
3497 &static_foreign_item.ty,
3498 &RhsAssignKind::Ty,
3499 shape
3500 .sub_width(1)
3501 .max_width_error(shape.width, static_foreign_item.ty.span)?,
3502 )
3503 .map(|s| s + ";")
3504 }
3505 ast::ForeignItemKind::TyAlias(ref ty_alias) => {
3506 let kind = ItemVisitorKind::ForeignItem;
3507 rewrite_type_alias(ty_alias, &self.vis, context, shape.indent, kind, self.span)
3508 }
3509 ast::ForeignItemKind::MacCall(ref mac) => {
3510 rewrite_macro(mac, context, shape, MacroPosition::Item)
3511 }
3512 }?;
3513
3514 let missing_span = if self.attrs.is_empty() {
3515 mk_sp(self.span.lo(), self.span.lo())
3516 } else {
3517 mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
3518 };
3519 combine_strs_with_missing_comments(
3520 context,
3521 &attrs_str,
3522 &item_str,
3523 missing_span,
3524 shape,
3525 false,
3526 )
3527 }
3528}
3529
3530fn rewrite_attrs(
3532 context: &RewriteContext<'_>,
3533 item: &ast::Item,
3534 item_str: &str,
3535 shape: Shape,
3536) -> Option<String> {
3537 let attrs = filter_inline_attrs(&item.attrs, item.span());
3538 let attrs_str = attrs.rewrite(context, shape)?;
3539
3540 let missed_span = if attrs.is_empty() {
3541 mk_sp(item.span.lo(), item.span.lo())
3542 } else {
3543 mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
3544 };
3545
3546 let allow_extend = if attrs.len() == 1 {
3547 let line_len = attrs_str.len() + 1 + item_str.len();
3548 !attrs.first().unwrap().is_doc_comment()
3549 && context.config.inline_attribute_width() >= line_len
3550 } else {
3551 false
3552 };
3553
3554 combine_strs_with_missing_comments(
3555 context,
3556 &attrs_str,
3557 item_str,
3558 missed_span,
3559 shape,
3560 allow_extend,
3561 )
3562 .ok()
3563}
3564
3565pub(crate) fn rewrite_mod(
3568 context: &RewriteContext<'_>,
3569 item: &ast::Item,
3570 ident: Ident,
3571 attrs_shape: Shape,
3572) -> Option<String> {
3573 let mut result = String::with_capacity(32);
3574 result.push_str(&*format_visibility(context, &item.vis));
3575 result.push_str("mod ");
3576 result.push_str(rewrite_ident(context, ident));
3577 result.push(';');
3578 rewrite_attrs(context, item, &result, attrs_shape)
3579}
3580
3581pub(crate) fn rewrite_extern_crate(
3584 context: &RewriteContext<'_>,
3585 item: &ast::Item,
3586 attrs_shape: Shape,
3587) -> Option<String> {
3588 assert!(is_extern_crate(item));
3589 let new_str = context.snippet(item.span);
3590 let item_str = if contains_comment(new_str) {
3591 new_str.to_owned()
3592 } else {
3593 let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
3594 String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
3595 };
3596 rewrite_attrs(context, item, &item_str, attrs_shape)
3597}
3598
3599pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
3601 !matches!(
3602 item.kind,
3603 ast::ItemKind::Mod(_, _, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
3604 )
3605}
3606
3607pub(crate) fn is_use_item(item: &ast::Item) -> bool {
3608 matches!(item.kind, ast::ItemKind::Use(_))
3609}
3610
3611pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
3612 matches!(item.kind, ast::ItemKind::ExternCrate(..))
3613}