Skip to content

Commit 4f32ce8

Browse files
feat: support struct/slice destructuring
1 parent 5b21602 commit 4f32ce8

File tree

3 files changed

+53
-18
lines changed

3 files changed

+53
-18
lines changed

src/expr.rs

+28-18
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,
@@ -1510,19 +1510,15 @@ fn rewrite_index(
15101510
}
15111511
}
15121512

1513-
fn struct_lit_can_be_aligned(fields: &[ast::Field], base: Option<&ast::Expr>) -> bool {
1514-
if base.is_some() {
1515-
return false;
1516-
}
1517-
1518-
fields.iter().all(|field| !field.is_shorthand)
1513+
fn struct_lit_can_be_aligned(fields: &[ast::Field], has_base: bool) -> bool {
1514+
!has_base && fields.iter().all(|field| !field.is_shorthand)
15191515
}
15201516

15211517
fn rewrite_struct_lit<'a>(
15221518
context: &RewriteContext<'_>,
15231519
path: &ast::Path,
15241520
fields: &'a [ast::Field],
1525-
base: Option<&'a ast::Expr>,
1521+
struct_rest: &ast::StructRest,
15261522
attrs: &[ast::Attribute],
15271523
span: Span,
15281524
shape: Shape,
@@ -1532,22 +1528,29 @@ fn rewrite_struct_lit<'a>(
15321528
enum StructLitField<'a> {
15331529
Regular(&'a ast::Field),
15341530
Base(&'a ast::Expr),
1531+
Rest(&'a Span),
15351532
}
15361533

15371534
// 2 = " {".len()
15381535
let path_shape = shape.sub_width(2)?;
15391536
let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
15401537

1541-
if fields.is_empty() && base.is_none() {
1542-
return Some(format!("{} {{}}", path_str));
1543-
}
1538+
1539+
let has_base = match struct_rest {
1540+
ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
1541+
ast::StructRest::Rest(_) if fields.is_empty() => {
1542+
return Some(format!("{} {{ .. }}", path_str));
1543+
}
1544+
ast::StructRest::Base(_) => true,
1545+
_ => false,
1546+
};
15441547

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

15481551
let one_line_width = h_shape.map_or(0, |shape| shape.width);
15491552
let body_lo = context.snippet_provider.span_after(span, "{");
1550-
let fields_str = if struct_lit_can_be_aligned(fields, base)
1553+
let fields_str = if struct_lit_can_be_aligned(fields, has_base)
15511554
&& context.config.struct_field_align_threshold() > 0
15521555
{
15531556
rewrite_with_alignment(
@@ -1558,10 +1561,14 @@ fn rewrite_struct_lit<'a>(
15581561
one_line_width,
15591562
)?
15601563
} else {
1561-
let field_iter = fields
1562-
.iter()
1563-
.map(StructLitField::Regular)
1564-
.chain(base.into_iter().map(StructLitField::Base));
1564+
let field_iter = fields.iter().map(StructLitField::Regular).chain(
1565+
match struct_rest {
1566+
ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
1567+
ast::StructRest::Rest(span) => Some(StructLitField::Rest(span)),
1568+
ast::StructRest::None => None,
1569+
}
1570+
.into_iter(),
1571+
);
15651572

15661573
let span_lo = |item: &StructLitField<'_>| match *item {
15671574
StructLitField::Regular(field) => field.span().lo(),
@@ -1571,10 +1578,12 @@ fn rewrite_struct_lit<'a>(
15711578
let pos = snippet.find_uncommented("..").unwrap();
15721579
last_field_hi + BytePos(pos as u32)
15731580
}
1581+
StructLitField::Rest(span) => span.lo(),
15741582
};
15751583
let span_hi = |item: &StructLitField<'_>| match *item {
15761584
StructLitField::Regular(field) => field.span().hi(),
15771585
StructLitField::Base(expr) => expr.span.hi(),
1586+
StructLitField::Rest(span) => span.hi(),
15781587
};
15791588
let rewrite = |item: &StructLitField<'_>| match *item {
15801589
StructLitField::Regular(field) => {
@@ -1586,6 +1595,7 @@ fn rewrite_struct_lit<'a>(
15861595
expr.rewrite(context, v_shape.offset_left(2)?)
15871596
.map(|s| format!("..{}", s))
15881597
}
1598+
StructLitField::Rest(_) => Some("..".to_owned()),
15891599
};
15901600

15911601
let items = itemize_list(
@@ -1612,7 +1622,7 @@ fn rewrite_struct_lit<'a>(
16121622
nested_shape,
16131623
tactic,
16141624
context,
1615-
force_no_trailing_comma || base.is_some() || !context.use_block_indent(),
1625+
force_no_trailing_comma || has_base || !context.use_block_indent(),
16161626
);
16171627

16181628
write_list(&item_vec, &fmt)?

tests/source/structs.rs

+11
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

+14
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)