1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
11 // Formatting top-level items - functions, structs, enums, traits, impls.
14 use codemap::SpanUtils;
15 use utils::{format_mutability, format_visibility, contains_skip, end_typaram, wrap_str,
16 last_line_width, format_unsafety, trim_newlines, stmt_expr, semicolon_for_expr};
17 use lists::{write_list, itemize_list, ListItem, ListFormatting, SeparatorTactic,
18 DefinitiveListTactic, ListTactic, definitive_tactic, format_item_list};
19 use expr::{is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, type_annotation_separator};
20 use comment::{FindUncommented, contains_comment};
21 use visitor::FmtVisitor;
22 use rewrite::{Rewrite, RewriteContext};
23 use config::{Config, BlockIndentStyle, Density, ReturnIndent, BraceStyle, FnArgLayoutStyle};
24 use itertools::Itertools;
26 use syntax::{ast, abi, codemap, ptr, symbol};
27 use syntax::codemap::{Span, BytePos, mk_sp};
28 use syntax::ast::ImplItem;
30 // Statements of the form
31 // let pat: ty = init;
32 impl Rewrite for ast::Local {
33 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
34 debug!("Local::rewrite {:?} {} {:?}", self, width, offset);
35 let mut result = "let ".to_owned();
36 let pattern_offset = offset + result.len();
38 let pattern_width = try_opt!(width.checked_sub(pattern_offset.width() + 1));
40 let pat_str = try_opt!(self.pat.rewrite(&context, pattern_width, pattern_offset));
41 result.push_str(&pat_str);
43 // String that is placed within the assignment pattern and expression.
45 let mut infix = String::new();
47 if let Some(ref ty) = self.ty {
48 let separator = type_annotation_separator(context.config);
49 let indent = offset + last_line_width(&result) + separator.len();
51 let budget = try_opt!(width.checked_sub(indent.width() + 1));
52 let rewrite = try_opt!(ty.rewrite(context, budget, indent));
54 infix.push_str(separator);
55 infix.push_str(&rewrite);
58 if self.init.is_some() {
65 result.push_str(&infix);
67 if let Some(ref ex) = self.init {
68 // 1 = trailing semicolon;
69 let budget = try_opt!(width.checked_sub(context.block_indent.width() + 1));
72 try_opt!(rewrite_assign_rhs(&context, result, ex, budget, context.block_indent));
80 // TODO convert to using rewrite style rather than visitor
81 // TODO format modules in this style
84 keyword: &'static str,
86 vis: Option<&'a ast::Visibility>,
87 body: Vec<BodyElement<'a>>,
92 fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
93 let abi = if fm.abi == abi::Abi::C && !config.force_explicit_abi {
96 format!("extern {}", fm.abi)
102 body: fm.items.iter().map(|i| BodyElement::ForeignItem(i)).collect(),
108 enum BodyElement<'a> {
109 // Stmt(&'a ast::Stmt),
110 // Field(&'a ast::Field),
111 // Variant(&'a ast::Variant),
112 // Item(&'a ast::Item),
113 ForeignItem(&'a ast::ForeignItem),
116 impl<'a> FmtVisitor<'a> {
117 fn format_item(&mut self, item: Item) {
118 self.buffer.push_str(&item.abi);
119 self.buffer.push_str(" ");
121 let snippet = self.snippet(item.span);
122 let brace_pos = snippet.find_uncommented("{").unwrap();
124 self.buffer.push_str("{");
125 if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
126 // FIXME: this skips comments between the extern keyword and the opening
128 self.last_pos = item.span.lo + BytePos(brace_pos as u32 + 1);
129 self.block_indent = self.block_indent.block_indent(self.config);
131 if item.body.is_empty() {
132 self.format_missing_no_indent(item.span.hi - BytePos(1));
133 self.block_indent = self.block_indent.block_unindent(self.config);
135 self.buffer.push_str(&self.block_indent.to_string(self.config));
137 for item in &item.body {
138 self.format_body_element(item);
141 self.block_indent = self.block_indent.block_unindent(self.config);
142 self.format_missing_with_indent(item.span.hi - BytePos(1));
146 self.buffer.push_str("}");
147 self.last_pos = item.span.hi;
150 fn format_body_element(&mut self, element: &BodyElement) {
152 BodyElement::ForeignItem(ref item) => self.format_foreign_item(item),
156 pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
157 let item = Item::from_foreign_mod(fm, span, self.config);
158 self.format_item(item);
161 fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
162 self.format_missing_with_indent(item.span.lo);
163 // Drop semicolon or it will be interpreted as comment.
164 // FIXME: this may be a faulty span from libsyntax.
165 let span = mk_sp(item.span.lo, item.span.hi - BytePos(1));
168 ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
169 let indent = self.block_indent;
170 let rewrite = rewrite_fn_base(&self.get_context(),
175 ast::Unsafety::Normal,
176 ast::Constness::NotConst,
177 ast::Defaultness::Final,
178 // These are not actually rust functions,
179 // but we format them as such.
187 Some((new_fn, _)) => {
188 self.buffer.push_str(&new_fn);
189 self.buffer.push_str(";");
191 None => self.format_missing(item.span.hi),
194 ast::ForeignItemKind::Static(ref ty, is_mutable) => {
195 // FIXME(#21): we're dropping potential comments in between the
196 // function keywords here.
197 let vis = format_visibility(&item.vis);
198 let mut_str = if is_mutable { "mut " } else { "" };
199 let prefix = format!("{}static {}{}: ", vis, mut_str, item.ident);
200 let offset = self.block_indent + prefix.len();
202 let width = self.config.max_width - offset.width() - 1;
203 let rewrite = ty.rewrite(&self.get_context(), width, offset);
207 self.buffer.push_str(&prefix);
208 self.buffer.push_str(&result);
209 self.buffer.push_str(";");
211 None => self.format_missing(item.span.hi),
216 self.last_pos = item.span.hi;
219 pub fn rewrite_fn(&mut self,
223 generics: &ast::Generics,
224 unsafety: ast::Unsafety,
225 constness: ast::Constness,
226 defaultness: ast::Defaultness,
228 vis: &ast::Visibility,
232 let mut newline_brace = newline_for_brace(self.config, &generics.where_clause);
233 let context = self.get_context();
235 let block_snippet = self.snippet(codemap::mk_sp(block.span.lo, block.span.hi));
236 let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
237 !context.config.fn_empty_single_line;
239 let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(&context,
253 if self.config.fn_brace_style != BraceStyle::AlwaysNextLine && !result.contains('\n') {
254 newline_brace = false;
255 } else if force_newline_brace {
256 newline_brace = true;
259 // Prepare for the function body by possibly adding a newline and
261 // FIXME we'll miss anything between the end of the signature and the
262 // start of the body, but we need more spans from the compiler to solve
266 result.push_str(&indent.to_string(self.config));
271 self.single_line_fn(&result, block).or_else(|| Some(result))
274 pub fn rewrite_required_fn(&mut self,
277 sig: &ast::MethodSig,
280 // Drop semicolon or it will be interpreted as comment.
281 let span = mk_sp(span.lo, span.hi - BytePos(1));
282 let context = self.get_context();
284 let (mut result, _) = try_opt!(rewrite_fn_base(&context,
291 ast::Defaultness::Final,
293 &ast::Visibility::Inherited,
298 // Re-attach semicolon
304 fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
305 if fn_str.contains('\n') {
309 let codemap = self.get_context().codemap;
311 if self.config.fn_empty_single_line && is_empty_block(block, codemap) &&
312 self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width {
313 return Some(format!("{}{{}}", fn_str));
316 if self.config.fn_single_line && is_simple_block_stmt(block, codemap) {
318 if let Some(ref stmt) = block.stmts.first() {
319 match stmt_expr(stmt) {
321 let suffix = if semicolon_for_expr(e) { ";" } else { "" };
323 e.rewrite(&self.get_context(),
324 self.config.max_width - self.block_indent.width(),
327 .or_else(|| Some(self.snippet(e.span)))
330 stmt.rewrite(&self.get_context(),
331 self.config.max_width - self.block_indent.width(),
340 if let Some(res) = rewrite {
341 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
342 if !res.contains('\n') && width <= self.config.max_width {
343 return Some(format!("{}{{ {} }}", fn_str, res));
351 pub fn visit_enum(&mut self,
353 vis: &ast::Visibility,
354 enum_def: &ast::EnumDef,
355 generics: &ast::Generics,
357 self.buffer.push_str(&format_header("enum ", ident, vis));
359 let enum_snippet = self.snippet(span);
360 let brace_pos = enum_snippet.find_uncommented("{").unwrap();
361 let body_start = span.lo + BytePos(brace_pos as u32 + 1);
362 let generics_str = format_generics(&self.get_context(),
366 self.config.item_brace_style,
367 enum_def.variants.is_empty(),
369 self.block_indent.block_indent(self.config),
370 mk_sp(span.lo, body_start))
372 self.buffer.push_str(&generics_str);
374 self.last_pos = body_start;
376 self.block_indent = self.block_indent.block_indent(self.config);
377 let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
379 Some(ref body_str) => self.buffer.push_str(body_str),
381 if contains_comment(&enum_snippet[brace_pos..]) {
382 self.format_missing_no_indent(span.hi - BytePos(1))
384 self.format_missing(span.hi - BytePos(1))
388 self.block_indent = self.block_indent.block_unindent(self.config);
390 if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
391 self.buffer.push_str(&self.block_indent.to_string(self.config));
393 self.buffer.push_str("}");
394 self.last_pos = span.hi;
397 // Format the body of an enum definition
398 fn format_variant_list(&self,
399 enum_def: &ast::EnumDef,
403 if enum_def.variants.is_empty() {
406 let mut result = String::with_capacity(1024);
408 let indentation = self.block_indent.to_string(self.config);
409 result.push_str(&indentation);
411 let items = itemize_list(self.codemap,
412 enum_def.variants.iter(),
414 |f| if !f.node.attrs.is_empty() {
415 f.node.attrs[0].span.lo
420 |f| self.format_variant(f),
424 let budget = self.config.max_width - self.block_indent.width() - 2;
425 let fmt = ListFormatting {
426 tactic: DefinitiveListTactic::Vertical,
428 trailing_separator: SeparatorTactic::from_bool(self.config.enum_trailing_comma),
429 indent: self.block_indent,
431 ends_with_newline: true,
435 let list = try_opt!(write_list(items, &fmt));
436 result.push_str(&list);
441 // Variant of an enum.
442 fn format_variant(&self, field: &ast::Variant) -> Option<String> {
443 if contains_skip(&field.node.attrs) {
444 let lo = field.node.attrs[0].span.lo;
445 let span = mk_sp(lo, field.span.hi);
446 return Some(self.snippet(span));
449 let indent = self.block_indent;
450 let mut result = try_opt!(field.node
452 .rewrite(&self.get_context(),
453 self.config.max_width - indent.width(),
455 if !result.is_empty() {
457 result.push_str(&indent.to_string(self.config));
460 let context = self.get_context();
461 let variant_body = match field.node.data {
462 ast::VariantData::Tuple(..) |
463 ast::VariantData::Struct(..) => {
464 // FIXME: Should limit the width, as we have a trailing comma
465 format_struct(&context,
468 &ast::Visibility::Inherited,
473 Some(self.config.struct_variant_width))
475 ast::VariantData::Unit(..) => {
476 let tag = if let Some(ref expr) = field.node.disr_expr {
477 format!("{} = {}", field.node.name, self.snippet(expr.span))
479 field.node.name.to_string()
483 self.config.max_width,
484 self.config.max_width - indent.width(),
489 if let Some(variant_str) = variant_body {
490 result.push_str(&variant_str);
498 pub fn format_impl(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
499 if let ast::ItemKind::Impl(_, _, ref generics, ref trait_ref, _, ref items) = item.node {
500 let mut result = String::new();
501 // First try to format the ref and type without a split at the 'for'.
502 let mut ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, false));
504 // If there is a line break present in the first result format it again
505 // with a split at the 'for'. Skip this if there is no trait ref and
506 // therefore no 'for'.
507 if ref_and_type.contains('\n') && trait_ref.is_some() {
508 ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset, true));
510 result.push_str(&ref_and_type);
512 let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
513 let where_clause_str = try_opt!(rewrite_where_clause(context,
514 &generics.where_clause,
516 context.config.item_brace_style,
517 context.block_indent,
519 context.config.where_density,
524 if try_opt!(is_impl_single_line(context, &items, &result, &where_clause_str, &item)) {
525 result.push_str(&where_clause_str);
526 if where_clause_str.contains('\n') {
527 let white_space = offset.to_string(context.config);
528 result.push_str(&format!("\n{}{{\n{}}}", &white_space, &white_space));
530 result.push_str(" {}");
535 if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
537 let width = context.block_indent.width() + context.config.tab_spaces - 1;
538 let where_indent = Indent::new(0, width);
539 result.push_str(&where_indent.to_string(context.config));
541 result.push_str(&where_clause_str);
543 match context.config.item_brace_style {
544 BraceStyle::AlwaysNextLine => {
546 result.push_str(&offset.to_string(context.config));
548 BraceStyle::PreferSameLine => result.push(' '),
549 BraceStyle::SameLineWhere => {
550 if !where_clause_str.is_empty() {
552 result.push_str(&offset.to_string(context.config));
561 let snippet = context.snippet(item.span);
562 let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
564 if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
565 let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
566 visitor.block_indent = context.block_indent.block_indent(context.config);
567 visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
570 visitor.visit_impl_item(item);
573 visitor.format_missing(item.span.hi - BytePos(1));
575 let inner_indent_str = visitor.block_indent.to_string(context.config);
576 let outer_indent_str = context.block_indent.to_string(context.config);
579 result.push_str(&inner_indent_str);
580 result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
582 result.push_str(&outer_indent_str);
585 if result.chars().last().unwrap() == '{' {
587 result.push_str(&offset.to_string(context.config));
597 fn is_impl_single_line(context: &RewriteContext,
600 where_clause_str: &str,
603 let snippet = context.snippet(item.span);
604 let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
606 Some(context.config.impl_empty_single_line && items.is_empty() &&
607 result.len() + where_clause_str.len() <= context.config.max_width &&
608 !contains_comment(&snippet[open_pos..]))
611 fn format_impl_ref_and_type(context: &RewriteContext,
616 if let ast::ItemKind::Impl(unsafety, polarity, ref generics, ref trait_ref, ref self_ty, _) =
618 let mut result = String::new();
620 result.push_str(&*format_visibility(&item.vis));
621 result.push_str(format_unsafety(unsafety));
622 result.push_str("impl");
624 let lo = context.codemap.span_after(item.span, "impl");
625 let hi = match *trait_ref {
626 Some(ref tr) => tr.path.span.lo,
627 None => self_ty.span.lo,
629 let generics_str = try_opt!(rewrite_generics(context,
632 context.config.max_width,
633 offset + result.len(),
635 result.push_str(&generics_str);
637 if polarity == ast::ImplPolarity::Negative {
638 result.push_str(" !");
640 if let Some(ref trait_ref) = *trait_ref {
641 if polarity != ast::ImplPolarity::Negative {
642 result.push_str(" ");
644 let budget = try_opt!(context.config.max_width.checked_sub(result.len()));
645 let indent = offset + result.len();
646 result.push_str(&*try_opt!(trait_ref.rewrite(context, budget, indent)));
651 // Add indentation of one additional tab.
652 let width = context.block_indent.width() + context.config.tab_spaces;
653 let for_indent = Indent::new(0, width);
654 result.push_str(&for_indent.to_string(context.config));
656 result.push_str("for");
658 result.push_str(" for");
662 let mut used_space = last_line_width(&result);
663 if generics.where_clause.predicates.is_empty() {
664 // If there is no where clause adapt budget for type formatting to take space and curly
665 // brace into account.
666 match context.config.item_brace_style {
667 BraceStyle::AlwaysNextLine => {}
668 BraceStyle::PreferSameLine => used_space += 2,
669 BraceStyle::SameLineWhere => used_space += 2,
673 // 1 = space before the type.
674 let budget = try_opt!(context.config.max_width.checked_sub(used_space + 1));
675 let indent = offset + result.len() + 1;
676 let self_ty_str = self_ty.rewrite(context, budget, indent);
677 if let Some(self_ty_str) = self_ty_str {
678 result.push_str(" ");
679 result.push_str(&self_ty_str);
683 // Can't fit the self type on what's left of the line, so start a new one.
684 let indent = offset.block_indent(context.config);
685 result.push_str(&format!("\n{}", indent.to_string(context.config)));
686 let budget = try_opt!(context.config.max_width.checked_sub(indent.width()));
687 result.push_str(&*try_opt!(self_ty.rewrite(context, budget, indent)));
694 pub fn format_struct(context: &RewriteContext,
697 vis: &ast::Visibility,
698 struct_def: &ast::VariantData,
699 generics: Option<&ast::Generics>,
702 one_line_width: Option<usize>)
705 ast::VariantData::Unit(..) => Some(format_unit_struct(item_name, ident, vis)),
706 ast::VariantData::Tuple(ref fields, _) => {
707 format_tuple_struct(context,
716 ast::VariantData::Struct(ref fields, _) => {
717 format_struct_struct(context,
730 pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
731 if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
733 let mut result = String::new();
734 let header = format!("{}{}trait {}",
735 format_visibility(&item.vis),
736 format_unsafety(unsafety),
739 result.push_str(&header);
741 let body_lo = context.codemap.span_after(item.span, "{");
743 let generics_str = try_opt!(rewrite_generics(context,
746 context.config.max_width,
747 offset + result.len(),
748 mk_sp(item.span.lo, body_lo)));
749 result.push_str(&generics_str);
751 let trait_bound_str = try_opt!(rewrite_trait_bounds(context,
754 context.config.max_width));
755 // If the trait, generics, and trait bound cannot fit on the same line,
756 // put the trait bounds on an indented new line
757 if offset.width() + last_line_width(&result) + trait_bound_str.len() >
758 context.config.ideal_width {
760 let trait_indent = context.block_indent.block_indent(context.config);
761 result.push_str(&trait_indent.to_string(context.config));
763 result.push_str(&trait_bound_str);
765 let has_body = !trait_items.is_empty();
768 if (context.config.where_density == Density::Compressed &&
769 (!result.contains('\n') ||
770 context.config.fn_args_layout == FnArgLayoutStyle::Block)) ||
771 (context.config.fn_args_layout == FnArgLayoutStyle::Block && result.is_empty()) ||
772 (context.config.where_density == Density::CompressedIfEmpty && !has_body &&
773 !result.contains('\n')) {
779 let where_budget = try_opt!(context.config
781 .checked_sub(last_line_width(&result)));
782 let where_clause_str = try_opt!(rewrite_where_clause(context,
783 &generics.where_clause,
785 context.config.item_brace_style,
786 context.block_indent,
792 // If the where clause cannot fit on the same line,
793 // put the where clause on a new line
794 if !where_clause_str.contains('\n') &&
795 last_line_width(&result) + where_clause_str.len() + offset.width() >
796 context.config.ideal_width {
798 let width = context.block_indent.width() + context.config.tab_spaces - 1;
799 let where_indent = Indent::new(0, width);
800 result.push_str(&where_indent.to_string(context.config));
802 result.push_str(&where_clause_str);
804 match context.config.item_brace_style {
805 BraceStyle::AlwaysNextLine => {
807 result.push_str(&offset.to_string(context.config));
809 BraceStyle::PreferSameLine => result.push(' '),
810 BraceStyle::SameLineWhere => {
811 if !where_clause_str.is_empty() &&
812 (!trait_items.is_empty() || result.contains('\n')) {
814 result.push_str(&offset.to_string(context.config));
822 let snippet = context.snippet(item.span);
823 let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
825 if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
826 let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
827 visitor.block_indent = context.block_indent.block_indent(context.config);
828 visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
830 for item in trait_items {
831 visitor.visit_trait_item(item);
834 visitor.format_missing(item.span.hi - BytePos(1));
836 let inner_indent_str = visitor.block_indent.to_string(context.config);
837 let outer_indent_str = context.block_indent.to_string(context.config);
840 result.push_str(&inner_indent_str);
841 result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
843 result.push_str(&outer_indent_str);
844 } else if result.contains('\n') {
855 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
856 format!("{};", format_header(item_name, ident, vis))
859 fn format_struct_struct(context: &RewriteContext,
862 vis: &ast::Visibility,
863 fields: &[ast::StructField],
864 generics: Option<&ast::Generics>,
867 one_line_width: Option<usize>)
869 let mut result = String::with_capacity(1024);
871 let header_str = format_header(item_name, ident, vis);
872 result.push_str(&header_str);
874 let body_lo = context.codemap.span_after(span, "{");
876 let generics_str = match generics {
878 try_opt!(format_generics(context,
882 context.config.item_brace_style,
885 offset + header_str.len(),
886 mk_sp(span.lo, body_lo)))
889 if context.config.item_brace_style == BraceStyle::AlwaysNextLine && !fields.is_empty() {
890 format!("\n{}{{", context.block_indent.to_string(context.config))
896 result.push_str(&generics_str);
898 // FIXME(#919): properly format empty structs and their comments.
899 if fields.is_empty() {
900 let snippet = context.snippet(mk_sp(body_lo, span.hi - BytePos(1)));
901 if snippet.trim().is_empty() {
903 } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
905 result.push_str(&snippet.trim_right());
907 result.push_str(&offset.to_string(context.config));
909 result.push_str(&snippet);
915 let item_indent = offset.block_indent(context.config);
917 let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 1));
919 let items = itemize_list(context.codemap,
923 // Include attributes and doc comments, if present
924 if !field.attrs.is_empty() {
925 field.attrs[0].span.lo
930 |field| field.ty.span.hi,
931 |field| field.rewrite(context, item_budget, item_indent),
932 context.codemap.span_after(span, "{"),
934 .collect::<Vec<_>>();
936 let budget = context.config.max_width - offset.width() + context.config.tab_spaces - 1;
938 let tactic = match one_line_width {
939 Some(w) => definitive_tactic(&items, ListTactic::LimitedHorizontalVertical(w), budget),
940 None => DefinitiveListTactic::Vertical,
943 let fmt = ListFormatting {
946 trailing_separator: context.config.struct_trailing_comma,
949 ends_with_newline: true,
950 config: context.config,
952 let items_str = try_opt!(write_list(&items, &fmt));
953 if one_line_width.is_some() && !items_str.contains('\n') {
954 Some(format!("{} {} }}", result, items_str))
956 Some(format!("{}\n{}{}\n{}}}",
958 offset.block_indent(context.config).to_string(context.config),
960 offset.to_string(context.config)))
964 fn format_tuple_struct(context: &RewriteContext,
967 vis: &ast::Visibility,
968 fields: &[ast::StructField],
969 generics: Option<&ast::Generics>,
973 let mut result = String::with_capacity(1024);
975 let header_str = format_header(item_name, ident, vis);
976 result.push_str(&header_str);
978 // FIXME(#919): don't lose comments on empty tuple structs.
979 let body_lo = if fields.is_empty() {
985 let where_clause_str = match generics {
987 let generics_str = try_opt!(rewrite_generics(context,
990 context.config.max_width,
991 offset + header_str.len(),
992 mk_sp(span.lo, body_lo)));
993 result.push_str(&generics_str);
995 let where_budget = try_opt!(context.config
997 .checked_sub(last_line_width(&result)));
998 try_opt!(rewrite_where_clause(context,
999 &generics.where_clause,
1001 context.config.item_brace_style,
1002 context.block_indent,
1004 Density::Compressed,
1009 None => "".to_owned(),
1013 let item_indent = context.block_indent + result.len();
1015 let item_budget = try_opt!(context.config.max_width.checked_sub(item_indent.width() + 2));
1017 let items = itemize_list(context.codemap,
1021 // Include attributes and doc comments, if present
1022 if !field.attrs.is_empty() {
1023 field.attrs[0].span.lo
1028 |field| field.ty.span.hi,
1029 |field| field.rewrite(context, item_budget, item_indent),
1030 context.codemap.span_after(span, "("),
1032 let body = try_opt!(format_item_list(items, item_budget, item_indent, context.config));
1034 if context.config.spaces_within_parens && body.len() > 0 {
1038 result.push_str(&body);
1040 if context.config.spaces_within_parens && body.len() > 0 {
1046 if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
1047 (result.contains('\n') ||
1048 context.block_indent.width() + result.len() + where_clause_str.len() + 1 >
1049 context.config.max_width) {
1050 // We need to put the where clause on a new line, but we didn'to_string
1051 // know that earlier, so the where clause will not be indented properly.
1053 result.push_str(&(context.block_indent + (context.config.tab_spaces - 1))
1054 .to_string(context.config));
1056 result.push_str(&where_clause_str);
1061 pub fn rewrite_type_alias(context: &RewriteContext,
1065 generics: &ast::Generics,
1066 vis: &ast::Visibility,
1069 let mut result = String::new();
1071 result.push_str(&format_visibility(vis));
1072 result.push_str("type ");
1073 result.push_str(&ident.to_string());
1075 let generics_indent = indent + result.len();
1076 let generics_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
1077 let generics_width = context.config.max_width - " =".len();
1078 let generics_str = try_opt!(rewrite_generics(context,
1085 result.push_str(&generics_str);
1087 let where_budget = try_opt!(context.config
1089 .checked_sub(last_line_width(&result)));
1090 let where_clause_str = try_opt!(rewrite_where_clause(context,
1091 &generics.where_clause,
1093 context.config.item_brace_style,
1096 context.config.where_density,
1100 result.push_str(&where_clause_str);
1101 result.push_str(" = ");
1103 let line_width = last_line_width(&result);
1104 // This checked_sub may fail as the extra space after '=' is not taken into account
1105 // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
1106 let budget = context.config
1108 .checked_sub(indent.width() + line_width + ";".len())
1110 let type_indent = indent + line_width;
1111 // Try to fit the type on the same line
1112 let ty_str = try_opt!(ty.rewrite(context, budget, type_indent)
1114 // The line was too short, try to put the type on the next line
1116 // Remove the space after '='
1118 let type_indent = indent.block_indent(context.config);
1120 result.push_str(&type_indent.to_string(context.config));
1121 let budget = try_opt!(context.config
1123 .checked_sub(type_indent.width() + ";".len()));
1124 ty.rewrite(context, budget, type_indent)
1126 result.push_str(&ty_str);
1127 result.push_str(";");
1131 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1132 (if config.space_before_type_annotation {
1137 if config.space_after_type_annotation_colon {
1144 impl Rewrite for ast::StructField {
1145 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1146 if contains_skip(&self.attrs) {
1147 let span = context.snippet(mk_sp(self.attrs[0].span.lo, self.span.hi));
1148 return wrap_str(span, context.config.max_width, width, offset);
1151 let name = self.ident;
1152 let vis = format_visibility(&self.vis);
1153 let mut attr_str = try_opt!(self.attrs
1154 .rewrite(context, context.config.max_width - offset.width(), offset));
1155 if !attr_str.is_empty() {
1156 attr_str.push('\n');
1157 attr_str.push_str(&offset.to_string(context.config));
1160 let type_annotation_spacing = type_annotation_spacing(context.config);
1161 let result = match name {
1163 format!("{}{}{}{}:{}",
1167 type_annotation_spacing.0,
1168 type_annotation_spacing.1)
1170 None => format!("{}{}", attr_str, vis),
1173 let last_line_width = last_line_width(&result);
1174 let budget = try_opt!(width.checked_sub(last_line_width));
1175 let rewrite = try_opt!(self.ty.rewrite(context, budget, offset + last_line_width));
1176 Some(result + &rewrite)
1180 pub fn rewrite_static(prefix: &str,
1181 vis: &ast::Visibility,
1184 mutability: ast::Mutability,
1185 expr_opt: Option<&ptr::P<ast::Expr>>,
1186 context: &RewriteContext)
1188 let type_annotation_spacing = type_annotation_spacing(context.config);
1189 let prefix = format!("{}{} {}{}{}:{}",
1190 format_visibility(vis),
1192 format_mutability(mutability),
1194 type_annotation_spacing.0,
1195 type_annotation_spacing.1);
1197 let ty_str = try_opt!(ty.rewrite(context,
1198 context.config.max_width - context.block_indent.width() -
1200 context.block_indent));
1202 if let Some(expr) = expr_opt {
1203 let lhs = format!("{}{} =", prefix, ty_str);
1205 let remaining_width = context.config.max_width - context.block_indent.width() - 1;
1206 rewrite_assign_rhs(context, lhs, expr, remaining_width, context.block_indent)
1209 let lhs = format!("{}{};", prefix, ty_str);
1214 pub fn rewrite_associated_type(ident: ast::Ident,
1215 ty_opt: Option<&ptr::P<ast::Ty>>,
1216 ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1217 context: &RewriteContext,
1220 let prefix = format!("type {}", ident);
1222 let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
1223 let bounds: &[_] = ty_param_bounds;
1224 let bound_str = try_opt!(bounds.iter()
1225 .map(|ty_bound| ty_bound.rewrite(context, context.config.max_width, indent))
1226 .intersperse(Some(" + ".to_string()))
1227 .collect::<Option<String>>());
1228 if bounds.len() > 0 {
1229 format!(": {}", bound_str)
1237 if let Some(ty) = ty_opt {
1238 let ty_str = try_opt!(ty.rewrite(context,
1239 context.config.max_width - context.block_indent.width() -
1242 context.block_indent));
1243 Some(format!("{} = {};", prefix, ty_str))
1245 Some(format!("{}{};", prefix, type_bounds_str))
1249 impl Rewrite for ast::FunctionRetTy {
1250 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1252 ast::FunctionRetTy::Default(_) => Some(String::new()),
1253 ast::FunctionRetTy::Ty(ref ty) => {
1254 let inner_width = try_opt!(width.checked_sub(3));
1255 ty.rewrite(context, inner_width, offset + 3).map(|r| format!("-> {}", r))
1261 impl Rewrite for ast::Arg {
1262 fn rewrite(&self, context: &RewriteContext, width: usize, offset: Indent) -> Option<String> {
1263 if is_named_arg(self) {
1264 let mut result = try_opt!(self.pat.rewrite(context, width, offset));
1266 if self.ty.node != ast::TyKind::Infer {
1267 if context.config.space_before_type_annotation {
1268 result.push_str(" ");
1270 result.push_str(":");
1271 if context.config.space_after_type_annotation_colon {
1272 result.push_str(" ");
1274 let max_width = try_opt!(width.checked_sub(result.len()));
1275 let ty_str = try_opt!(self.ty.rewrite(context, max_width, offset + result.len()));
1276 result.push_str(&ty_str);
1281 self.ty.rewrite(context, width, offset)
1286 fn rewrite_explicit_self(explicit_self: &ast::ExplicitSelf,
1288 context: &RewriteContext)
1290 match explicit_self.node {
1291 ast::SelfKind::Region(lt, m) => {
1292 let mut_str = format_mutability(m);
1296 try_opt!(l.rewrite(context, usize::max_value(), Indent::empty()));
1297 Some(format!("&{} {}self", lifetime_str, mut_str))
1299 None => Some(format!("&{}self", mut_str)),
1302 ast::SelfKind::Explicit(ref ty, _) => {
1303 assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1305 let mutability = explicit_self_mutability(&args[0]);
1306 let type_str = try_opt!(ty.rewrite(context, usize::max_value(), Indent::empty()));
1308 Some(format!("{}self: {}", format_mutability(mutability), type_str))
1310 ast::SelfKind::Value(_) => {
1311 assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1313 let mutability = explicit_self_mutability(&args[0]);
1315 Some(format!("{}self", format_mutability(mutability)))
1320 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1321 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1322 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1323 if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1330 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1331 if is_named_arg(arg) {
1338 pub fn span_hi_for_arg(arg: &ast::Arg) -> BytePos {
1340 ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
1341 _ => arg.ty.span.hi,
1345 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1346 if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1347 ident.node != symbol::keywords::Invalid.ident()
1353 fn span_for_return(ret: &ast::FunctionRetTy) -> Span {
1355 ast::FunctionRetTy::Default(ref span) => span.clone(),
1356 ast::FunctionRetTy::Ty(ref ty) => ty.span,
1360 fn span_for_ty_param(ty: &ast::TyParam) -> Span {
1361 // Note that ty.span is the span for ty.ident, not the whole item.
1362 let lo = ty.span.lo;
1363 if let Some(ref def) = ty.default {
1364 return mk_sp(lo, def.span.hi);
1366 if ty.bounds.is_empty() {
1369 let hi = match ty.bounds[ty.bounds.len() - 1] {
1370 ast::TyParamBound::TraitTyParamBound(ref ptr, _) => ptr.span.hi,
1371 ast::TyParamBound::RegionTyParamBound(ref l) => l.span.hi,
1376 fn span_for_where_pred(pred: &ast::WherePredicate) -> Span {
1378 ast::WherePredicate::BoundPredicate(ref p) => p.span,
1379 ast::WherePredicate::RegionPredicate(ref p) => p.span,
1380 ast::WherePredicate::EqPredicate(ref p) => p.span,
1384 // Return type is (result, force_new_line_for_brace)
1385 fn rewrite_fn_base(context: &RewriteContext,
1389 generics: &ast::Generics,
1390 unsafety: ast::Unsafety,
1391 constness: ast::Constness,
1392 defaultness: ast::Defaultness,
1394 vis: &ast::Visibility,
1396 newline_brace: bool,
1398 -> Option<(String, bool)> {
1399 let mut force_new_line_for_brace = false;
1401 let where_clause = &generics.where_clause;
1403 let mut result = String::with_capacity(1024);
1404 // Vis unsafety abi.
1405 result.push_str(&*format_visibility(vis));
1407 if let ast::Defaultness::Default = defaultness {
1408 result.push_str("default ");
1411 if let ast::Constness::Const = constness {
1412 result.push_str("const ");
1415 result.push_str(::utils::format_unsafety(unsafety));
1417 if abi != abi::Abi::Rust {
1418 result.push_str(&::utils::format_abi(abi, context.config.force_explicit_abi));
1422 result.push_str("fn ");
1423 result.push_str(&ident.to_string());
1426 let generics_indent = indent + result.len();
1427 let generics_span = mk_sp(span.lo, span_for_return(&fd.output).lo);
1428 let generics_str = try_opt!(rewrite_generics(context,
1431 context.config.max_width,
1434 result.push_str(&generics_str);
1436 // Note that if the width and indent really matter, we'll re-layout the
1437 // return type later anyway.
1438 let ret_str = try_opt!(fd.output
1439 .rewrite(&context, context.config.max_width - indent.width(), indent));
1441 let multi_line_ret_str = ret_str.contains('\n');
1442 let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1445 let (mut one_line_budget, mut multi_line_budget, mut arg_indent) =
1446 try_opt!(compute_budgets_for_args(context, &result, indent, ret_str_len, newline_brace));
1448 if context.config.fn_args_layout == FnArgLayoutStyle::Block ||
1449 context.config.fn_args_layout == FnArgLayoutStyle::BlockAlways {
1450 arg_indent = indent.block_indent(context.config);
1451 multi_line_budget = context.config.max_width - arg_indent.width();
1454 debug!("rewrite_fn: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1459 // Check if vertical layout was forced.
1460 if one_line_budget == 0 {
1461 if context.config.fn_args_paren_newline {
1463 result.push_str(&arg_indent.to_string(context.config));
1464 arg_indent = arg_indent + 1; // extra space for `(`
1466 if context.config.spaces_within_parens && fd.inputs.len() > 0 {
1470 result.push_str("(\n");
1471 result.push_str(&arg_indent.to_string(context.config));
1475 if context.config.spaces_within_parens && fd.inputs.len() > 0 {
1480 if multi_line_ret_str {
1481 one_line_budget = 0;
1484 // A conservative estimation, to goal is to be over all parens in generics
1485 let args_start = generics.ty_params
1487 .map_or(span.lo, |tp| end_typaram(tp));
1488 let args_span = mk_sp(context.codemap.span_after(mk_sp(args_start, span.hi), "("),
1489 span_for_return(&fd.output).lo);
1490 let arg_str = try_opt!(rewrite_args(context,
1492 fd.get_self().as_ref(),
1500 let multi_line_arg_str = arg_str.contains('\n');
1502 let put_args_in_block = match context.config.fn_args_layout {
1503 FnArgLayoutStyle::Block => multi_line_arg_str,
1504 FnArgLayoutStyle::BlockAlways => true,
1506 } && !fd.inputs.is_empty();
1508 if put_args_in_block {
1509 arg_indent = indent.block_indent(context.config);
1511 result.push_str(&arg_indent.to_string(context.config));
1512 result.push_str(&arg_str);
1514 result.push_str(&indent.to_string(context.config));
1517 result.push_str(&arg_str);
1518 if context.config.spaces_within_parens && fd.inputs.len() > 0 {
1525 if !ret_str.is_empty() {
1526 let ret_should_indent = match context.config.fn_args_layout {
1527 // If our args are block layout then we surely must have space.
1528 FnArgLayoutStyle::Block if put_args_in_block => false,
1529 FnArgLayoutStyle::BlockAlways => false,
1531 // If we've already gone multi-line, or the return type would push over the max
1532 // width, then put the return type on a new line. With the +1 for the signature
1533 // length an additional space between the closing parenthesis of the argument and
1534 // the arrow '->' is considered.
1535 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1537 // If there is no where clause, take into account the space after the return type
1539 if where_clause.predicates.is_empty() {
1543 let overlong_sig = sig_length > context.config.max_width;
1545 result.contains('\n') || multi_line_ret_str || overlong_sig
1548 let ret_indent = if ret_should_indent {
1549 let indent = match context.config.fn_return_indent {
1550 ReturnIndent::WithWhereClause => indent + 4,
1551 // Aligning with non-existent args looks silly.
1552 _ if arg_str.is_empty() => {
1553 force_new_line_for_brace = true;
1556 // FIXME: we might want to check that using the arg indent
1557 // doesn't blow our budget, and if it does, then fallback to
1558 // the where clause indent.
1563 result.push_str(&indent.to_string(context.config));
1567 Indent::new(indent.width(), result.len())
1570 if multi_line_ret_str {
1571 // Now that we know the proper indent and width, we need to
1572 // re-layout the return type.
1573 let budget = try_opt!(context.config.max_width.checked_sub(ret_indent.width()));
1574 let ret_str = try_opt!(fd.output.rewrite(context, budget, ret_indent));
1575 result.push_str(&ret_str);
1577 result.push_str(&ret_str);
1580 // Comment between return type and the end of the decl.
1581 let snippet_lo = fd.output.span().hi;
1582 if where_clause.predicates.is_empty() {
1583 let snippet_hi = span.hi;
1584 let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1585 let snippet = snippet.trim();
1586 if !snippet.is_empty() {
1588 result.push_str(snippet);
1591 // FIXME it would be nice to catch comments between the return type
1592 // and the where clause, but we don't have a span for the where
1597 let should_compress_where = match context.config.where_density {
1598 Density::Compressed => !result.contains('\n') || put_args_in_block,
1599 Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
1601 } || (put_args_in_block && ret_str.is_empty());
1603 let where_density = if should_compress_where {
1610 let where_budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
1611 let where_clause_str = try_opt!(rewrite_where_clause(context,
1614 context.config.fn_brace_style,
1622 if last_line_width(&result) + where_clause_str.len() > context.config.max_width &&
1623 !where_clause_str.contains('\n') {
1627 result.push_str(&where_clause_str);
1629 Some((result, force_new_line_for_brace))
1632 fn rewrite_args(context: &RewriteContext,
1634 explicit_self: Option<&ast::ExplicitSelf>,
1635 one_line_budget: usize,
1636 multi_line_budget: usize,
1642 let mut arg_item_strs = try_opt!(args.iter()
1643 .map(|arg| arg.rewrite(&context, multi_line_budget, arg_indent))
1644 .collect::<Option<Vec<_>>>());
1646 // Account for sugary self.
1647 // FIXME: the comment for the self argument is dropped. This is blocked
1648 // on rust issue #27522.
1650 explicit_self.and_then(|explicit_self| rewrite_explicit_self(explicit_self, args, context))
1651 .map_or(1, |self_str| {
1652 arg_item_strs[0] = self_str;
1656 // Comments between args.
1657 let mut arg_items = Vec::new();
1659 arg_items.push(ListItem::from_str(""));
1662 // FIXME(#21): if there are no args, there might still be a comment, but
1663 // without spans for the comment or parens, there is no chance of
1664 // getting it right. You also don't get to put a comment on self, unless
1666 if args.len() >= min_args || variadic {
1667 let comment_span_start = if min_args == 2 {
1668 let second_arg_start = if arg_has_pattern(&args[1]) {
1673 let reduced_span = mk_sp(span.lo, second_arg_start);
1675 context.codemap.span_after_last(reduced_span, ",")
1680 enum ArgumentKind<'a> {
1681 Regular(&'a ast::Arg),
1685 let variadic_arg = if variadic {
1686 let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
1687 let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
1688 Some(ArgumentKind::Variadic(variadic_start))
1693 let more_items = itemize_list(context.codemap,
1694 args[min_args - 1..]
1696 .map(ArgumentKind::Regular)
1697 .chain(variadic_arg),
1700 ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
1701 ArgumentKind::Variadic(start) => start,
1704 ArgumentKind::Regular(arg) => arg.ty.span.hi,
1705 ArgumentKind::Variadic(start) => start + BytePos(3),
1708 ArgumentKind::Regular(..) => None,
1709 ArgumentKind::Variadic(..) => Some("...".to_owned()),
1714 arg_items.extend(more_items);
1717 for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
1718 item.item = Some(arg);
1721 let indent = match context.config.fn_arg_indent {
1722 BlockIndentStyle::Inherit => indent,
1723 BlockIndentStyle::Tabbed => indent.block_indent(context.config),
1724 BlockIndentStyle::Visual => arg_indent,
1727 let tactic = definitive_tactic(&arg_items,
1728 context.config.fn_args_density.to_list_tactic(),
1730 let budget = match tactic {
1731 DefinitiveListTactic::Horizontal => one_line_budget,
1732 _ => multi_line_budget,
1735 debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
1737 let end_with_newline = match context.config.fn_args_layout {
1738 FnArgLayoutStyle::Block |
1739 FnArgLayoutStyle::BlockAlways => true,
1743 let fmt = ListFormatting {
1746 trailing_separator: SeparatorTactic::Never,
1749 ends_with_newline: end_with_newline,
1750 config: context.config,
1753 write_list(&arg_items, &fmt)
1756 fn arg_has_pattern(arg: &ast::Arg) -> bool {
1757 if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1758 ident.node != symbol::keywords::Invalid.ident()
1764 fn compute_budgets_for_args(context: &RewriteContext,
1768 newline_brace: bool)
1769 -> Option<((usize, usize, Indent))> {
1770 debug!("compute_budgets_for_args {} {:?}, {}, {}",
1775 // Try keeping everything on the same line.
1776 if !result.contains('\n') {
1777 // 3 = `() `, space is before ret_string.
1778 let mut used_space = indent.width() + result.len() + ret_str_len + 3;
1782 let one_line_budget = context.config.max_width.checked_sub(used_space).unwrap_or(0);
1784 if one_line_budget > 0 {
1786 let multi_line_budget =
1787 try_opt!(context.config.max_width.checked_sub(indent.width() + result.len() + 4));
1789 return Some((one_line_budget, multi_line_budget, indent + result.len() + 1));
1793 // Didn't work. we must force vertical layout and put args on a newline.
1794 let new_indent = indent.block_indent(context.config);
1795 let used_space = new_indent.width() + 4; // Account for `(` and `)` and possibly ` {`.
1796 let max_space = context.config.max_width;
1797 if used_space <= max_space {
1798 Some((0, max_space - used_space, new_indent))
1800 // Whoops! bankrupt.
1805 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> bool {
1806 match config.fn_brace_style {
1807 BraceStyle::AlwaysNextLine => true,
1808 BraceStyle::SameLineWhere if !where_clause.predicates.is_empty() => true,
1813 fn rewrite_generics(context: &RewriteContext,
1814 generics: &ast::Generics,
1817 generics_offset: Indent,
1820 // FIXME: convert bounds to where clauses where they get too big or if
1821 // there is a where clause at all.
1822 let lifetimes: &[_] = &generics.lifetimes;
1823 let tys: &[_] = &generics.ty_params;
1824 if lifetimes.is_empty() && tys.is_empty() {
1825 return Some(String::new());
1828 let offset = match context.config.generics_indent {
1829 BlockIndentStyle::Inherit => offset,
1830 BlockIndentStyle::Tabbed => offset.block_indent(context.config),
1832 BlockIndentStyle::Visual => generics_offset + 1,
1835 let h_budget = try_opt!(width.checked_sub(generics_offset.width() + 2));
1836 // FIXME: might need to insert a newline if the generics are really long.
1838 // Strings for the generics.
1839 let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, h_budget, offset));
1840 let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, h_budget, offset));
1842 // Extract comments between generics.
1843 let lt_spans = lifetimes.iter().map(|l| {
1844 let hi = if l.bounds.is_empty() {
1847 l.bounds[l.bounds.len() - 1].span.hi
1849 mk_sp(l.lifetime.span.lo, hi)
1851 let ty_spans = tys.iter().map(span_for_ty_param);
1853 let items = itemize_list(context.codemap,
1854 lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
1858 // FIXME: don't clone
1859 |&(_, ref str)| str.clone(),
1860 context.codemap.span_after(span, "<"),
1862 let list_str = try_opt!(format_item_list(items, h_budget, offset, context.config));
1864 Some(if context.config.spaces_within_angle_brackets {
1865 format!("< {} >", list_str)
1867 format!("<{}>", list_str)
1871 fn rewrite_trait_bounds(context: &RewriteContext,
1872 type_param_bounds: &ast::TyParamBounds,
1876 let bounds: &[_] = type_param_bounds;
1878 if bounds.is_empty() {
1879 return Some(String::new());
1882 let bound_str = try_opt!(bounds.iter()
1883 .map(|ty_bound| ty_bound.rewrite(&context, width, indent))
1884 .intersperse(Some(" + ".to_string()))
1885 .collect::<Option<String>>());
1887 let mut result = String::new();
1888 result.push_str(": ");
1889 result.push_str(&bound_str);
1893 fn rewrite_where_clause(context: &RewriteContext,
1894 where_clause: &ast::WhereClause,
1896 brace_style: BraceStyle,
1901 allow_trailing_comma: bool,
1902 span_end: Option<BytePos>)
1904 if where_clause.predicates.is_empty() {
1905 return Some(String::new());
1908 let extra_indent = match context.config.where_indent {
1909 BlockIndentStyle::Inherit => Indent::empty(),
1910 BlockIndentStyle::Tabbed | BlockIndentStyle::Visual => Indent::new(config.tab_spaces, 0),
1913 let offset = match context.config.where_pred_indent {
1914 BlockIndentStyle::Inherit => indent + extra_indent,
1915 BlockIndentStyle::Tabbed => indent + extra_indent.block_indent(config),
1916 // 6 = "where ".len()
1917 BlockIndentStyle::Visual => indent + extra_indent + 6,
1919 // FIXME: if where_pred_indent != Visual, then the budgets below might
1920 // be out by a char or two.
1922 let budget = context.config.max_width - offset.width();
1923 let span_start = span_for_where_pred(&where_clause.predicates[0]).lo;
1924 // If we don't have the start of the next span, then use the end of the
1925 // predicates, but that means we miss comments.
1926 let len = where_clause.predicates.len();
1927 let end_of_preds = span_for_where_pred(&where_clause.predicates[len - 1]).hi;
1928 let span_end = span_end.unwrap_or(end_of_preds);
1929 let items = itemize_list(context.codemap,
1930 where_clause.predicates.iter(),
1932 |pred| span_for_where_pred(pred).lo,
1933 |pred| span_for_where_pred(pred).hi,
1934 |pred| pred.rewrite(context, budget, offset),
1937 let item_vec = items.collect::<Vec<_>>();
1938 // FIXME: we don't need to collect here if the where_layout isn't
1939 // HorizontalVertical.
1940 let tactic = definitive_tactic(&item_vec, context.config.where_layout, budget);
1941 let use_trailing_comma = allow_trailing_comma && context.config.where_trailing_comma;
1943 let fmt = ListFormatting {
1946 trailing_separator: SeparatorTactic::from_bool(use_trailing_comma),
1949 ends_with_newline: true,
1950 config: context.config,
1952 let preds_str = try_opt!(write_list(&item_vec, &fmt));
1954 let end_length = if terminator == "{" {
1955 // If the brace is on the next line we don't need to count it otherwise it needs two
1958 BraceStyle::AlwaysNextLine |
1959 BraceStyle::SameLineWhere => 0,
1960 BraceStyle::PreferSameLine => 2,
1962 } else if terminator == "=" {
1967 if density == Density::Tall || preds_str.contains('\n') ||
1968 indent.width() + " where ".len() + preds_str.len() + end_length > width {
1969 Some(format!("\n{}where {}",
1970 (indent + extra_indent).to_string(context.config),
1973 Some(format!(" where {}", preds_str))
1977 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
1978 format!("{}{}{}", format_visibility(vis), item_name, ident)
1981 fn format_generics(context: &RewriteContext,
1982 generics: &ast::Generics,
1985 brace_style: BraceStyle,
1986 force_same_line_brace: bool,
1988 generics_offset: Indent,
1991 let mut result = try_opt!(rewrite_generics(context,
1994 context.config.max_width,
1998 if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
1999 let budget = try_opt!(context.config.max_width.checked_sub(last_line_width(&result)));
2000 let where_clause_str = try_opt!(rewrite_where_clause(context,
2001 &generics.where_clause,
2004 context.block_indent,
2010 result.push_str(&where_clause_str);
2011 if !force_same_line_brace &&
2012 (brace_style == BraceStyle::SameLineWhere || brace_style == BraceStyle::AlwaysNextLine) {
2014 result.push_str(&context.block_indent.to_string(context.config));
2018 result.push_str(opener);
2020 if !force_same_line_brace && brace_style == BraceStyle::AlwaysNextLine {
2022 result.push_str(&context.block_indent.to_string(context.config));
2026 result.push_str(opener);