1use {
5 crate::{
6 attr::{self, WithOuterAttributes, with},
7 expr::Expression,
8 token,
9 ty::Type,
10 util::{Braced, Parenthesized},
11 vis::Visibility,
12 },
13 super::function::{GenericParams, WhereClause},
14 rustidy_ast_util::{Identifier, PunctuatedTrailing, delimited, punct},
15 rustidy_format::{Format, FormatOutput, Formattable, WhitespaceConfig, WhitespaceFormat},
16 rustidy_parse::Parse,
17 rustidy_print::Print,
18 rustidy_util::Whitespace,
19};
20
21#[derive(PartialEq, Eq, Clone, Debug)]
23#[derive(serde::Serialize, serde::Deserialize)]
24#[derive(Parse, Formattable, Format, Print)]
25pub enum Struct {
26 Struct(StructStruct),
27 Tuple(TupleStruct),
28}
29
30#[derive(PartialEq, Eq, Clone, Debug)]
32#[derive(serde::Serialize, serde::Deserialize)]
33#[derive(Parse, Formattable, Format, Print)]
34pub struct StructStruct {
35 pub struct_: token::Struct,
36 #[format(prefix_ws = Whitespace::SINGLE)]
37 pub ident: Identifier,
38 #[format(prefix_ws = Whitespace::REMOVE)]
39 pub generics: Option<GenericParams>,
40 #[format(prefix_ws = Whitespace::INDENT)]
41 pub where_: Option<WhereClause>,
42 #[format(prefix_ws = match self.inner {
43 StructStructInner::Fields(_) => Whitespace::SINGLE,
44 StructStructInner::Semi(_) => Whitespace::REMOVE,
45 })]
46 pub inner: StructStructInner,
47}
48
49#[derive(PartialEq, Eq, Clone, Debug)]
50#[derive(strum::EnumIs)]
51#[derive(serde::Serialize, serde::Deserialize)]
52#[derive(Parse, Formattable, Format, Print)]
53pub enum StructStructInner {
54 #[format(args = delimited::fmt_indent_if_non_blank())]
55 Fields(Braced<Option<StructFields>>),
56 Semi(token::Semi),
57}
58
59#[derive(PartialEq, Eq, Clone, Debug)]
61#[derive(serde::Serialize, serde::Deserialize)]
62#[derive(Parse, Formattable, Format, Print)]
63pub struct StructFields(#[format(args = {
64 let max_ident_len = self.0
65 .values()
66 .map(|field| field.0.inner.ident.non_ws_len())
67 .max()
68 .expect("At least one element exists");
69 punct::fmt_with(
70 Whitespace::INDENT,
71 Whitespace::REMOVE,
72 StructFieldInnerArgs { max_ident_len },
73 ()
74 )
75})] PunctuatedTrailing<StructField, token::Comma>);
76
77#[derive(PartialEq, Eq, Clone, Debug)]
79#[derive(serde::Serialize, serde::Deserialize)]
80#[derive(Parse, Formattable, Format, Print)]
81#[format(args(ty = "StructFieldInnerArgs"))]
82pub struct StructField(
83 #[format(args = with::fmt_with(Whitespace::INDENT, args))]
84 pub WithOuterAttributes<StructFieldInner>,
85);
86
87#[derive(PartialEq, Eq, Clone, Debug)]
88#[derive(serde::Serialize, serde::Deserialize)]
89#[derive(Parse, Formattable, Format, Print)]
90#[format(args(ty = "StructFieldInnerArgs"))]
91pub struct StructFieldInner {
92 pub vis: Option<Visibility>,
93 #[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.vis.is_some()))]
94 pub ident: Identifier,
95 #[format(prefix_ws = Whitespace::REMOVE)]
96 pub colon: token::Colon,
97 #[format(prefix_ws = {
98 let ident_len = self.ident.non_ws_len();
99 let ty_prefix_ws_len = 1 + args.max_ident_len - ident_len;
100 Whitespace::spaces(ty_prefix_ws_len)
101 })]
102 pub ty: Type,
103 #[format(prefix_ws = Whitespace::SINGLE)]
105 pub eq: Option<StructFieldEq>,
106}
107
108#[derive(Clone, Copy, Debug)]
109struct StructFieldInnerArgs {
110 max_ident_len: usize,
111}
112
113#[derive(PartialEq, Eq, Clone, Debug)]
114#[derive(serde::Serialize, serde::Deserialize)]
115#[derive(Parse, Formattable, Format, Print)]
116pub struct StructFieldEq {
117 pub eq: token::Eq,
118 #[format(prefix_ws = Whitespace::SINGLE)]
119 pub expr: Expression,
120}
121
122#[derive(PartialEq, Eq, Clone, Debug)]
124#[derive(serde::Serialize, serde::Deserialize)]
125#[derive(Parse, Formattable, Format, Print)]
126pub struct TupleStruct {
127 pub struct_: token::Struct,
128 #[format(prefix_ws = Whitespace::SINGLE)]
129 pub ident: Identifier,
130 #[format(prefix_ws = Whitespace::REMOVE)]
131 pub generics: Option<GenericParams>,
132 #[format(prefix_ws = Whitespace::REMOVE)]
133 #[format(with = Self::format_fields)]
134 pub fields: Parenthesized<Option<TupleFields>>,
135 #[parse(fatal)]
136 #[format(prefix_ws = Whitespace::INDENT)]
137 pub where_: Option<WhereClause>,
138 #[format(prefix_ws = Whitespace::REMOVE)]
139 pub semi: token::Semi,
140}
141
142impl TupleStruct {
143 pub fn format_fields(
144 fields: &mut Parenthesized<Option<TupleFields>>,
145 ctx: &mut rustidy_format::Context,
146 prefix_ws: WhitespaceConfig,
147 _args: ()
148 ) -> FormatOutput {
149 if let Some(fields) = &mut fields.value {
150 fields.0.trailing = None;
151 }
152 let output = fields
153 .format(ctx, prefix_ws, delimited::FmtRemoveWith(
154 TupleFieldsFmt { field_prefix_ws: Whitespace::SINGLE }
155 ));
156
157 match output.len_non_multiline_ws() <= ctx.config().max_inline_tuple_struct_len {
158 true => output,
159 false => {
160 if let Some(fields) = &mut fields.value && fields.0.trailing.is_none() {
161 fields.0.trailing = Some(token::Comma::new());
162 }
163
164 fields.format(
165 ctx,
166 prefix_ws,
167 delimited::fmt_indent_if_non_blank_with_value(
168 TupleFieldsFmt { field_prefix_ws: Whitespace::INDENT }
169 )
170 )
171 },
172 }
173 }
174}
175
176#[derive(PartialEq, Eq, Clone, Debug)]
178#[derive(serde::Serialize, serde::Deserialize)]
179#[derive(Parse, Formattable, Format, Print)]
180#[format(args(ty = "TupleFieldsFmt"))]
181pub struct TupleFields(
182 #[format(args = punct::fmt_with(
183 args.field_prefix_ws,
184 Whitespace::REMOVE,
185 args,
186 ()
187 ))]
188 pub PunctuatedTrailing<TupleField, token::Comma>,
189);
190
191#[derive(Clone, Copy, Debug)]
192struct TupleFieldsFmt {
193 field_prefix_ws: WhitespaceConfig,
194}
195
196#[derive(PartialEq, Eq, Clone, Debug)]
198#[derive(serde::Serialize, serde::Deserialize)]
199#[derive(Parse, Formattable, Format, Print)]
200#[format(args(ty = "TupleFieldsFmt"))]
201pub struct TupleField(
202 #[format(args = attr::with::fmt(args.field_prefix_ws))]
203 pub WithOuterAttributes<TupleFieldInner>,
204);
205
206#[derive(PartialEq, Eq, Clone, Debug)]
208#[derive(serde::Serialize, serde::Deserialize)]
209#[derive(Parse, Formattable, Format, Print)]
210pub struct TupleFieldInner {
211 pub vis: Option<Visibility>,
212 #[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.vis.is_some()))]
213 pub ty: Type,
214}