Skip to main content

rustidy_ast/item/
struct_.rs

1//! Struct
2
3// Imports
4use {
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/// `Struct`
22#[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/// `StructStruct`
31#[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/// `StructFields`
60#[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/// `StructField`
78#[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	// Note: Nightly-only
104	#[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/// `TupleStruct`
123#[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/// `TupleFields`
177#[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/// `TupleField`
197#[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/// `TupleFieldInner`
207#[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}