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