Skip to content

Commit affbbe4

Browse files
feat: support struct/slice destructuring
1 parent a94fe44 commit affbbe4

File tree

3 files changed

+53
-18
lines changed

3 files changed

+53
-18
lines changed

src/formatting/expr.rs

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ pub(crate) fn format_expr(
106106
})
107107
}
108108
ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
109-
ast::ExprKind::Struct(ref path, ref fields, ref base) => rewrite_struct_lit(
109+
ast::ExprKind::Struct(ref path, ref fields, ref struct_rest) => rewrite_struct_lit(
110110
context,
111111
path,
112112
fields,
113-
base.as_ref().map(|e| &**e),
113+
struct_rest,
114114
&expr.attrs,
115115
expr.span,
116116
shape,
@@ -1589,19 +1589,15 @@ fn rewrite_index(
15891589
}
15901590
}
15911591

1592-
fn struct_lit_can_be_aligned(fields: &[ast::Field], base: Option<&ast::Expr>) -> bool {
1593-
if base.is_some() {
1594-
return false;
1595-
}
1596-
1597-
fields.iter().all(|field| !field.is_shorthand)
1592+
fn struct_lit_can_be_aligned(fields: &[ast::Field], has_base: bool) -> bool {
1593+
!has_base && fields.iter().all(|field| !field.is_shorthand)
15981594
}
15991595

16001596
fn rewrite_struct_lit<'a>(
16011597
context: &RewriteContext<'_>,
16021598
path: &ast::Path,
16031599
fields: &'a [ast::Field],
1604-
base: Option<&'a ast::Expr>,
1600+
struct_rest: &ast::StructRest,
16051601
attrs: &[ast::Attribute],
16061602
span: Span,
16071603
shape: Shape,
@@ -1611,22 +1607,29 @@ fn rewrite_struct_lit<'a>(
16111607
enum StructLitField<'a> {
16121608
Regular(&'a ast::Field),
16131609
Base(&'a ast::Expr),
1610+
Rest(&'a Span),
16141611
}
16151612

16161613
// 2 = " {".len()
16171614
let path_shape = shape.sub_width(2)?;
16181615
let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
16191616

1620-
if fields.is_empty() && base.is_none() {
1621-
return Some(format!("{} {{}}", path_str));
1622-
}
1617+
1618+
let has_base = match struct_rest {
1619+
ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
1620+
ast::StructRest::Rest(_) if fields.is_empty() => {
1621+
return Some(format!("{} {{ .. }}", path_str));
1622+
}
1623+
ast::StructRest::Base(_) => true,
1624+
_ => false,
1625+
};
16231626

16241627
// Foo { a: Foo } - indent is +3, width is -5.
16251628
let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)?;
16261629

16271630
let one_line_width = h_shape.map_or(0, |shape| shape.width);
16281631
let body_lo = context.snippet_provider.span_after(span, "{");
1629-
let fields_str = if struct_lit_can_be_aligned(fields, base)
1632+
let fields_str = if struct_lit_can_be_aligned(fields, has_base)
16301633
&& context.config.struct_field_align_threshold() > 0
16311634
{
16321635
rewrite_with_alignment(
@@ -1637,10 +1640,14 @@ fn rewrite_struct_lit<'a>(
16371640
one_line_width,
16381641
)?
16391642
} else {
1640-
let field_iter = fields
1641-
.iter()
1642-
.map(StructLitField::Regular)
1643-
.chain(base.into_iter().map(StructLitField::Base));
1643+
let field_iter = fields.iter().map(StructLitField::Regular).chain(
1644+
match struct_rest {
1645+
ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
1646+
ast::StructRest::Rest(span) => Some(StructLitField::Rest(span)),
1647+
ast::StructRest::None => None,
1648+
}
1649+
.into_iter(),
1650+
);
16441651

16451652
let span_lo = |item: &StructLitField<'_>| match *item {
16461653
StructLitField::Regular(field) => field.span().lo(),
@@ -1650,10 +1657,12 @@ fn rewrite_struct_lit<'a>(
16501657
let pos = snippet.find_uncommented("..").unwrap();
16511658
last_field_hi + BytePos(pos as u32)
16521659
}
1660+
StructLitField::Rest(span) => span.lo(),
16531661
};
16541662
let span_hi = |item: &StructLitField<'_>| match *item {
16551663
StructLitField::Regular(field) => field.span().hi(),
16561664
StructLitField::Base(expr) => expr.span.hi(),
1665+
StructLitField::Rest(span) => span.hi(),
16571666
};
16581667
let rewrite = |item: &StructLitField<'_>| match *item {
16591668
StructLitField::Regular(field) => {
@@ -1665,6 +1674,7 @@ fn rewrite_struct_lit<'a>(
16651674
expr.rewrite(context, v_shape.offset_left(2)?)
16661675
.map(|s| format!("..{}", s))
16671676
}
1677+
StructLitField::Rest(_) => Some("..".to_owned()),
16681678
};
16691679

16701680
let items = itemize_list(
@@ -1691,7 +1701,7 @@ fn rewrite_struct_lit<'a>(
16911701
nested_shape,
16921702
tactic,
16931703
context,
1694-
force_no_trailing_comma || base.is_some() || !context.use_block_indent(),
1704+
force_no_trailing_comma || has_base || !context.use_block_indent(),
16951705
);
16961706

16971707
write_list(&item_vec, &fmt)?

tests/source/structs.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ pub struct Foo {
1515
pub i: TypeForPublicField
1616
}
1717

18+
// Destructuring
19+
fn foo() {
20+
S { x: 5,
21+
..};
22+
Struct {..} = Struct { a: 1, b: 4 };
23+
Struct { a, .. } = Struct { a: 1, b: 2, c: 3};
24+
TupleStruct(a,.., b) = TupleStruct(1, 2);
25+
TupleStruct( ..) = TupleStruct(3, 4);
26+
TupleStruct(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, .., bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb) = TupleStruct(1, 2);
27+
}
28+
1829
// #1095
1930
struct S<T: /* comment */> {
2031
t: T,

tests/target/structs.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,20 @@ pub struct Foo {
1515
pub i: TypeForPublicField,
1616
}
1717

18+
// Destructuring
19+
fn foo() {
20+
S { x: 5, .. };
21+
Struct { .. } = Struct { a: 1, b: 4 };
22+
Struct { a, .. } = Struct { a: 1, b: 2, c: 3 };
23+
TupleStruct(a, .., b) = TupleStruct(1, 2);
24+
TupleStruct(..) = TupleStruct(3, 4);
25+
TupleStruct(
26+
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
27+
..,
28+
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
29+
) = TupleStruct(1, 2);
30+
}
31+
1832
// #1095
1933
struct S<T /* comment */> {
2034
t: T,

0 commit comments

Comments
 (0)