|
2 | 2 |
|
3 | 3 | use itertools::Itertools; |
4 | 4 | use regex::Regex; |
5 | | -use rustc_ast::{AttrVec, visit}; |
| 5 | +use rustc_ast::visit; |
6 | 6 | use rustc_ast::{ast, ptr}; |
7 | 7 | use rustc_span::{BytePos, DUMMY_SP, Span, symbol}; |
8 | 8 | use std::borrow::Cow; |
@@ -519,13 +519,19 @@ impl<'a> FmtVisitor<'a> { |
519 | 519 | self.push_rewrite(static_parts.span, rewrite); |
520 | 520 | } |
521 | 521 |
|
522 | | - pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) { |
| 522 | + pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>, sort: bool) { |
523 | 523 | let is_tuple = match struct_parts.def { |
524 | 524 | ast::VariantData::Tuple(..) => true, |
525 | 525 | _ => false, |
526 | 526 | }; |
527 | | - let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None) |
528 | | - .map(|s| if is_tuple { s + ";" } else { s }); |
| 527 | + let rewrite = format_struct( |
| 528 | + &self.get_context(), |
| 529 | + struct_parts, |
| 530 | + self.block_indent, |
| 531 | + None, |
| 532 | + sort, |
| 533 | + ) |
| 534 | + .map(|s| if is_tuple { s + ";" } else { s }); |
529 | 535 | self.push_rewrite(struct_parts.span, rewrite); |
530 | 536 | } |
531 | 537 |
|
@@ -705,6 +711,7 @@ impl<'a> FmtVisitor<'a> { |
705 | 711 | &StructParts::from_variant(field, &context), |
706 | 712 | self.block_indent, |
707 | 713 | Some(one_line_width), |
| 714 | + false, |
708 | 715 | )?, |
709 | 716 | ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(), |
710 | 717 | }; |
@@ -1153,14 +1160,15 @@ fn format_struct( |
1153 | 1160 | struct_parts: &StructParts<'_>, |
1154 | 1161 | offset: Indent, |
1155 | 1162 | one_line_width: Option<usize>, |
| 1163 | + sort: bool, |
1156 | 1164 | ) -> Option<String> { |
1157 | 1165 | match struct_parts.def { |
1158 | 1166 | ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset), |
1159 | 1167 | ast::VariantData::Tuple(fields, _) => { |
1160 | 1168 | format_tuple_struct(context, struct_parts, fields, offset) |
1161 | 1169 | } |
1162 | 1170 | ast::VariantData::Struct { fields, .. } => { |
1163 | | - format_struct_struct(context, struct_parts, fields, offset, one_line_width) |
| 1171 | + format_struct_struct(context, struct_parts, fields, offset, one_line_width, sort) |
1164 | 1172 | } |
1165 | 1173 | } |
1166 | 1174 | } |
@@ -1439,6 +1447,7 @@ pub(crate) fn format_struct_struct( |
1439 | 1447 | fields: &[ast::FieldDef], |
1440 | 1448 | offset: Indent, |
1441 | 1449 | one_line_width: Option<usize>, |
| 1450 | + sort: bool, |
1442 | 1451 | ) -> Option<String> { |
1443 | 1452 | let mut result = String::with_capacity(1024); |
1444 | 1453 | let span = struct_parts.span; |
@@ -1507,12 +1516,36 @@ pub(crate) fn format_struct_struct( |
1507 | 1516 | let one_line_budget = |
1508 | 1517 | one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget)); |
1509 | 1518 |
|
| 1519 | + let ranks: Option<Vec<_>> = if sort { |
| 1520 | + // get the sequence of indices that would sort the vec |
| 1521 | + let indices: Vec<usize> = fields |
| 1522 | + .iter() |
| 1523 | + .enumerate() |
| 1524 | + .sorted_by(|(_, field_a), (_, field_b)| { |
| 1525 | + field_a |
| 1526 | + .ident |
| 1527 | + .zip(field_b.ident) |
| 1528 | + .map(|(a, b)| a.name.as_str().cmp(b.name.as_str())) |
| 1529 | + .unwrap_or(Ordering::Equal) |
| 1530 | + }) |
| 1531 | + .map(|(i, _)| i) |
| 1532 | + .collect(); |
| 1533 | + // create a vec with ranks for the fields, allowing for use in Itertools.sorted_by_key |
| 1534 | + let mut ranks = vec![0; indices.len()]; |
| 1535 | + for (rank, original_index) in indices.into_iter().enumerate() { |
| 1536 | + ranks[original_index] = rank; |
| 1537 | + } |
| 1538 | + Some(ranks) |
| 1539 | + } else { |
| 1540 | + None |
| 1541 | + }; |
1510 | 1542 | let items_str = rewrite_with_alignment( |
1511 | 1543 | fields, |
1512 | 1544 | context, |
1513 | 1545 | Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?, |
1514 | 1546 | mk_sp(body_lo, span.hi()), |
1515 | 1547 | one_line_budget, |
| 1548 | + ranks.as_ref().map(|v| v.as_slice()), |
1516 | 1549 | )?; |
1517 | 1550 |
|
1518 | 1551 | if !items_str.contains('\n') |
|
0 commit comments