]> git.lizzy.rs Git - rust.git/blob - src/items.rs
9dd1972670a561b43af60af2c92ff3e06b4e5b1f
[rust.git] / src / items.rs
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.
4 //
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.
10
11 // Formatting top-level items - functions, structs, enums, traits, impls.
12
13 use std::cmp::min;
14
15 use syntax::{abi, ast, ptr, symbol};
16 use syntax::ast::ImplItem;
17 use syntax::codemap::{BytePos, Span};
18
19 use {Indent, Shape, Spanned};
20 use codemap::{LineRangeUtils, SpanUtils};
21 use comment::{combine_strs_with_missing_comments, contains_comment, recover_comment_removed,
22               rewrite_comment, FindUncommented};
23 use config::{BraceStyle, Config, Density, IndentStyle, ReturnIndent, Style};
24 use expr::{format_expr, is_empty_block, is_simple_block_stmt, rewrite_assign_rhs,
25            rewrite_call_inner, ExprType};
26 use lists::{definitive_tactic, itemize_list, write_list, DefinitiveListTactic, ListFormatting,
27             ListItem, ListTactic, Separator, SeparatorPlace, SeparatorTactic};
28 use rewrite::{Rewrite, RewriteContext};
29 use types::join_bounds;
30 use utils::{colon_spaces, contains_skip, end_typaram, first_line_width, format_abi,
31             format_constness, format_defaultness, format_mutability, format_unsafety,
32             format_visibility, is_attributes_extendable, last_line_contains_single_line_comment,
33             last_line_used_width, last_line_width, mk_sp, semicolon_for_expr, stmt_expr,
34             trim_newlines, trimmed_last_line_width, wrap_str};
35 use vertical::rewrite_with_alignment;
36 use visitor::FmtVisitor;
37
38 fn type_annotation_separator(config: &Config) -> &str {
39     colon_spaces(
40         config.space_before_type_annotation(),
41         config.space_after_type_annotation_colon(),
42     )
43 }
44
45 // Statements of the form
46 // let pat: ty = init;
47 impl Rewrite for ast::Local {
48     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
49         debug!(
50             "Local::rewrite {:?} {} {:?}",
51             self,
52             shape.width,
53             shape.indent
54         );
55
56         skip_out_of_file_lines_range!(context, self.span);
57
58         let mut result = "let ".to_owned();
59
60         // 4 = "let ".len()
61         let pat_shape = try_opt!(shape.offset_left(4));
62         // 1 = ;
63         let pat_shape = try_opt!(pat_shape.sub_width(1));
64         let pat_str = try_opt!(self.pat.rewrite(&context, pat_shape));
65         result.push_str(&pat_str);
66
67         // String that is placed within the assignment pattern and expression.
68         let infix = {
69             let mut infix = String::new();
70
71             if let Some(ref ty) = self.ty {
72                 let separator = type_annotation_separator(context.config);
73                 let indent = shape.indent + last_line_width(&result) + separator.len();
74                 // 1 = ;
75                 let budget = try_opt!(shape.width.checked_sub(indent.width() + 1));
76                 let rewrite = try_opt!(ty.rewrite(context, Shape::legacy(budget, indent)));
77
78                 infix.push_str(separator);
79                 infix.push_str(&rewrite);
80             }
81
82             if self.init.is_some() {
83                 infix.push_str(" =");
84             }
85
86             infix
87         };
88
89         result.push_str(&infix);
90
91         if let Some(ref ex) = self.init {
92             // 1 = trailing semicolon;
93             let nested_shape = try_opt!(shape.sub_width(1));
94
95             result = try_opt!(rewrite_assign_rhs(&context, result, ex, nested_shape));
96         }
97
98         result.push(';');
99         Some(result)
100     }
101 }
102
103 // TODO convert to using rewrite style rather than visitor
104 // TODO format modules in this style
105 #[allow(dead_code)]
106 struct Item<'a> {
107     keyword: &'static str,
108     abi: String,
109     vis: Option<&'a ast::Visibility>,
110     body: Vec<BodyElement<'a>>,
111     span: Span,
112 }
113
114 impl<'a> Item<'a> {
115     fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
116         let abi = if fm.abi == abi::Abi::C && !config.force_explicit_abi() {
117             "extern".into()
118         } else {
119             format!("extern {}", fm.abi)
120         };
121         Item {
122             keyword: "",
123             abi: abi,
124             vis: None,
125             body: fm.items
126                 .iter()
127                 .map(|i| BodyElement::ForeignItem(i))
128                 .collect(),
129             span: span,
130         }
131     }
132 }
133
134 enum BodyElement<'a> {
135     // Stmt(&'a ast::Stmt),
136     // Field(&'a ast::Field),
137     // Variant(&'a ast::Variant),
138     // Item(&'a ast::Item),
139     ForeignItem(&'a ast::ForeignItem),
140 }
141
142 impl<'a> FmtVisitor<'a> {
143     fn format_item(&mut self, item: Item) {
144         self.buffer.push_str(&item.abi);
145         self.buffer.push_str(" ");
146
147         let snippet = self.snippet(item.span);
148         let brace_pos = snippet.find_uncommented("{").unwrap();
149
150         self.buffer.push_str("{");
151         if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
152             // FIXME: this skips comments between the extern keyword and the opening
153             // brace.
154             self.last_pos = item.span.lo + BytePos(brace_pos as u32 + 1);
155             self.block_indent = self.block_indent.block_indent(self.config);
156
157             if item.body.is_empty() {
158                 self.format_missing_no_indent(item.span.hi - BytePos(1));
159                 self.block_indent = self.block_indent.block_unindent(self.config);
160
161                 self.buffer
162                     .push_str(&self.block_indent.to_string(self.config));
163             } else {
164                 for item in &item.body {
165                     self.format_body_element(item);
166                 }
167
168                 self.block_indent = self.block_indent.block_unindent(self.config);
169                 self.format_missing_with_indent(item.span.hi - BytePos(1));
170             }
171         }
172
173         self.buffer.push_str("}");
174         self.last_pos = item.span.hi;
175     }
176
177     fn format_body_element(&mut self, element: &BodyElement) {
178         match *element {
179             BodyElement::ForeignItem(ref item) => self.format_foreign_item(item),
180         }
181     }
182
183     pub fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
184         let item = Item::from_foreign_mod(fm, span, self.config);
185         self.format_item(item);
186     }
187
188
189     fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
190         let shape = Shape::indented(self.block_indent, self.config);
191         let rewrite = item.rewrite(&self.get_context(), shape);
192         self.push_rewrite(item.span(), rewrite);
193         self.last_pos = item.span.hi;
194     }
195
196     pub fn rewrite_fn(
197         &mut self,
198         indent: Indent,
199         ident: ast::Ident,
200         fd: &ast::FnDecl,
201         generics: &ast::Generics,
202         unsafety: ast::Unsafety,
203         constness: ast::Constness,
204         defaultness: ast::Defaultness,
205         abi: abi::Abi,
206         vis: &ast::Visibility,
207         span: Span,
208         block: &ast::Block,
209     ) -> Option<String> {
210         let context = self.get_context();
211
212         let block_snippet = self.snippet(mk_sp(block.span.lo, block.span.hi));
213         let has_body = !block_snippet[1..block_snippet.len() - 1].trim().is_empty() ||
214             !context.config.fn_empty_single_line();
215         let mut newline_brace = newline_for_brace(self.config, &generics.where_clause, has_body);
216
217         let (mut result, force_newline_brace) = try_opt!(rewrite_fn_base(
218             &context,
219             indent,
220             ident,
221             fd,
222             generics,
223             unsafety,
224             constness,
225             defaultness,
226             abi,
227             vis,
228             span,
229             newline_brace,
230             has_body,
231             true,
232         ));
233
234         if force_newline_brace {
235             newline_brace = true;
236         } else if self.config.fn_brace_style() != BraceStyle::AlwaysNextLine &&
237             !result.contains('\n')
238         {
239             newline_brace = false;
240         }
241
242         // Prepare for the function body by possibly adding a newline and
243         // indent.
244         // FIXME we'll miss anything between the end of the signature and the
245         // start of the body, but we need more spans from the compiler to solve
246         // this.
247         if newline_brace {
248             result.push('\n');
249             result.push_str(&indent.to_string(self.config));
250         } else {
251             result.push(' ');
252         }
253
254         self.single_line_fn(&result, block).or_else(|| Some(result))
255     }
256
257     pub fn rewrite_required_fn(
258         &mut self,
259         indent: Indent,
260         ident: ast::Ident,
261         sig: &ast::MethodSig,
262         span: Span,
263     ) -> Option<String> {
264         // Drop semicolon or it will be interpreted as comment.
265         let span = mk_sp(span.lo, span.hi - BytePos(1));
266         let context = self.get_context();
267
268         let (mut result, _) = try_opt!(rewrite_fn_base(
269             &context,
270             indent,
271             ident,
272             &sig.decl,
273             &sig.generics,
274             sig.unsafety,
275             sig.constness.node,
276             ast::Defaultness::Final,
277             sig.abi,
278             &ast::Visibility::Inherited,
279             span,
280             false,
281             false,
282             false,
283         ));
284
285         // Re-attach semicolon
286         result.push(';');
287
288         Some(result)
289     }
290
291     fn single_line_fn(&self, fn_str: &str, block: &ast::Block) -> Option<String> {
292         if fn_str.contains('\n') {
293             return None;
294         }
295
296         let codemap = self.get_context().codemap;
297
298         if self.config.fn_empty_single_line() && is_empty_block(block, codemap) &&
299             self.block_indent.width() + fn_str.len() + 2 <= self.config.max_width()
300         {
301             return Some(format!("{}{{}}", fn_str));
302         }
303
304         if self.config.fn_single_line() && is_simple_block_stmt(block, codemap) {
305             let rewrite = {
306                 if let Some(ref stmt) = block.stmts.first() {
307                     match stmt_expr(stmt) {
308                         Some(e) => {
309                             let suffix = if semicolon_for_expr(&self.get_context(), e) {
310                                 ";"
311                             } else {
312                                 ""
313                             };
314
315                             format_expr(
316                                 &e,
317                                 ExprType::Statement,
318                                 &self.get_context(),
319                                 Shape::indented(self.block_indent, self.config),
320                             ).map(|s| s + suffix)
321                                 .or_else(|| Some(self.snippet(e.span)))
322                         }
323                         None => stmt.rewrite(
324                             &self.get_context(),
325                             Shape::indented(self.block_indent, self.config),
326                         ),
327                     }
328                 } else {
329                     None
330                 }
331             };
332
333             if let Some(res) = rewrite {
334                 let width = self.block_indent.width() + fn_str.len() + res.len() + 4;
335                 if !res.contains('\n') && width <= self.config.max_width() {
336                     return Some(format!("{}{{ {} }}", fn_str, res));
337                 }
338             }
339         }
340
341         None
342     }
343
344     pub fn visit_enum(
345         &mut self,
346         ident: ast::Ident,
347         vis: &ast::Visibility,
348         enum_def: &ast::EnumDef,
349         generics: &ast::Generics,
350         span: Span,
351     ) {
352         let enum_header = format_header("enum ", ident, vis);
353         self.buffer.push_str(&enum_header);
354
355         let enum_snippet = self.snippet(span);
356         let brace_pos = enum_snippet.find_uncommented("{").unwrap();
357         let body_start = span.lo + BytePos(brace_pos as u32 + 1);
358         let generics_str = format_generics(
359             &self.get_context(),
360             generics,
361             "{",
362             "{",
363             self.config.item_brace_style(),
364             enum_def.variants.is_empty(),
365             self.block_indent,
366             mk_sp(span.lo, body_start),
367             last_line_width(&enum_header),
368         ).unwrap();
369         self.buffer.push_str(&generics_str);
370
371         self.last_pos = body_start;
372
373         self.block_indent = self.block_indent.block_indent(self.config);
374         let variant_list = self.format_variant_list(enum_def, body_start, span.hi - BytePos(1));
375         match variant_list {
376             Some(ref body_str) => self.buffer.push_str(body_str),
377             None => if contains_comment(&enum_snippet[brace_pos..]) {
378                 self.format_missing_no_indent(span.hi - BytePos(1))
379             } else {
380                 self.format_missing(span.hi - BytePos(1))
381             },
382         }
383         self.block_indent = self.block_indent.block_unindent(self.config);
384
385         if variant_list.is_some() || contains_comment(&enum_snippet[brace_pos..]) {
386             self.buffer
387                 .push_str(&self.block_indent.to_string(self.config));
388         }
389         self.buffer.push_str("}");
390         self.last_pos = span.hi;
391     }
392
393     // Format the body of an enum definition
394     fn format_variant_list(
395         &self,
396         enum_def: &ast::EnumDef,
397         body_lo: BytePos,
398         body_hi: BytePos,
399     ) -> Option<String> {
400         if enum_def.variants.is_empty() {
401             return None;
402         }
403         let mut result = String::with_capacity(1024);
404         result.push('\n');
405         let indentation = self.block_indent.to_string(self.config);
406         result.push_str(&indentation);
407
408         let items = itemize_list(
409             self.codemap,
410             enum_def.variants.iter(),
411             "}",
412             |f| if !f.node.attrs.is_empty() {
413                 f.node.attrs[0].span.lo
414             } else {
415                 f.span.lo
416             },
417             |f| f.span.hi,
418             |f| self.format_variant(f),
419             body_lo,
420             body_hi,
421             false,
422         );
423
424         let shape = Shape::indented(self.block_indent, self.config)
425             .sub_width(2)
426             .unwrap();
427         let fmt = ListFormatting {
428             tactic: DefinitiveListTactic::Vertical,
429             separator: ",",
430             trailing_separator: self.config.trailing_comma(),
431             separator_place: SeparatorPlace::Back,
432             shape: shape,
433             ends_with_newline: true,
434             preserve_newline: true,
435             config: self.config,
436         };
437
438         let list = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
439         result.push_str(&list);
440         result.push('\n');
441         Some(result)
442     }
443
444     // Variant of an enum.
445     fn format_variant(&self, field: &ast::Variant) -> Option<String> {
446         if contains_skip(&field.node.attrs) {
447             let lo = field.node.attrs[0].span.lo;
448             let span = mk_sp(lo, field.span.hi);
449             return Some(self.snippet(span));
450         }
451
452         let context = self.get_context();
453         let indent = self.block_indent;
454         let shape = Shape::indented(indent, self.config);
455         let attrs_str = try_opt!(field.node.attrs.rewrite(&context, shape));
456         let lo = field
457             .node
458             .attrs
459             .last()
460             .map_or(field.span.lo, |attr| attr.span.hi);
461         let span = mk_sp(lo, field.span.lo);
462
463         let variant_body = match field.node.data {
464             ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => {
465                 // FIXME: Should limit the width, as we have a trailing comma
466                 try_opt!(format_struct(
467                     &context,
468                     "",
469                     field.node.name,
470                     &ast::Visibility::Inherited,
471                     &field.node.data,
472                     None,
473                     field.span,
474                     indent,
475                     Some(self.config.struct_variant_width()),
476                 ))
477             }
478             ast::VariantData::Unit(..) => if let Some(ref expr) = field.node.disr_expr {
479                 let one_line_width =
480                     field.node.name.to_string().len() + self.snippet(expr.span).len() + 3;
481                 if one_line_width <= shape.width {
482                     format!("{} = {}", field.node.name, self.snippet(expr.span))
483                 } else {
484                     format!(
485                         "{}\n{}{}",
486                         field.node.name,
487                         shape
488                             .indent
489                             .block_indent(self.config)
490                             .to_string(self.config),
491                         self.snippet(expr.span)
492                     )
493                 }
494             } else {
495                 String::from(field.node.name.to_string())
496             },
497         };
498
499         let attrs_extendable = attrs_str.is_empty() ||
500             (context.config.attributes_on_same_line_as_variant() &&
501                 is_attributes_extendable(&attrs_str));
502         combine_strs_with_missing_comments(
503             &context,
504             &attrs_str,
505             &variant_body,
506             span,
507             shape,
508             attrs_extendable,
509         )
510     }
511 }
512
513 pub fn format_impl(
514     context: &RewriteContext,
515     item: &ast::Item,
516     offset: Indent,
517     where_span_end: Option<BytePos>,
518 ) -> Option<String> {
519     if let ast::ItemKind::Impl(_, _, _, ref generics, _, ref self_ty, ref items) = item.node {
520         let mut result = String::new();
521         let ref_and_type = try_opt!(format_impl_ref_and_type(context, item, offset));
522         result.push_str(&ref_and_type);
523
524         let where_budget = if result.contains('\n') {
525             context.config.max_width()
526         } else {
527             context
528                 .config
529                 .max_width()
530                 .checked_sub(last_line_width(&result))
531                 .unwrap_or(0)
532         };
533         let option = WhereClauseOption::snuggled(&ref_and_type);
534         let where_clause_str = try_opt!(rewrite_where_clause(
535             context,
536             &generics.where_clause,
537             context.config.item_brace_style(),
538             Shape::legacy(where_budget, offset.block_only()),
539             context.config.where_density(),
540             "{",
541             where_span_end,
542             self_ty.span.hi,
543             option,
544         ));
545
546         if try_opt!(is_impl_single_line(
547             context,
548             &items,
549             &result,
550             &where_clause_str,
551             &item,
552         )) {
553             result.push_str(&where_clause_str);
554             if where_clause_str.contains('\n') {
555                 let white_space = offset.to_string(context.config);
556                 result.push_str(&format!("\n{}{{\n{}}}", &white_space, &white_space));
557             } else {
558                 result.push_str(" {}");
559             }
560             return Some(result);
561         }
562
563         if !where_clause_str.is_empty() && !where_clause_str.contains('\n') {
564             result.push('\n');
565             let width = offset.block_indent + context.config.tab_spaces() - 1;
566             let where_indent = Indent::new(0, width);
567             result.push_str(&where_indent.to_string(context.config));
568         }
569         result.push_str(&where_clause_str);
570
571         match context.config.item_brace_style() {
572             BraceStyle::AlwaysNextLine => {
573                 result.push('\n');
574                 result.push_str(&offset.to_string(context.config));
575             }
576             BraceStyle::PreferSameLine => result.push(' '),
577             BraceStyle::SameLineWhere => if !where_clause_str.is_empty() {
578                 result.push('\n');
579                 result.push_str(&offset.to_string(context.config));
580             } else {
581                 result.push(' ');
582             },
583         }
584
585         result.push('{');
586
587         let snippet = context.snippet(item.span);
588         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
589
590         if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
591             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
592             visitor.block_indent = offset.block_only().block_indent(context.config);
593             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
594
595             visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
596             for item in items {
597                 visitor.visit_impl_item(item);
598             }
599
600             visitor.format_missing(item.span.hi - BytePos(1));
601
602             let inner_indent_str = visitor.block_indent.to_string(context.config);
603             let outer_indent_str = offset.block_only().to_string(context.config);
604
605             result.push('\n');
606             result.push_str(&inner_indent_str);
607             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
608             result.push('\n');
609             result.push_str(&outer_indent_str);
610         }
611
612         if result.chars().last().unwrap() == '{' {
613             result.push('\n');
614             result.push_str(&offset.to_string(context.config));
615         }
616         result.push('}');
617
618         Some(result)
619     } else {
620         unreachable!();
621     }
622 }
623
624 fn is_impl_single_line(
625     context: &RewriteContext,
626     items: &[ImplItem],
627     result: &str,
628     where_clause_str: &str,
629     item: &ast::Item,
630 ) -> Option<bool> {
631     let snippet = context.snippet(item.span);
632     let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
633
634     Some(
635         context.config.impl_empty_single_line() && items.is_empty() &&
636             result.len() + where_clause_str.len() <= context.config.max_width() &&
637             !contains_comment(&snippet[open_pos..]),
638     )
639 }
640
641 fn format_impl_ref_and_type(
642     context: &RewriteContext,
643     item: &ast::Item,
644     offset: Indent,
645 ) -> Option<String> {
646     if let ast::ItemKind::Impl(
647         unsafety,
648         polarity,
649         defaultness,
650         ref generics,
651         ref trait_ref,
652         ref self_ty,
653         _,
654     ) = item.node
655     {
656         let mut result = String::new();
657
658         result.push_str(&format_visibility(&item.vis));
659         result.push_str(&format_defaultness(defaultness));
660         result.push_str(format_unsafety(unsafety));
661         result.push_str("impl");
662
663         let lo = context.codemap.span_after(item.span, "impl");
664         let hi = match *trait_ref {
665             Some(ref tr) => tr.path.span.lo,
666             None => self_ty.span.lo,
667         };
668         let shape = try_opt!(generics_shape_from_config(
669             context.config,
670             Shape::indented(offset + last_line_width(&result), context.config),
671             0,
672         ));
673         let one_line_budget = try_opt!(shape.width.checked_sub(last_line_width(&result) + 2));
674         let generics_str = try_opt!(rewrite_generics_inner(
675             context,
676             generics,
677             shape,
678             one_line_budget,
679             mk_sp(lo, hi),
680         ));
681
682         let polarity_str = if polarity == ast::ImplPolarity::Negative {
683             "!"
684         } else {
685             ""
686         };
687
688         if let Some(ref trait_ref) = *trait_ref {
689             let result_len = result.len();
690             if let Some(trait_ref_str) = rewrite_trait_ref(
691                 context,
692                 &trait_ref,
693                 offset,
694                 &generics_str,
695                 true,
696                 polarity_str,
697                 result_len,
698             ) {
699                 result.push_str(&trait_ref_str);
700             } else {
701                 let generics_str = try_opt!(rewrite_generics_inner(
702                     context,
703                     generics,
704                     shape,
705                     0,
706                     mk_sp(lo, hi),
707                 ));
708                 result.push_str(&try_opt!(rewrite_trait_ref(
709                     context,
710                     &trait_ref,
711                     offset,
712                     &generics_str,
713                     false,
714                     polarity_str,
715                     result_len,
716                 )));
717             }
718         } else {
719             result.push_str(&generics_str);
720         }
721
722         // Try to put the self type in a single line.
723         // ` for`
724         let trait_ref_overhead = if trait_ref.is_some() { 4 } else { 0 };
725         let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
726             // If there is no where clause adapt budget for type formatting to take space and curly
727             // brace into account.
728             match context.config.item_brace_style() {
729                 BraceStyle::AlwaysNextLine => 0,
730                 _ => 2,
731             }
732         } else {
733             0
734         };
735         let used_space = last_line_width(&result) + trait_ref_overhead + curly_brace_overhead;
736         // 1 = space before the type.
737         let budget = context
738             .config
739             .max_width()
740             .checked_sub(used_space + 1)
741             .unwrap_or(0);
742         if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
743             if !self_ty_str.contains('\n') {
744                 if trait_ref.is_some() {
745                     result.push_str(" for ");
746                 } else {
747                     result.push(' ');
748                 }
749                 result.push_str(&self_ty_str);
750                 return Some(result);
751             }
752         }
753
754         // Couldn't fit the self type on a single line, put it on a new line.
755         result.push('\n');
756         // Add indentation of one additional tab.
757         let new_line_offset = offset.block_indent(context.config);
758         result.push_str(&new_line_offset.to_string(context.config));
759         if trait_ref.is_some() {
760             result.push_str("for ");
761         }
762         let budget = context.config.max_width() - last_line_width(&result);
763         let type_offset = match context.config.where_style() {
764             Style::Legacy => new_line_offset + trait_ref_overhead,
765             Style::Rfc => new_line_offset,
766         };
767         result.push_str(&*try_opt!(
768             self_ty.rewrite(context, Shape::legacy(budget, type_offset))
769         ));
770         Some(result)
771     } else {
772         unreachable!();
773     }
774 }
775
776 fn rewrite_trait_ref(
777     context: &RewriteContext,
778     trait_ref: &ast::TraitRef,
779     offset: Indent,
780     generics_str: &str,
781     retry: bool,
782     polarity_str: &str,
783     result_len: usize,
784 ) -> Option<String> {
785     // 1 = space between generics and trait_ref
786     let used_space = 1 + polarity_str.len() + last_line_used_width(generics_str, result_len);
787     let shape = Shape::indented(offset + used_space, context.config);
788     if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
789         if !(retry && trait_ref_str.contains('\n')) {
790             return Some(format!(
791                 "{} {}{}",
792                 generics_str,
793                 polarity_str,
794                 &trait_ref_str
795             ));
796         }
797     }
798     // We could not make enough space for trait_ref, so put it on new line.
799     if !retry {
800         let offset = offset.block_indent(context.config);
801         let shape = Shape::indented(offset, context.config);
802         let trait_ref_str = try_opt!(trait_ref.rewrite(context, shape));
803         Some(format!(
804             "{}\n{}{}{}",
805             generics_str,
806             &offset.to_string(context.config),
807             polarity_str,
808             &trait_ref_str
809         ))
810     } else {
811         None
812     }
813 }
814
815 pub fn format_struct(
816     context: &RewriteContext,
817     item_name: &str,
818     ident: ast::Ident,
819     vis: &ast::Visibility,
820     struct_def: &ast::VariantData,
821     generics: Option<&ast::Generics>,
822     span: Span,
823     offset: Indent,
824     one_line_width: Option<usize>,
825 ) -> Option<String> {
826     match *struct_def {
827         ast::VariantData::Unit(..) => Some(format_unit_struct(item_name, ident, vis)),
828         ast::VariantData::Tuple(ref fields, _) => format_tuple_struct(
829             context,
830             item_name,
831             ident,
832             vis,
833             fields,
834             generics,
835             span,
836             offset,
837         ),
838         ast::VariantData::Struct(ref fields, _) => format_struct_struct(
839             context,
840             item_name,
841             ident,
842             vis,
843             fields,
844             generics,
845             span,
846             offset,
847             one_line_width,
848         ),
849     }
850 }
851
852 pub fn format_trait(context: &RewriteContext, item: &ast::Item, offset: Indent) -> Option<String> {
853     if let ast::ItemKind::Trait(unsafety, ref generics, ref type_param_bounds, ref trait_items) =
854         item.node
855     {
856         let mut result = String::new();
857         let header = format!(
858             "{}{}trait {}",
859             format_visibility(&item.vis),
860             format_unsafety(unsafety),
861             item.ident
862         );
863
864         result.push_str(&header);
865
866         let body_lo = context.codemap.span_after(item.span, "{");
867
868         let shape = Shape::indented(offset + last_line_width(&result), context.config);
869         let generics_str = try_opt!(rewrite_generics(
870             context,
871             generics,
872             shape,
873             mk_sp(item.span.lo, body_lo),
874         ));
875         result.push_str(&generics_str);
876
877         let trait_bound_str = try_opt!(rewrite_trait_bounds(
878             context,
879             type_param_bounds,
880             Shape::indented(offset, context.config),
881         ));
882         // If the trait, generics, and trait bound cannot fit on the same line,
883         // put the trait bounds on an indented new line
884         if offset.width() + last_line_width(&result) + trait_bound_str.len() >
885             context.config.comment_width()
886         {
887             result.push('\n');
888             let trait_indent = offset.block_only().block_indent(context.config);
889             result.push_str(&trait_indent.to_string(context.config));
890         }
891         result.push_str(&trait_bound_str);
892
893         let has_body = !trait_items.is_empty();
894
895         let where_density = if (context.config.where_density() == Density::Compressed &&
896             (!result.contains('\n') || context.config.fn_args_layout() == IndentStyle::Block)) ||
897             (context.config.fn_args_layout() == IndentStyle::Block && result.is_empty()) ||
898             (context.config.where_density() == Density::CompressedIfEmpty && !has_body &&
899                 !result.contains('\n'))
900         {
901             Density::Compressed
902         } else {
903             Density::Tall
904         };
905
906         let where_budget = try_opt!(
907             context
908                 .config
909                 .max_width()
910                 .checked_sub(last_line_width(&result))
911         );
912         let pos_before_where = if type_param_bounds.is_empty() {
913             if generics.where_clause.predicates.is_empty() {
914                 // We do not use this, so it does not matter
915                 item.span.lo
916             } else {
917                 let snippet = context.snippet(item.span);
918                 let where_pos = snippet.find_uncommented("where");
919                 item.span.lo + where_pos.map_or(BytePos(0), |p| BytePos(p as u32))
920             }
921         } else {
922             type_param_bounds[type_param_bounds.len() - 1].span().hi
923         };
924         let option = WhereClauseOption::snuggled(&generics_str);
925         let where_clause_str = try_opt!(rewrite_where_clause(
926             context,
927             &generics.where_clause,
928             context.config.item_brace_style(),
929             Shape::legacy(where_budget, offset.block_only()),
930             where_density,
931             "{",
932             None,
933             pos_before_where,
934             option,
935         ));
936         // If the where clause cannot fit on the same line,
937         // put the where clause on a new line
938         if !where_clause_str.contains('\n') &&
939             last_line_width(&result) + where_clause_str.len() + offset.width() >
940                 context.config.comment_width()
941         {
942             result.push('\n');
943             let width = offset.block_indent + context.config.tab_spaces() - 1;
944             let where_indent = Indent::new(0, width);
945             result.push_str(&where_indent.to_string(context.config));
946         }
947         result.push_str(&where_clause_str);
948
949         match context.config.item_brace_style() {
950             BraceStyle::AlwaysNextLine => {
951                 result.push('\n');
952                 result.push_str(&offset.to_string(context.config));
953             }
954             BraceStyle::PreferSameLine => result.push(' '),
955             BraceStyle::SameLineWhere => if !where_clause_str.is_empty() &&
956                 (!trait_items.is_empty() || result.contains('\n'))
957             {
958                 result.push('\n');
959                 result.push_str(&offset.to_string(context.config));
960             } else {
961                 result.push(' ');
962             },
963         }
964         result.push('{');
965
966         let snippet = context.snippet(item.span);
967         let open_pos = try_opt!(snippet.find_uncommented("{")) + 1;
968
969         if !trait_items.is_empty() || contains_comment(&snippet[open_pos..]) {
970             let mut visitor = FmtVisitor::from_codemap(context.parse_session, context.config);
971             visitor.block_indent = offset.block_only().block_indent(context.config);
972             visitor.last_pos = item.span.lo + BytePos(open_pos as u32);
973
974             for item in trait_items {
975                 visitor.visit_trait_item(item);
976             }
977
978             visitor.format_missing(item.span.hi - BytePos(1));
979
980             let inner_indent_str = visitor.block_indent.to_string(context.config);
981             let outer_indent_str = offset.block_only().to_string(context.config);
982
983             result.push('\n');
984             result.push_str(&inner_indent_str);
985             result.push_str(trim_newlines(visitor.buffer.to_string().trim()));
986             result.push('\n');
987             result.push_str(&outer_indent_str);
988         } else if result.contains('\n') {
989             result.push('\n');
990         }
991
992         result.push('}');
993         Some(result)
994     } else {
995         unreachable!();
996     }
997 }
998
999 fn format_unit_struct(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
1000     format!("{};", format_header(item_name, ident, vis))
1001 }
1002
1003 pub fn format_struct_struct(
1004     context: &RewriteContext,
1005     item_name: &str,
1006     ident: ast::Ident,
1007     vis: &ast::Visibility,
1008     fields: &[ast::StructField],
1009     generics: Option<&ast::Generics>,
1010     span: Span,
1011     offset: Indent,
1012     one_line_width: Option<usize>,
1013 ) -> Option<String> {
1014     let mut result = String::with_capacity(1024);
1015
1016     let header_str = format_header(item_name, ident, vis);
1017     result.push_str(&header_str);
1018
1019     let body_lo = context.codemap.span_after(span, "{");
1020
1021     let generics_str = match generics {
1022         Some(g) => try_opt!(format_generics(
1023             context,
1024             g,
1025             "{",
1026             "{",
1027             context.config.item_brace_style(),
1028             fields.is_empty(),
1029             offset,
1030             mk_sp(span.lo, body_lo),
1031             last_line_width(&result),
1032         )),
1033         None => {
1034             // 3 = ` {}`, 2 = ` {`.
1035             let overhead = if fields.is_empty() { 3 } else { 2 };
1036             if (context.config.item_brace_style() == BraceStyle::AlwaysNextLine &&
1037                 !fields.is_empty()) ||
1038                 context
1039                     .config
1040                     .max_width()
1041                     .checked_sub(result.len())
1042                     .unwrap_or(0) < overhead
1043             {
1044                 format!("\n{}{{", offset.block_only().to_string(context.config))
1045             } else {
1046                 " {".to_owned()
1047             }
1048         }
1049     };
1050     // 1 = `}`
1051     let overhead = if fields.is_empty() { 1 } else { 0 };
1052     let max_len = context
1053         .config
1054         .max_width()
1055         .checked_sub(offset.width())
1056         .unwrap_or(0);
1057     if !generics_str.contains('\n') && result.len() + generics_str.len() + overhead > max_len {
1058         result.push('\n');
1059         result.push_str(&offset.to_string(context.config));
1060         result.push_str(&generics_str.trim_left());
1061     } else {
1062         result.push_str(&generics_str);
1063     }
1064
1065     if fields.is_empty() {
1066         let snippet = context.snippet(mk_sp(body_lo, span.hi - BytePos(1)));
1067         if snippet.trim().is_empty() {
1068             // `struct S {}`
1069         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1070             // fix indent
1071             result.push_str(&snippet.trim_right());
1072             result.push('\n');
1073             result.push_str(&offset.to_string(context.config));
1074         } else {
1075             result.push_str(&snippet);
1076         }
1077         result.push('}');
1078         return Some(result);
1079     }
1080
1081     // 3 = ` ` and ` }`
1082     let one_line_budget = context
1083         .config
1084         .max_width()
1085         .checked_sub(result.len() + 3 + offset.width())
1086         .unwrap_or(0);
1087     let one_line_budget =
1088         one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
1089
1090     let items_str = try_opt!(rewrite_with_alignment(
1091         fields,
1092         context,
1093         Shape::indented(offset, context.config),
1094         mk_sp(body_lo, span.hi),
1095         one_line_budget,
1096     ));
1097
1098     if !items_str.contains('\n') && !result.contains('\n') && items_str.len() <= one_line_budget {
1099         Some(format!("{} {} }}", result, items_str))
1100     } else {
1101         Some(format!(
1102             "{}\n{}{}\n{}}}",
1103             result,
1104             offset
1105                 .block_indent(context.config)
1106                 .to_string(context.config),
1107             items_str,
1108             offset.to_string(context.config)
1109         ))
1110     }
1111 }
1112
1113 fn format_tuple_struct(
1114     context: &RewriteContext,
1115     item_name: &str,
1116     ident: ast::Ident,
1117     vis: &ast::Visibility,
1118     fields: &[ast::StructField],
1119     generics: Option<&ast::Generics>,
1120     span: Span,
1121     offset: Indent,
1122 ) -> Option<String> {
1123     let mut result = String::with_capacity(1024);
1124
1125     let header_str = format_header(item_name, ident, vis);
1126     result.push_str(&header_str);
1127
1128     let body_lo = if fields.is_empty() {
1129         context.codemap.span_after(span, "(")
1130     } else {
1131         fields[0].span.lo
1132     };
1133     let body_hi = if fields.is_empty() {
1134         context.codemap.span_after(span, ")")
1135     } else {
1136         // This is a dirty hack to work around a missing `)` from the span of the last field.
1137         let last_arg_span = fields[fields.len() - 1].span;
1138         if context.snippet(last_arg_span).ends_with(")") {
1139             last_arg_span.hi
1140         } else {
1141             context
1142                 .codemap
1143                 .span_after(mk_sp(last_arg_span.hi, span.hi), ")")
1144         }
1145     };
1146
1147     let where_clause_str = match generics {
1148         Some(generics) => {
1149             let budget = context.budget(last_line_width(&header_str));
1150             let shape = Shape::legacy(budget, offset);
1151             let g_span = mk_sp(span.lo, body_lo);
1152             let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1153             result.push_str(&generics_str);
1154
1155             let where_budget = context.budget(last_line_width(&result));
1156             let option = WhereClauseOption::new(true, false);
1157             try_opt!(rewrite_where_clause(
1158                 context,
1159                 &generics.where_clause,
1160                 context.config.item_brace_style(),
1161                 Shape::legacy(where_budget, offset.block_only()),
1162                 Density::Compressed,
1163                 ";",
1164                 None,
1165                 body_hi,
1166                 option,
1167             ))
1168         }
1169         None => "".to_owned(),
1170     };
1171
1172     if fields.is_empty() {
1173         // 3 = `();`
1174         let used_width = last_line_used_width(&result, offset.width()) + 3;
1175         if used_width > context.config.max_width() {
1176             result.push('\n');
1177             result.push_str(&offset
1178                 .block_indent(context.config)
1179                 .to_string(context.config))
1180         }
1181         result.push('(');
1182         let snippet = context.snippet(mk_sp(body_lo, context.codemap.span_before(span, ")")));
1183         if snippet.is_empty() {
1184             // `struct S ()`
1185         } else if snippet.trim_right_matches(&[' ', '\t'][..]).ends_with('\n') {
1186             result.push_str(&snippet.trim_right());
1187             result.push('\n');
1188             result.push_str(&offset.to_string(context.config));
1189         } else {
1190             result.push_str(&snippet);
1191         }
1192         result.push(')');
1193     } else {
1194         // 3 = `();`
1195         let body = try_opt!(
1196             rewrite_call_inner(
1197                 context,
1198                 "",
1199                 &fields.iter().map(|field| field).collect::<Vec<_>>()[..],
1200                 span,
1201                 Shape::legacy(context.budget(last_line_width(&result) + 3), offset),
1202                 context.config.fn_call_width(),
1203                 false,
1204             ).ok()
1205         );
1206         result.push_str(&body);
1207     }
1208
1209     if !where_clause_str.is_empty() && !where_clause_str.contains('\n') &&
1210         (result.contains('\n') ||
1211             offset.block_indent + result.len() + where_clause_str.len() + 1 >
1212                 context.config.max_width())
1213     {
1214         // We need to put the where clause on a new line, but we didn't
1215         // know that earlier, so the where clause will not be indented properly.
1216         result.push('\n');
1217         result.push_str(&(offset.block_only() + (context.config.tab_spaces() - 1))
1218             .to_string(context.config));
1219     }
1220     result.push_str(&where_clause_str);
1221
1222     Some(result)
1223 }
1224
1225 pub fn rewrite_type_alias(
1226     context: &RewriteContext,
1227     indent: Indent,
1228     ident: ast::Ident,
1229     ty: &ast::Ty,
1230     generics: &ast::Generics,
1231     vis: &ast::Visibility,
1232     span: Span,
1233 ) -> Option<String> {
1234     let mut result = String::new();
1235
1236     result.push_str(&format_visibility(vis));
1237     result.push_str("type ");
1238     result.push_str(&ident.to_string());
1239
1240     // 2 = `= `
1241     let shape = try_opt!(Shape::indented(indent + result.len(), context.config).sub_width(2));
1242     let g_span = mk_sp(context.codemap.span_after(span, "type"), ty.span.lo);
1243     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1244     result.push_str(&generics_str);
1245
1246     let where_budget = try_opt!(
1247         context
1248             .config
1249             .max_width()
1250             .checked_sub(last_line_width(&result))
1251     );
1252     let option = WhereClauseOption::snuggled(&result);
1253     let where_clause_str = try_opt!(rewrite_where_clause(
1254         context,
1255         &generics.where_clause,
1256         context.config.item_brace_style(),
1257         Shape::legacy(where_budget, indent),
1258         context.config.where_density(),
1259         "=",
1260         Some(span.hi),
1261         generics.span.hi,
1262         option,
1263     ));
1264     result.push_str(&where_clause_str);
1265     if where_clause_str.is_empty() {
1266         result.push_str(" = ");
1267     } else {
1268         result.push_str(&format!("\n{}= ", indent.to_string(context.config)));
1269     }
1270
1271     let line_width = last_line_width(&result);
1272     // This checked_sub may fail as the extra space after '=' is not taken into account
1273     // In that case the budget is set to 0 which will make ty.rewrite retry on a new line
1274     let budget = context
1275         .config
1276         .max_width()
1277         .checked_sub(indent.width() + line_width + ";".len())
1278         .unwrap_or(0);
1279     let type_indent = indent + line_width;
1280     // Try to fit the type on the same line
1281     let ty_str = try_opt!(
1282         ty.rewrite(context, Shape::legacy(budget, type_indent))
1283             .or_else(|| {
1284                 // The line was too short, try to put the type on the next line
1285
1286                 // Remove the space after '='
1287                 result.pop();
1288                 let type_indent = indent.block_indent(context.config);
1289                 result.push('\n');
1290                 result.push_str(&type_indent.to_string(context.config));
1291                 let budget = try_opt!(
1292                     context
1293                         .config
1294                         .max_width()
1295                         .checked_sub(type_indent.width() + ";".len())
1296                 );
1297                 ty.rewrite(context, Shape::legacy(budget, type_indent))
1298             })
1299     );
1300     result.push_str(&ty_str);
1301     result.push_str(";");
1302     Some(result)
1303 }
1304
1305 fn type_annotation_spacing(config: &Config) -> (&str, &str) {
1306     (
1307         if config.space_before_type_annotation() {
1308             " "
1309         } else {
1310             ""
1311         },
1312         if config.space_after_type_annotation_colon() {
1313             " "
1314         } else {
1315             ""
1316         },
1317     )
1318 }
1319
1320 pub fn rewrite_struct_field_prefix(
1321     context: &RewriteContext,
1322     field: &ast::StructField,
1323 ) -> Option<String> {
1324     let vis = format_visibility(&field.vis);
1325     let type_annotation_spacing = type_annotation_spacing(context.config);
1326     Some(match field.ident {
1327         Some(name) => format!("{}{}{}:", vis, name, type_annotation_spacing.0),
1328         None => format!("{}", vis),
1329     })
1330 }
1331
1332 fn rewrite_struct_field_type(
1333     context: &RewriteContext,
1334     last_line_width: usize,
1335     field: &ast::StructField,
1336     spacing: &str,
1337     shape: Shape,
1338 ) -> Option<String> {
1339     let ty_shape = try_opt!(shape.offset_left(last_line_width + spacing.len()));
1340     field
1341         .ty
1342         .rewrite(context, ty_shape)
1343         .map(|ty| format!("{}{}", spacing, ty))
1344 }
1345
1346 impl Rewrite for ast::StructField {
1347     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1348         rewrite_struct_field(context, self, shape, 0)
1349     }
1350 }
1351
1352 pub fn rewrite_struct_field(
1353     context: &RewriteContext,
1354     field: &ast::StructField,
1355     shape: Shape,
1356     lhs_max_width: usize,
1357 ) -> Option<String> {
1358     if contains_skip(&field.attrs) {
1359         let span = context.snippet(mk_sp(field.attrs[0].span.lo, field.span.hi));
1360         return wrap_str(span, context.config.max_width(), shape);
1361     }
1362
1363     let type_annotation_spacing = type_annotation_spacing(context.config);
1364     let prefix = try_opt!(rewrite_struct_field_prefix(context, field));
1365
1366     let attrs_str = try_opt!(field.attrs.rewrite(context, shape));
1367     let attrs_extendable = attrs_str.is_empty() ||
1368         (context.config.attributes_on_same_line_as_field() && is_attributes_extendable(&attrs_str));
1369     let missing_span = if field.attrs.is_empty() {
1370         mk_sp(field.span.lo, field.span.lo)
1371     } else {
1372         mk_sp(field.attrs.last().unwrap().span.hi, field.span.lo)
1373     };
1374     let mut spacing = String::from(if field.ident.is_some() {
1375         type_annotation_spacing.1
1376     } else {
1377         ""
1378     });
1379     // Try to put everything on a single line.
1380     let attr_prefix = try_opt!(combine_strs_with_missing_comments(
1381         context,
1382         &attrs_str,
1383         &prefix,
1384         missing_span,
1385         shape,
1386         attrs_extendable,
1387     ));
1388     let overhead = last_line_width(&attr_prefix);
1389     let lhs_offset = lhs_max_width.checked_sub(overhead).unwrap_or(0);
1390     for _ in 0..lhs_offset {
1391         spacing.push(' ');
1392     }
1393     // In this extreme case we will be missing a space betweeen an attribute and a field.
1394     if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
1395         spacing.push(' ');
1396     }
1397     let ty_rewritten = rewrite_struct_field_type(context, overhead, field, &spacing, shape);
1398     if let Some(ref ty) = ty_rewritten {
1399         if !ty.contains('\n') {
1400             return Some(attr_prefix + &ty);
1401         }
1402     }
1403
1404     // We must use multiline.
1405     let last_line_width = last_line_width(&prefix);
1406     let ty_rewritten = rewrite_struct_field_type(context, last_line_width, field, &spacing, shape);
1407
1408     let type_offset = shape.indent.block_indent(context.config);
1409     let rewrite_type_in_next_line = || {
1410         field
1411             .ty
1412             .rewrite(context, Shape::indented(type_offset, context.config))
1413     };
1414
1415     let field_str = match ty_rewritten {
1416         // If we start from the next line and type fits in a single line, then do so.
1417         Some(ref ty) => match rewrite_type_in_next_line() {
1418             Some(ref new_ty) if !new_ty.contains('\n') => format!(
1419                 "{}\n{}{}",
1420                 prefix,
1421                 type_offset.to_string(&context.config),
1422                 &new_ty
1423             ),
1424             _ => prefix + &ty,
1425         },
1426         _ => {
1427             let ty = try_opt!(rewrite_type_in_next_line());
1428             format!(
1429                 "{}\n{}{}",
1430                 prefix,
1431                 type_offset.to_string(&context.config),
1432                 &ty
1433             )
1434         }
1435     };
1436     combine_strs_with_missing_comments(
1437         context,
1438         &attrs_str,
1439         &field_str,
1440         missing_span,
1441         shape,
1442         attrs_extendable,
1443     )
1444 }
1445
1446 pub fn rewrite_static(
1447     prefix: &str,
1448     vis: &ast::Visibility,
1449     ident: ast::Ident,
1450     ty: &ast::Ty,
1451     mutability: ast::Mutability,
1452     expr_opt: Option<&ptr::P<ast::Expr>>,
1453     offset: Indent,
1454     span: Span,
1455     context: &RewriteContext,
1456 ) -> Option<String> {
1457     let colon = colon_spaces(
1458         context.config.space_before_type_annotation(),
1459         context.config.space_after_type_annotation_colon(),
1460     );
1461     let prefix = format!(
1462         "{}{} {}{}{}",
1463         format_visibility(vis),
1464         prefix,
1465         format_mutability(mutability),
1466         ident,
1467         colon,
1468     );
1469     // 2 = " =".len()
1470     let ty_str = try_opt!(ty.rewrite(
1471         context,
1472         try_opt!(
1473             Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)
1474         ),
1475     ));
1476
1477     if let Some(expr) = expr_opt {
1478         let lhs = format!("{}{} =", prefix, ty_str);
1479         // 1 = ;
1480         let remaining_width = context.config.max_width() - offset.block_indent - 1;
1481         rewrite_assign_rhs(
1482             context,
1483             lhs,
1484             expr,
1485             Shape::legacy(remaining_width, offset.block_only()),
1486         ).and_then(|res| {
1487             recover_comment_removed(res, span, context, Shape::indented(offset, context.config))
1488         })
1489             .map(|s| if s.ends_with(';') { s } else { s + ";" })
1490     } else {
1491         Some(format!("{}{};", prefix, ty_str))
1492     }
1493 }
1494
1495 pub fn rewrite_associated_type(
1496     ident: ast::Ident,
1497     ty_opt: Option<&ptr::P<ast::Ty>>,
1498     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1499     context: &RewriteContext,
1500     indent: Indent,
1501 ) -> Option<String> {
1502     let prefix = format!("type {}", ident);
1503
1504     let type_bounds_str = if let Some(ty_param_bounds) = ty_param_bounds_opt {
1505         // 2 = ": ".len()
1506         let shape = try_opt!(Shape::indented(indent, context.config).offset_left(prefix.len() + 2));
1507         let bounds: &[_] = ty_param_bounds;
1508         let bound_str = try_opt!(
1509             bounds
1510                 .iter()
1511                 .map(|ty_bound| ty_bound.rewrite(context, shape))
1512                 .collect::<Option<Vec<_>>>()
1513         );
1514         if bounds.len() > 0 {
1515             format!(": {}", join_bounds(context, shape, &bound_str))
1516         } else {
1517             String::new()
1518         }
1519     } else {
1520         String::new()
1521     };
1522
1523     if let Some(ty) = ty_opt {
1524         let ty_str = try_opt!(ty.rewrite(
1525             context,
1526             Shape::legacy(
1527                 context.config.max_width() - indent.block_indent - prefix.len() - 2,
1528                 indent.block_only(),
1529             ),
1530         ));
1531         Some(format!("{}{} = {};", prefix, type_bounds_str, ty_str))
1532     } else {
1533         Some(format!("{}{};", prefix, type_bounds_str))
1534     }
1535 }
1536
1537 pub fn rewrite_associated_impl_type(
1538     ident: ast::Ident,
1539     defaultness: ast::Defaultness,
1540     ty_opt: Option<&ptr::P<ast::Ty>>,
1541     ty_param_bounds_opt: Option<&ast::TyParamBounds>,
1542     context: &RewriteContext,
1543     indent: Indent,
1544 ) -> Option<String> {
1545     let result = try_opt!(rewrite_associated_type(
1546         ident,
1547         ty_opt,
1548         ty_param_bounds_opt,
1549         context,
1550         indent,
1551     ));
1552
1553     match defaultness {
1554         ast::Defaultness::Default => Some(format!("default {}", result)),
1555         _ => Some(result),
1556     }
1557 }
1558
1559 impl Rewrite for ast::FunctionRetTy {
1560     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1561         match *self {
1562             ast::FunctionRetTy::Default(_) => Some(String::new()),
1563             ast::FunctionRetTy::Ty(ref ty) => {
1564                 let inner_width = try_opt!(shape.width.checked_sub(3));
1565                 ty.rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
1566                     .map(|r| format!("-> {}", r))
1567             }
1568         }
1569     }
1570 }
1571
1572 fn is_empty_infer(context: &RewriteContext, ty: &ast::Ty) -> bool {
1573     match ty.node {
1574         ast::TyKind::Infer => {
1575             let original = context.snippet(ty.span);
1576             original != "_"
1577         }
1578         _ => false,
1579     }
1580 }
1581
1582 impl Rewrite for ast::Arg {
1583     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
1584         if is_named_arg(self) {
1585             let mut result = try_opt!(
1586                 self.pat
1587                     .rewrite(context, Shape::legacy(shape.width, shape.indent))
1588             );
1589
1590             if !is_empty_infer(context, &*self.ty) {
1591                 if context.config.space_before_type_annotation() {
1592                     result.push_str(" ");
1593                 }
1594                 result.push_str(":");
1595                 if context.config.space_after_type_annotation_colon() {
1596                     result.push_str(" ");
1597                 }
1598                 let max_width = try_opt!(shape.width.checked_sub(result.len()));
1599                 let ty_str = try_opt!(self.ty.rewrite(
1600                     context,
1601                     Shape::legacy(max_width, shape.indent + result.len()),
1602                 ));
1603                 result.push_str(&ty_str);
1604             }
1605
1606             Some(result)
1607         } else {
1608             self.ty.rewrite(context, shape)
1609         }
1610     }
1611 }
1612
1613 fn rewrite_explicit_self(
1614     explicit_self: &ast::ExplicitSelf,
1615     args: &[ast::Arg],
1616     context: &RewriteContext,
1617 ) -> Option<String> {
1618     match explicit_self.node {
1619         ast::SelfKind::Region(lt, m) => {
1620             let mut_str = format_mutability(m);
1621             match lt {
1622                 Some(ref l) => {
1623                     let lifetime_str = try_opt!(l.rewrite(
1624                         context,
1625                         Shape::legacy(context.config.max_width(), Indent::empty()),
1626                     ));
1627                     Some(format!("&{} {}self", lifetime_str, mut_str))
1628                 }
1629                 None => Some(format!("&{}self", mut_str)),
1630             }
1631         }
1632         ast::SelfKind::Explicit(ref ty, _) => {
1633             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1634
1635             let mutability = explicit_self_mutability(&args[0]);
1636             let type_str = try_opt!(ty.rewrite(
1637                 context,
1638                 Shape::legacy(context.config.max_width(), Indent::empty()),
1639             ));
1640
1641             Some(format!(
1642                 "{}self: {}",
1643                 format_mutability(mutability),
1644                 type_str
1645             ))
1646         }
1647         ast::SelfKind::Value(_) => {
1648             assert!(!args.is_empty(), "&[ast::Arg] shouldn't be empty.");
1649
1650             let mutability = explicit_self_mutability(&args[0]);
1651
1652             Some(format!("{}self", format_mutability(mutability)))
1653         }
1654     }
1655 }
1656
1657 // Hacky solution caused by absence of `Mutability` in `SelfValue` and
1658 // `SelfExplicit` variants of `ast::ExplicitSelf_`.
1659 fn explicit_self_mutability(arg: &ast::Arg) -> ast::Mutability {
1660     if let ast::PatKind::Ident(ast::BindingMode::ByValue(mutability), _, _) = arg.pat.node {
1661         mutability
1662     } else {
1663         unreachable!()
1664     }
1665 }
1666
1667 pub fn span_lo_for_arg(arg: &ast::Arg) -> BytePos {
1668     if is_named_arg(arg) {
1669         arg.pat.span.lo
1670     } else {
1671         arg.ty.span.lo
1672     }
1673 }
1674
1675 pub fn span_hi_for_arg(context: &RewriteContext, arg: &ast::Arg) -> BytePos {
1676     match arg.ty.node {
1677         ast::TyKind::Infer if context.snippet(arg.ty.span) == "_" => arg.ty.span.hi,
1678         ast::TyKind::Infer if is_named_arg(arg) => arg.pat.span.hi,
1679         _ => arg.ty.span.hi,
1680     }
1681 }
1682
1683 pub fn is_named_arg(arg: &ast::Arg) -> bool {
1684     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
1685         ident.node != symbol::keywords::Invalid.ident()
1686     } else {
1687         true
1688     }
1689 }
1690
1691 // Return type is (result, force_new_line_for_brace)
1692 fn rewrite_fn_base(
1693     context: &RewriteContext,
1694     indent: Indent,
1695     ident: ast::Ident,
1696     fd: &ast::FnDecl,
1697     generics: &ast::Generics,
1698     unsafety: ast::Unsafety,
1699     constness: ast::Constness,
1700     defaultness: ast::Defaultness,
1701     abi: abi::Abi,
1702     vis: &ast::Visibility,
1703     span: Span,
1704     newline_brace: bool,
1705     has_body: bool,
1706     has_braces: bool,
1707 ) -> Option<(String, bool)> {
1708     let mut force_new_line_for_brace = false;
1709
1710     let where_clause = &generics.where_clause;
1711
1712     let mut result = String::with_capacity(1024);
1713     // Vis defaultness constness unsafety abi.
1714     result.push_str(&*format_visibility(vis));
1715     result.push_str(format_defaultness(defaultness));
1716     result.push_str(format_constness(constness));
1717     result.push_str(format_unsafety(unsafety));
1718     if abi != abi::Abi::Rust {
1719         result.push_str(&format_abi(abi, context.config.force_explicit_abi()));
1720     }
1721
1722     // fn foo
1723     result.push_str("fn ");
1724     result.push_str(&ident.to_string());
1725
1726     // Generics.
1727     let overhead = if has_braces && !newline_brace {
1728         // 4 = `() {`
1729         4
1730     } else {
1731         // 2 = `()`
1732         2
1733     };
1734     let used_width = last_line_used_width(&result, indent.width());
1735     let one_line_budget = context
1736         .config
1737         .max_width()
1738         .checked_sub(used_width + overhead)
1739         .unwrap_or(0);
1740     let shape = Shape {
1741         width: one_line_budget,
1742         indent: indent,
1743         offset: used_width,
1744     };
1745     let g_span = mk_sp(span.lo, fd.output.span().lo);
1746     let generics_str = try_opt!(rewrite_generics(context, generics, shape, g_span));
1747     result.push_str(&generics_str);
1748
1749     let snuggle_angle_bracket = generics_str
1750         .lines()
1751         .last()
1752         .map_or(false, |l| l.trim_left().len() == 1);
1753
1754     // Note that the width and indent don't really matter, we'll re-layout the
1755     // return type later anyway.
1756     let ret_str = try_opt!(
1757         fd.output
1758             .rewrite(&context, Shape::indented(indent, context.config))
1759     );
1760
1761     let multi_line_ret_str = ret_str.contains('\n');
1762     let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
1763
1764     // Args.
1765     let (one_line_budget, multi_line_budget, mut arg_indent) = try_opt!(compute_budgets_for_args(
1766         context,
1767         &result,
1768         indent,
1769         ret_str_len,
1770         newline_brace,
1771         has_braces,
1772         multi_line_ret_str,
1773     ));
1774
1775     debug!(
1776         "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, arg_indent: {:?}",
1777         one_line_budget,
1778         multi_line_budget,
1779         arg_indent
1780     );
1781
1782     // Check if vertical layout was forced.
1783     if one_line_budget == 0 {
1784         if snuggle_angle_bracket {
1785             result.push('(');
1786         } else {
1787             if context.config.fn_args_paren_newline() {
1788                 result.push('\n');
1789                 result.push_str(&arg_indent.to_string(context.config));
1790                 if context.config.fn_args_layout() == IndentStyle::Visual {
1791                     arg_indent = arg_indent + 1; // extra space for `(`
1792                 }
1793                 result.push('(');
1794             } else {
1795                 result.push_str("(");
1796                 if context.config.fn_args_layout() == IndentStyle::Visual {
1797                     result.push('\n');
1798                     result.push_str(&arg_indent.to_string(context.config));
1799                 }
1800             }
1801         }
1802     } else {
1803         result.push('(');
1804     }
1805     if context.config.spaces_within_parens() && fd.inputs.len() > 0 && result.ends_with('(') {
1806         result.push(' ')
1807     }
1808
1809     // A conservative estimation, to goal is to be over all parens in generics
1810     let args_start = generics
1811         .ty_params
1812         .last()
1813         .map_or(span.lo, |tp| end_typaram(tp));
1814     let args_end = if fd.inputs.is_empty() {
1815         context.codemap.span_after(mk_sp(args_start, span.hi), ")")
1816     } else {
1817         let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi, span.hi);
1818         context.codemap.span_after(last_span, ")")
1819     };
1820     let args_span = mk_sp(
1821         context.codemap.span_after(mk_sp(args_start, span.hi), "("),
1822         args_end,
1823     );
1824     let arg_str = try_opt!(rewrite_args(
1825         context,
1826         &fd.inputs,
1827         fd.get_self().as_ref(),
1828         one_line_budget,
1829         multi_line_budget,
1830         indent,
1831         arg_indent,
1832         args_span,
1833         fd.variadic,
1834         generics_str.contains('\n'),
1835     ));
1836
1837     let put_args_in_block = match context.config.fn_args_layout() {
1838         IndentStyle::Block => arg_str.contains('\n') || arg_str.len() > one_line_budget,
1839         _ => false,
1840     } && !fd.inputs.is_empty();
1841
1842     let mut args_last_line_contains_comment = false;
1843     if put_args_in_block {
1844         arg_indent = indent.block_indent(context.config);
1845         result.push('\n');
1846         result.push_str(&arg_indent.to_string(context.config));
1847         result.push_str(&arg_str);
1848         result.push('\n');
1849         result.push_str(&indent.to_string(context.config));
1850         result.push(')');
1851     } else {
1852         result.push_str(&arg_str);
1853         let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
1854         // Put the closing brace on the next line if it overflows the max width.
1855         // 1 = `)`
1856         if fd.inputs.len() == 0 && used_width + 1 > context.config.max_width() {
1857             result.push('\n');
1858         }
1859         if context.config.spaces_within_parens() && fd.inputs.len() > 0 {
1860             result.push(' ')
1861         }
1862         // If the last line of args contains comment, we cannot put the closing paren
1863         // on the same line.
1864         if arg_str
1865             .lines()
1866             .last()
1867             .map_or(false, |last_line| last_line.contains("//"))
1868         {
1869             args_last_line_contains_comment = true;
1870             result.push('\n');
1871             result.push_str(&arg_indent.to_string(context.config));
1872         }
1873         result.push(')');
1874     }
1875
1876     // Return type.
1877     if let ast::FunctionRetTy::Ty(..) = fd.output {
1878         let ret_should_indent = match context.config.fn_args_layout() {
1879             // If our args are block layout then we surely must have space.
1880             IndentStyle::Block if put_args_in_block || fd.inputs.len() == 0 => false,
1881             _ if args_last_line_contains_comment => false,
1882             _ if result.contains('\n') || multi_line_ret_str => true,
1883             _ => {
1884                 // If the return type would push over the max width, then put the return type on
1885                 // a new line. With the +1 for the signature length an additional space between
1886                 // the closing parenthesis of the argument and the arrow '->' is considered.
1887                 let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
1888
1889                 // If there is no where clause, take into account the space after the return type
1890                 // and the brace.
1891                 if where_clause.predicates.is_empty() {
1892                     sig_length += 2;
1893                 }
1894
1895                 sig_length > context.config.max_width()
1896             }
1897         };
1898         let ret_indent = if ret_should_indent {
1899             let indent = match context.config.fn_return_indent() {
1900                 ReturnIndent::WithWhereClause => indent + 4,
1901                 // Aligning with non-existent args looks silly.
1902                 _ if arg_str.is_empty() => {
1903                     force_new_line_for_brace = true;
1904                     indent + 4
1905                 }
1906                 // FIXME: we might want to check that using the arg indent
1907                 // doesn't blow our budget, and if it does, then fallback to
1908                 // the where clause indent.
1909                 _ => arg_indent,
1910             };
1911
1912             result.push('\n');
1913             result.push_str(&indent.to_string(context.config));
1914             indent
1915         } else {
1916             result.push(' ');
1917             Indent::new(indent.block_indent, last_line_width(&result))
1918         };
1919
1920         if multi_line_ret_str || ret_should_indent {
1921             // Now that we know the proper indent and width, we need to
1922             // re-layout the return type.
1923             let ret_str = try_opt!(
1924                 fd.output
1925                     .rewrite(context, Shape::indented(ret_indent, context.config))
1926             );
1927             result.push_str(&ret_str);
1928         } else {
1929             result.push_str(&ret_str);
1930         }
1931
1932         // Comment between return type and the end of the decl.
1933         let snippet_lo = fd.output.span().hi;
1934         if where_clause.predicates.is_empty() {
1935             let snippet_hi = span.hi;
1936             let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
1937             // Try to preserve the layout of the original snippet.
1938             let original_starts_with_newline = snippet
1939                 .find(|c| c != ' ')
1940                 .map_or(false, |i| snippet[i..].starts_with('\n'));
1941             let original_ends_with_newline = snippet
1942                 .rfind(|c| c != ' ')
1943                 .map_or(false, |i| snippet[i..].ends_with('\n'));
1944             let snippet = snippet.trim();
1945             if !snippet.is_empty() {
1946                 result.push(if original_starts_with_newline {
1947                     '\n'
1948                 } else {
1949                     ' '
1950                 });
1951                 result.push_str(snippet);
1952                 if original_ends_with_newline {
1953                     force_new_line_for_brace = true;
1954                 }
1955             }
1956         }
1957     }
1958
1959     let should_compress_where = match context.config.where_density() {
1960         Density::Compressed => !result.contains('\n'),
1961         Density::CompressedIfEmpty => !has_body && !result.contains('\n'),
1962         _ => false,
1963     };
1964
1965     let pos_before_where = match fd.output {
1966         ast::FunctionRetTy::Default(..) => args_span.hi,
1967         ast::FunctionRetTy::Ty(ref ty) => ty.span.hi,
1968     };
1969
1970     if where_clause.predicates.len() == 1 && should_compress_where {
1971         let budget = context
1972             .config
1973             .max_width()
1974             .checked_sub(last_line_used_width(&result, indent.width()))
1975             .unwrap_or(0);
1976         if let Some(where_clause_str) = rewrite_where_clause(
1977             context,
1978             where_clause,
1979             context.config.fn_brace_style(),
1980             Shape::legacy(budget, indent),
1981             Density::Compressed,
1982             "{",
1983             Some(span.hi),
1984             pos_before_where,
1985             WhereClauseOption::compressed(),
1986         ) {
1987             result.push_str(&where_clause_str);
1988             force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
1989             return Some((result, force_new_line_for_brace));
1990         }
1991     }
1992
1993     let option = WhereClauseOption::new(!has_braces, put_args_in_block && ret_str.is_empty());
1994     let where_clause_str = try_opt!(rewrite_where_clause(
1995         context,
1996         where_clause,
1997         context.config.fn_brace_style(),
1998         Shape::indented(indent, context.config),
1999         Density::Tall,
2000         "{",
2001         Some(span.hi),
2002         pos_before_where,
2003         option,
2004     ));
2005     // If there are neither where clause nor return type, we may be missing comments between
2006     // args and `{`.
2007     if where_clause_str.is_empty() {
2008         if let ast::FunctionRetTy::Default(ret_span) = fd.output {
2009             let sp = mk_sp(args_span.hi, ret_span.hi);
2010             let missing_snippet = context.snippet(sp);
2011             let trimmed_snippet = missing_snippet.trim();
2012             let missing_comment = if trimmed_snippet.is_empty() {
2013                 String::new()
2014             } else {
2015                 try_opt!(rewrite_comment(
2016                     trimmed_snippet,
2017                     false,
2018                     Shape::indented(indent, context.config),
2019                     context.config,
2020                 ))
2021             };
2022             if !missing_comment.is_empty() {
2023                 let pos = missing_snippet.chars().position(|c| c == '/').unwrap_or(0);
2024                 // 1 = ` `
2025                 let total_width = missing_comment.len() + last_line_width(&result) + 1;
2026                 let force_new_line_before_comment = missing_snippet[..pos].contains('\n') ||
2027                     total_width > context.config.max_width();
2028                 let sep = if force_new_line_before_comment {
2029                     format!("\n{}", indent.to_string(context.config))
2030                 } else {
2031                     String::from(" ")
2032                 };
2033                 result.push_str(&sep);
2034                 result.push_str(&missing_comment);
2035                 force_new_line_for_brace = true;
2036             }
2037         }
2038     }
2039
2040     result.push_str(&where_clause_str);
2041
2042     force_new_line_for_brace |= last_line_contains_single_line_comment(&result);
2043     return Some((result, force_new_line_for_brace));
2044 }
2045
2046 struct WhereClauseOption {
2047     suppress_comma: bool, // Force no trailing comma
2048     snuggle: bool,        // Do not insert newline before `where`
2049     compress_where: bool, // Try single line where clause instead of vertical layout
2050 }
2051
2052 impl WhereClauseOption {
2053     pub fn new(suppress_comma: bool, snuggle: bool) -> WhereClauseOption {
2054         WhereClauseOption {
2055             suppress_comma: suppress_comma,
2056             snuggle: snuggle,
2057             compress_where: false,
2058         }
2059     }
2060
2061     pub fn compressed() -> WhereClauseOption {
2062         WhereClauseOption {
2063             suppress_comma: true,
2064             snuggle: false,
2065             compress_where: true,
2066         }
2067     }
2068
2069     pub fn snuggled(current: &str) -> WhereClauseOption {
2070         WhereClauseOption {
2071             suppress_comma: false,
2072             snuggle: trimmed_last_line_width(current) == 1,
2073             compress_where: false,
2074         }
2075     }
2076 }
2077
2078 fn rewrite_args(
2079     context: &RewriteContext,
2080     args: &[ast::Arg],
2081     explicit_self: Option<&ast::ExplicitSelf>,
2082     one_line_budget: usize,
2083     multi_line_budget: usize,
2084     indent: Indent,
2085     arg_indent: Indent,
2086     span: Span,
2087     variadic: bool,
2088     generics_str_contains_newline: bool,
2089 ) -> Option<String> {
2090     let mut arg_item_strs = try_opt!(
2091         args.iter()
2092             .map(|arg| {
2093                 arg.rewrite(&context, Shape::legacy(multi_line_budget, arg_indent))
2094             })
2095             .collect::<Option<Vec<_>>>()
2096     );
2097
2098     // Account for sugary self.
2099     // FIXME: the comment for the self argument is dropped. This is blocked
2100     // on rust issue #27522.
2101     let min_args = explicit_self
2102         .and_then(|explicit_self| {
2103             rewrite_explicit_self(explicit_self, args, context)
2104         })
2105         .map_or(1, |self_str| {
2106             arg_item_strs[0] = self_str;
2107             2
2108         });
2109
2110     // Comments between args.
2111     let mut arg_items = Vec::new();
2112     if min_args == 2 {
2113         arg_items.push(ListItem::from_str(""));
2114     }
2115
2116     // FIXME(#21): if there are no args, there might still be a comment, but
2117     // without spans for the comment or parens, there is no chance of
2118     // getting it right. You also don't get to put a comment on self, unless
2119     // it is explicit.
2120     if args.len() >= min_args || variadic {
2121         let comment_span_start = if min_args == 2 {
2122             let second_arg_start = if arg_has_pattern(&args[1]) {
2123                 args[1].pat.span.lo
2124             } else {
2125                 args[1].ty.span.lo
2126             };
2127             let reduced_span = mk_sp(span.lo, second_arg_start);
2128
2129             context.codemap.span_after_last(reduced_span, ",")
2130         } else {
2131             span.lo
2132         };
2133
2134         enum ArgumentKind<'a> {
2135             Regular(&'a ast::Arg),
2136             Variadic(BytePos),
2137         }
2138
2139         let variadic_arg = if variadic {
2140             let variadic_span = mk_sp(args.last().unwrap().ty.span.hi, span.hi);
2141             let variadic_start = context.codemap.span_after(variadic_span, "...") - BytePos(3);
2142             Some(ArgumentKind::Variadic(variadic_start))
2143         } else {
2144             None
2145         };
2146
2147         let more_items = itemize_list(
2148             context.codemap,
2149             args[min_args - 1..]
2150                 .iter()
2151                 .map(ArgumentKind::Regular)
2152                 .chain(variadic_arg),
2153             ")",
2154             |arg| match *arg {
2155                 ArgumentKind::Regular(arg) => span_lo_for_arg(arg),
2156                 ArgumentKind::Variadic(start) => start,
2157             },
2158             |arg| match *arg {
2159                 ArgumentKind::Regular(arg) => arg.ty.span.hi,
2160                 ArgumentKind::Variadic(start) => start + BytePos(3),
2161             },
2162             |arg| match *arg {
2163                 ArgumentKind::Regular(..) => None,
2164                 ArgumentKind::Variadic(..) => Some("...".to_owned()),
2165             },
2166             comment_span_start,
2167             span.hi,
2168             false,
2169         );
2170
2171         arg_items.extend(more_items);
2172     }
2173
2174     let fits_in_one_line = !generics_str_contains_newline &&
2175         (arg_items.len() == 0 || arg_items.len() == 1 && arg_item_strs[0].len() <= one_line_budget);
2176
2177     for (item, arg) in arg_items.iter_mut().zip(arg_item_strs) {
2178         item.item = Some(arg);
2179     }
2180
2181     let last_line_ends_with_comment = arg_items
2182         .iter()
2183         .last()
2184         .and_then(|item| item.post_comment.as_ref())
2185         .map_or(false, |s| s.trim().starts_with("//"));
2186
2187     let (indent, trailing_comma) = match context.config.fn_args_layout() {
2188         IndentStyle::Block if fits_in_one_line => {
2189             (indent.block_indent(context.config), SeparatorTactic::Never)
2190         }
2191         IndentStyle::Block => (
2192             indent.block_indent(context.config),
2193             context.config.trailing_comma(),
2194         ),
2195         IndentStyle::Visual if last_line_ends_with_comment => {
2196             (arg_indent, context.config.trailing_comma())
2197         }
2198         IndentStyle::Visual => (arg_indent, SeparatorTactic::Never),
2199     };
2200
2201     let tactic = definitive_tactic(
2202         &arg_items,
2203         context.config.fn_args_density().to_list_tactic(),
2204         Separator::Comma,
2205         one_line_budget,
2206     );
2207     let budget = match tactic {
2208         DefinitiveListTactic::Horizontal => one_line_budget,
2209         _ => multi_line_budget,
2210     };
2211
2212     debug!("rewrite_args: budget: {}, tactic: {:?}", budget, tactic);
2213
2214     let fmt = ListFormatting {
2215         tactic: tactic,
2216         separator: ",",
2217         trailing_separator: if variadic {
2218             SeparatorTactic::Never
2219         } else {
2220             trailing_comma
2221         },
2222         separator_place: SeparatorPlace::Back,
2223         shape: Shape::legacy(budget, indent),
2224         ends_with_newline: tactic.ends_with_newline(context.config.fn_args_layout()),
2225         preserve_newline: true,
2226         config: context.config,
2227     };
2228
2229     write_list(&arg_items, &fmt)
2230 }
2231
2232 fn arg_has_pattern(arg: &ast::Arg) -> bool {
2233     if let ast::PatKind::Ident(_, ident, _) = arg.pat.node {
2234         ident.node != symbol::keywords::Invalid.ident()
2235     } else {
2236         true
2237     }
2238 }
2239
2240 fn compute_budgets_for_args(
2241     context: &RewriteContext,
2242     result: &str,
2243     indent: Indent,
2244     ret_str_len: usize,
2245     newline_brace: bool,
2246     has_braces: bool,
2247     force_vertical_layout: bool,
2248 ) -> Option<((usize, usize, Indent))> {
2249     debug!(
2250         "compute_budgets_for_args {} {:?}, {}, {}",
2251         result.len(),
2252         indent,
2253         ret_str_len,
2254         newline_brace
2255     );
2256     // Try keeping everything on the same line.
2257     if !result.contains('\n') && !force_vertical_layout {
2258         // 2 = `()`, 3 = `() `, space is before ret_string.
2259         let overhead = if ret_str_len == 0 { 2 } else { 3 };
2260         let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
2261         if has_braces {
2262             if !newline_brace {
2263                 // 2 = `{}`
2264                 used_space += 2;
2265             }
2266         } else {
2267             // 1 = `;`
2268             used_space += 1;
2269         }
2270         let one_line_budget = context
2271             .config
2272             .max_width()
2273             .checked_sub(used_space)
2274             .unwrap_or(0);
2275
2276         if one_line_budget > 0 {
2277             // 4 = "() {".len()
2278             let (indent, multi_line_budget) = match context.config.fn_args_layout() {
2279                 IndentStyle::Block => {
2280                     let indent = indent.block_indent(context.config);
2281                     let budget =
2282                         try_opt!(context.config.max_width().checked_sub(indent.width() + 1));
2283                     (indent, budget)
2284                 }
2285                 IndentStyle::Visual => {
2286                     let indent = indent + result.len() + 1;
2287                     let multi_line_overhead =
2288                         indent.width() + result.len() + if newline_brace { 2 } else { 4 };
2289                     let budget =
2290                         try_opt!(context.config.max_width().checked_sub(multi_line_overhead));
2291                     (indent, budget)
2292                 }
2293             };
2294
2295             return Some((one_line_budget, multi_line_budget, indent));
2296         }
2297     }
2298
2299     // Didn't work. we must force vertical layout and put args on a newline.
2300     let new_indent = indent.block_indent(context.config);
2301     let used_space = match context.config.fn_args_layout() {
2302         // 1 = `,`
2303         IndentStyle::Block => new_indent.width() + 1,
2304         // Account for `)` and possibly ` {`.
2305         IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
2306     };
2307     let max_space = try_opt!(context.config.max_width().checked_sub(used_space));
2308     Some((0, max_space, new_indent))
2309 }
2310
2311 fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause, has_body: bool) -> bool {
2312     match (config.fn_brace_style(), config.where_density()) {
2313         (BraceStyle::AlwaysNextLine, _) => true,
2314         (_, Density::Compressed) if where_clause.predicates.len() == 1 => false,
2315         (_, Density::CompressedIfEmpty) if where_clause.predicates.len() == 1 && !has_body => false,
2316         (BraceStyle::SameLineWhere, _) if !where_clause.predicates.is_empty() => true,
2317         _ => false,
2318     }
2319 }
2320
2321 fn rewrite_generics(
2322     context: &RewriteContext,
2323     generics: &ast::Generics,
2324     shape: Shape,
2325     span: Span,
2326 ) -> Option<String> {
2327     let g_shape = try_opt!(generics_shape_from_config(context.config, shape, 0));
2328     let one_line_width = shape.width.checked_sub(2).unwrap_or(0);
2329     rewrite_generics_inner(context, generics, g_shape, one_line_width, span).or_else(|| {
2330         rewrite_generics_inner(context, generics, g_shape, 0, span)
2331     })
2332 }
2333
2334 fn rewrite_generics_inner(
2335     context: &RewriteContext,
2336     generics: &ast::Generics,
2337     shape: Shape,
2338     one_line_width: usize,
2339     span: Span,
2340 ) -> Option<String> {
2341     // FIXME: convert bounds to where clauses where they get too big or if
2342     // there is a where clause at all.
2343     let lifetimes: &[_] = &generics.lifetimes;
2344     let tys: &[_] = &generics.ty_params;
2345     if lifetimes.is_empty() && tys.is_empty() {
2346         return Some(String::new());
2347     }
2348
2349     // Strings for the generics.
2350     let lt_strs = lifetimes.iter().map(|lt| lt.rewrite(context, shape));
2351     let ty_strs = tys.iter().map(|ty_param| ty_param.rewrite(context, shape));
2352
2353     // Extract comments between generics.
2354     let lt_spans = lifetimes.iter().map(|l| {
2355         let hi = if l.bounds.is_empty() {
2356             l.lifetime.span.hi
2357         } else {
2358             l.bounds[l.bounds.len() - 1].span.hi
2359         };
2360         mk_sp(l.lifetime.span.lo, hi)
2361     });
2362     let ty_spans = tys.iter().map(|ty| ty.span());
2363
2364     let items = itemize_list(
2365         context.codemap,
2366         lt_spans.chain(ty_spans).zip(lt_strs.chain(ty_strs)),
2367         ">",
2368         |&(sp, _)| sp.lo,
2369         |&(sp, _)| sp.hi,
2370         // FIXME: don't clone
2371         |&(_, ref str)| str.clone(),
2372         context.codemap.span_after(span, "<"),
2373         span.hi,
2374         false,
2375     );
2376     format_generics_item_list(context, items, shape, one_line_width)
2377 }
2378
2379 pub fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
2380     match config.generics_indent() {
2381         IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
2382         IndentStyle::Block => {
2383             // 1 = ","
2384             shape
2385                 .block()
2386                 .block_indent(config.tab_spaces())
2387                 .with_max_width(config)
2388                 .sub_width(1)
2389         }
2390     }
2391 }
2392
2393 pub fn format_generics_item_list<I>(
2394     context: &RewriteContext,
2395     items: I,
2396     shape: Shape,
2397     one_line_budget: usize,
2398 ) -> Option<String>
2399 where
2400     I: Iterator<Item = ListItem>,
2401 {
2402     let item_vec = items.collect::<Vec<_>>();
2403
2404     let tactic = definitive_tactic(
2405         &item_vec,
2406         ListTactic::HorizontalVertical,
2407         Separator::Comma,
2408         one_line_budget,
2409     );
2410     let fmt = ListFormatting {
2411         tactic: tactic,
2412         separator: ",",
2413         trailing_separator: if context.config.generics_indent() == IndentStyle::Visual {
2414             SeparatorTactic::Never
2415         } else {
2416             context.config.trailing_comma()
2417         },
2418         separator_place: SeparatorPlace::Back,
2419         shape: shape,
2420         ends_with_newline: tactic.ends_with_newline(context.config.generics_indent()),
2421         preserve_newline: true,
2422         config: context.config,
2423     };
2424
2425     let list_str = try_opt!(write_list(&item_vec, &fmt));
2426
2427     Some(wrap_generics_with_angle_brackets(
2428         context,
2429         &list_str,
2430         shape.indent,
2431     ))
2432 }
2433
2434 pub fn wrap_generics_with_angle_brackets(
2435     context: &RewriteContext,
2436     list_str: &str,
2437     list_offset: Indent,
2438 ) -> String {
2439     if context.config.generics_indent() == IndentStyle::Block &&
2440         (list_str.contains('\n') || list_str.ends_with(','))
2441     {
2442         format!(
2443             "<\n{}{}\n{}>",
2444             list_offset.to_string(context.config),
2445             list_str,
2446             list_offset
2447                 .block_unindent(context.config)
2448                 .to_string(context.config)
2449         )
2450     } else if context.config.spaces_within_angle_brackets() {
2451         format!("< {} >", list_str)
2452     } else {
2453         format!("<{}>", list_str)
2454     }
2455 }
2456
2457 fn rewrite_trait_bounds(
2458     context: &RewriteContext,
2459     type_param_bounds: &ast::TyParamBounds,
2460     shape: Shape,
2461 ) -> Option<String> {
2462     let bounds: &[_] = type_param_bounds;
2463
2464     if bounds.is_empty() {
2465         return Some(String::new());
2466     }
2467     let bound_str = try_opt!(
2468         bounds
2469             .iter()
2470             .map(|ty_bound| ty_bound.rewrite(&context, shape))
2471             .collect::<Option<Vec<_>>>()
2472     );
2473     Some(format!(": {}", join_bounds(context, shape, &bound_str)))
2474 }
2475
2476 fn rewrite_where_clause_rfc_style(
2477     context: &RewriteContext,
2478     where_clause: &ast::WhereClause,
2479     shape: Shape,
2480     terminator: &str,
2481     span_end: Option<BytePos>,
2482     span_end_before_where: BytePos,
2483     where_clause_option: WhereClauseOption,
2484 ) -> Option<String> {
2485     let block_shape = shape.block().with_max_width(context.config);
2486
2487     let (span_before, span_after) =
2488         missing_span_before_after_where(span_end_before_where, where_clause);
2489     let (comment_before, comment_after) = try_opt!(rewrite_comments_before_after_where(
2490         context,
2491         span_before,
2492         span_after,
2493         shape,
2494     ));
2495
2496     let starting_newline = if where_clause_option.snuggle && comment_before.is_empty() {
2497         " ".to_owned()
2498     } else {
2499         "\n".to_owned() + &block_shape.indent.to_string(context.config)
2500     };
2501
2502     let clause_shape = block_shape.block_indent(context.config.tab_spaces());
2503     // each clause on one line, trailing comma (except if suppress_comma)
2504     let span_start = where_clause.predicates[0].span().lo;
2505     // If we don't have the start of the next span, then use the end of the
2506     // predicates, but that means we miss comments.
2507     let len = where_clause.predicates.len();
2508     let end_of_preds = where_clause.predicates[len - 1].span().hi;
2509     let span_end = span_end.unwrap_or(end_of_preds);
2510     let items = itemize_list(
2511         context.codemap,
2512         where_clause.predicates.iter(),
2513         terminator,
2514         |pred| pred.span().lo,
2515         |pred| pred.span().hi,
2516         |pred| pred.rewrite(context, block_shape),
2517         span_start,
2518         span_end,
2519         false,
2520     );
2521     let comma_tactic = if where_clause_option.suppress_comma {
2522         SeparatorTactic::Never
2523     } else {
2524         context.config.trailing_comma()
2525     };
2526
2527     let fmt = ListFormatting {
2528         tactic: DefinitiveListTactic::Vertical,
2529         separator: ",",
2530         trailing_separator: comma_tactic,
2531         separator_place: SeparatorPlace::Back,
2532         shape: clause_shape,
2533         ends_with_newline: true,
2534         preserve_newline: true,
2535         config: context.config,
2536     };
2537     let preds_str = try_opt!(write_list(&items.collect::<Vec<_>>(), &fmt));
2538
2539     let comment_separator = |comment: &str, shape: Shape| if comment.is_empty() {
2540         String::new()
2541     } else {
2542         format!("\n{}", shape.indent.to_string(context.config))
2543     };
2544     let newline_before_where = comment_separator(&comment_before, shape);
2545     let newline_after_where = comment_separator(&comment_after, clause_shape);
2546
2547     // 6 = `where `
2548     let clause_sep = if where_clause_option.compress_where && comment_before.is_empty() &&
2549         comment_after.is_empty() && !preds_str.contains('\n') &&
2550         6 + preds_str.len() <= shape.width
2551     {
2552         String::from(" ")
2553     } else {
2554         format!("\n{}", clause_shape.indent.to_string(context.config))
2555     };
2556     Some(format!(
2557         "{}{}{}where{}{}{}{}",
2558         starting_newline,
2559         comment_before,
2560         newline_before_where,
2561         newline_after_where,
2562         comment_after,
2563         clause_sep,
2564         preds_str
2565     ))
2566 }
2567
2568 fn rewrite_where_clause(
2569     context: &RewriteContext,
2570     where_clause: &ast::WhereClause,
2571     brace_style: BraceStyle,
2572     shape: Shape,
2573     density: Density,
2574     terminator: &str,
2575     span_end: Option<BytePos>,
2576     span_end_before_where: BytePos,
2577     where_clause_option: WhereClauseOption,
2578 ) -> Option<String> {
2579     if where_clause.predicates.is_empty() {
2580         return Some(String::new());
2581     }
2582
2583     if context.config.where_style() == Style::Rfc {
2584         return rewrite_where_clause_rfc_style(
2585             context,
2586             where_clause,
2587             shape,
2588             terminator,
2589             span_end,
2590             span_end_before_where,
2591             where_clause_option,
2592         );
2593     }
2594
2595     let extra_indent = Indent::new(context.config.tab_spaces(), 0);
2596
2597     let offset = match context.config.where_pred_indent() {
2598         IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
2599         // 6 = "where ".len()
2600         IndentStyle::Visual => shape.indent + extra_indent + 6,
2601     };
2602     // FIXME: if where_pred_indent != Visual, then the budgets below might
2603     // be out by a char or two.
2604
2605     let budget = context.config.max_width() - offset.width();
2606     let span_start = where_clause.predicates[0].span().lo;
2607     // If we don't have the start of the next span, then use the end of the
2608     // predicates, but that means we miss comments.
2609     let len = where_clause.predicates.len();
2610     let end_of_preds = where_clause.predicates[len - 1].span().hi;
2611     let span_end = span_end.unwrap_or(end_of_preds);
2612     let items = itemize_list(
2613         context.codemap,
2614         where_clause.predicates.iter(),
2615         terminator,
2616         |pred| pred.span().lo,
2617         |pred| pred.span().hi,
2618         |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
2619         span_start,
2620         span_end,
2621         false,
2622     );
2623     let item_vec = items.collect::<Vec<_>>();
2624     // FIXME: we don't need to collect here if the where_layout isn't
2625     // HorizontalVertical.
2626     let tactic = definitive_tactic(
2627         &item_vec,
2628         context.config.where_layout(),
2629         Separator::Comma,
2630         budget,
2631     );
2632
2633     let mut comma_tactic = context.config.trailing_comma();
2634     // Kind of a hack because we don't usually have trailing commas in where clauses.
2635     if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
2636         comma_tactic = SeparatorTactic::Never;
2637     }
2638
2639     let fmt = ListFormatting {
2640         tactic: tactic,
2641         separator: ",",
2642         trailing_separator: comma_tactic,
2643         separator_place: SeparatorPlace::Back,
2644         shape: Shape::legacy(budget, offset),
2645         ends_with_newline: tactic.ends_with_newline(context.config.where_pred_indent()),
2646         preserve_newline: true,
2647         config: context.config,
2648     };
2649     let preds_str = try_opt!(write_list(&item_vec, &fmt));
2650
2651     let end_length = if terminator == "{" {
2652         // If the brace is on the next line we don't need to count it otherwise it needs two
2653         // characters " {"
2654         match brace_style {
2655             BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
2656             BraceStyle::PreferSameLine => 2,
2657         }
2658     } else if terminator == "=" {
2659         2
2660     } else {
2661         terminator.len()
2662     };
2663     if density == Density::Tall || preds_str.contains('\n') ||
2664         shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
2665     {
2666         Some(format!(
2667             "\n{}where {}",
2668             (shape.indent + extra_indent).to_string(context.config),
2669             preds_str
2670         ))
2671     } else {
2672         Some(format!(" where {}", preds_str))
2673     }
2674 }
2675
2676 fn missing_span_before_after_where(
2677     before_item_span_end: BytePos,
2678     where_clause: &ast::WhereClause,
2679 ) -> (Span, Span) {
2680     let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo);
2681     // 5 = `where`
2682     let pos_after_where = where_clause.span.lo + BytePos(5);
2683     let missing_span_after = mk_sp(pos_after_where, where_clause.predicates[0].span().lo);
2684     (missing_span_before, missing_span_after)
2685 }
2686
2687 fn rewrite_missing_comment_in_where(
2688     context: &RewriteContext,
2689     comment: &str,
2690     shape: Shape,
2691 ) -> Option<String> {
2692     let comment = comment.trim();
2693     if comment.is_empty() {
2694         Some(String::new())
2695     } else {
2696         rewrite_comment(comment, false, shape, context.config)
2697     }
2698 }
2699
2700 fn rewrite_comments_before_after_where(
2701     context: &RewriteContext,
2702     span_before_where: Span,
2703     span_after_where: Span,
2704     shape: Shape,
2705 ) -> Option<(String, String)> {
2706     let before_comment = try_opt!(rewrite_missing_comment_in_where(
2707         context,
2708         &context.snippet(span_before_where),
2709         shape,
2710     ));
2711     let after_comment = try_opt!(rewrite_missing_comment_in_where(
2712         context,
2713         &context.snippet(span_after_where),
2714         shape.block_indent(context.config.tab_spaces()),
2715     ));
2716     Some((before_comment, after_comment))
2717 }
2718
2719 fn format_header(item_name: &str, ident: ast::Ident, vis: &ast::Visibility) -> String {
2720     format!("{}{}{}", format_visibility(vis), item_name, ident)
2721 }
2722
2723 fn format_generics(
2724     context: &RewriteContext,
2725     generics: &ast::Generics,
2726     opener: &str,
2727     terminator: &str,
2728     brace_style: BraceStyle,
2729     force_same_line_brace: bool,
2730     offset: Indent,
2731     span: Span,
2732     used_width: usize,
2733 ) -> Option<String> {
2734     let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
2735     let mut result = try_opt!(rewrite_generics(context, generics, shape, span));
2736
2737     let same_line_brace = if !generics.where_clause.predicates.is_empty() || result.contains('\n') {
2738         let budget = context
2739             .config
2740             .max_width()
2741             .checked_sub(last_line_used_width(&result, offset.width()))
2742             .unwrap_or(0);
2743         let option = WhereClauseOption::snuggled(&result);
2744         let where_clause_str = try_opt!(rewrite_where_clause(
2745             context,
2746             &generics.where_clause,
2747             brace_style,
2748             Shape::legacy(budget, offset.block_only()),
2749             Density::Tall,
2750             terminator,
2751             Some(span.hi),
2752             generics.span.hi,
2753             option,
2754         ));
2755         result.push_str(&where_clause_str);
2756         force_same_line_brace || brace_style == BraceStyle::PreferSameLine ||
2757             (generics.where_clause.predicates.is_empty() && trimmed_last_line_width(&result) == 1)
2758     } else {
2759         force_same_line_brace || trimmed_last_line_width(&result) == 1 ||
2760             brace_style != BraceStyle::AlwaysNextLine
2761     };
2762     let total_used_width = last_line_used_width(&result, used_width);
2763     let remaining_budget = context
2764         .config
2765         .max_width()
2766         .checked_sub(total_used_width)
2767         .unwrap_or(0);
2768     // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
2769     // and hence we take the closer into account as well for one line budget.
2770     // We assume that the closer has the same length as the opener.
2771     let overhead = if force_same_line_brace {
2772         1 + opener.len() + opener.len()
2773     } else {
2774         1 + opener.len()
2775     };
2776     let forbid_same_line_brace = overhead > remaining_budget;
2777     if !forbid_same_line_brace && same_line_brace {
2778         result.push(' ');
2779     } else {
2780         result.push('\n');
2781         result.push_str(&offset.block_only().to_string(context.config));
2782     }
2783     result.push_str(opener);
2784
2785     Some(result)
2786 }
2787
2788 impl Rewrite for ast::ForeignItem {
2789     fn rewrite(&self, context: &RewriteContext, shape: Shape) -> Option<String> {
2790         let attrs_str = try_opt!(self.attrs.rewrite(context, shape));
2791         // Drop semicolon or it will be interpreted as comment.
2792         // FIXME: this may be a faulty span from libsyntax.
2793         let span = mk_sp(self.span.lo, self.span.hi - BytePos(1));
2794
2795         let item_str = try_opt!(match self.node {
2796             ast::ForeignItemKind::Fn(ref fn_decl, ref generics) => {
2797                 rewrite_fn_base(
2798                     context,
2799                     shape.indent,
2800                     self.ident,
2801                     fn_decl,
2802                     generics,
2803                     ast::Unsafety::Normal,
2804                     ast::Constness::NotConst,
2805                     ast::Defaultness::Final,
2806                     // These are not actually rust functions,
2807                     // but we format them as such.
2808                     abi::Abi::Rust,
2809                     &self.vis,
2810                     span,
2811                     false,
2812                     false,
2813                     false,
2814                 ).map(|(s, _)| format!("{};", s))
2815             }
2816             ast::ForeignItemKind::Static(ref ty, is_mutable) => {
2817                 // FIXME(#21): we're dropping potential comments in between the
2818                 // function keywords here.
2819                 let vis = format_visibility(&self.vis);
2820                 let mut_str = if is_mutable { "mut " } else { "" };
2821                 let prefix = format!("{}static {}{}:", vis, mut_str, self.ident);
2822                 // 1 = ;
2823                 let shape = try_opt!(shape.sub_width(1));
2824                 ty.rewrite(context, shape).map(|ty_str| {
2825                     // 1 = space between prefix and type.
2826                     let sep = if prefix.len() + ty_str.len() + 1 <= shape.width {
2827                         String::from(" ")
2828                     } else {
2829                         let nested_indent = shape.indent.block_indent(context.config);
2830                         format!("\n{}", nested_indent.to_string(context.config))
2831                     };
2832                     format!("{}{}{};", prefix, sep, ty_str)
2833                 })
2834             }
2835         });
2836
2837         let missing_span = if self.attrs.is_empty() {
2838             mk_sp(self.span.lo, self.span.lo)
2839         } else {
2840             mk_sp(self.attrs[self.attrs.len() - 1].span.hi, self.span.lo)
2841         };
2842         combine_strs_with_missing_comments(
2843             context,
2844             &attrs_str,
2845             &item_str,
2846             missing_span,
2847             shape,
2848             false,
2849         )
2850     }
2851 }