1pub mod const_;
5pub mod enum_;
6pub mod extern_block;
7pub mod extern_crate;
8pub mod function;
9pub mod implementation;
10pub mod macro_;
11pub mod macro_rules;
12pub mod mod_;
13pub mod static_;
14pub mod struct_;
15pub mod trait_;
16pub mod type_alias;
17pub mod union;
18pub mod use_;
19
20pub use self::{
22 const_::ConstantItem,
23 enum_::Enumeration,
24 extern_block::ExternBlock,
25 extern_crate::ExternCrate,
26 function::Function,
27 implementation::Implementation,
28 macro_::MacroInvocationSemi,
29 macro_rules::MacroRulesDefinition,
30 mod_::Module,
31 static_::StaticItem,
32 struct_::Struct,
33 trait_::Trait,
34 type_alias::TypeAlias,
35 union::Union,
36 use_::UseDeclaration,
37};
38
39use {
41 crate::attr,
42 super::{
43 attr::{
44 DelimTokenTree,
45 DelimTokenTreeInner,
46 OuterAttrOrDocComment,
47 WithOuterAttributes,
48 },
49 token,
50 util::{Braced, Parenthesized},
51 vis::Visibility,
52 },
53 core::mem,
54 rustidy_ast_util::{Identifier, PunctuatedTrailing, delimited, punct},
55 rustidy_format::{Format, Formattable, WhitespaceFormat},
56 rustidy_parse::Parse,
57 rustidy_print::Print,
58 rustidy_util::{ArenaIdx, Whitespace, decl_arena},
59};
60
61#[derive(PartialEq, Eq, Clone, Debug)]
62#[derive(serde::Serialize, serde::Deserialize)]
63#[derive(Parse, Formattable, Format, Print)]
64#[format(before_with = Self::merge_use)]
65pub struct Items(
66 #[format(args = rustidy_format::vec::args_prefix_ws(Whitespace::INDENT))]
67 pub Vec<Item>,
68);
69
70impl Items {
71 pub fn merge_use(&mut self, ctx: &mut rustidy_format::Context) {
72 #[expect(clippy::unused_peekable, reason = "We use `Peekable::next_if_map`")]
73 let mut items = mem::take(&mut self.0).into_iter().peekable();
74 while let Some(mut item) = items.next() {
75 item = match item.try_into_use_decl() {
76 Ok((attrs, vis, mut first_use_decl)) => {
77 while let Some(use_decl) = items.next_if_map(
78 |item| item
79 .try_into_just_use_decl(ctx, vis.as_ref())
80 ) {
81 first_use_decl.merge(use_decl);
82 }
83
84 Item(ArenaIdx::new(
85 WithOuterAttributes { attrs, inner: ItemInner::Vis(
86 VisItem { vis, inner: VisItemInner::Use(first_use_decl), }
87 ), }
88 ))
89 },
90 Err(item) => item,
91 };
92
93 self.0.push(item);
94 }
95 }
96}
97
98#[derive(PartialEq, Eq, Clone, Debug)]
100#[derive(serde::Serialize, serde::Deserialize)]
101#[derive(Parse, Formattable, Format, Print)]
102pub struct Item(
103 #[format(args = attr::with::fmt(Whitespace::INDENT))]
104 pub ArenaIdx<WithOuterAttributes<ItemInner>>,
105);
106
107impl Item {
108 #[expect(clippy::result_large_err, reason = "TODO")]
109 fn try_into_use_decl(self) -> Result<(Vec<OuterAttrOrDocComment>, Option<Visibility>, UseDeclaration), Self> {
110 self.0.try_take_map(|item| match item.inner {
111 ItemInner::Vis(VisItem { vis, inner: VisItemInner::Use(use_decl), }) => Ok((item.attrs, vis, use_decl)),
112 _ => Err(item),
113 }).map_err(Self)
114 }
115
116 #[expect(clippy::result_large_err, reason = "TODO")]
118 fn try_into_just_use_decl(
119 self,
120 ctx: &mut rustidy_format::Context,
121 expected_vis: Option<&Visibility>,
122 ) -> Result<UseDeclaration, Self> {
123 self.0.try_take_map(|mut item| {
124 if matches!(item.prefix_ws_is_pure(ctx), Some(false)) {
126 return Err(item);
127 }
128 if !item.attrs.is_empty() {
129 return Err(item);
130 }
131
132 match item.inner {
133 ItemInner::Vis(VisItem { vis, inner: VisItemInner::Use(use_decl), }) if vis.as_ref() == expected_vis => Ok(use_decl),
134 _ => Err(item),
135 }
136 }).map_err(Self)
137 }
138}
139
140#[derive(PartialEq, Eq, Clone, Debug)]
141#[derive(serde::Serialize, serde::Deserialize)]
142#[derive(Parse, Formattable, Format, Print)]
143#[parse(name = "an item")]
144pub enum ItemInner {
145 Vis(VisItem),
146 Macro(MacroItem),
147}
148
149decl_arena! { WithOuterAttributes<ItemInner> }
150
151#[derive(PartialEq, Eq, Clone, Debug)]
153#[derive(serde::Serialize, serde::Deserialize)]
154#[derive(Parse, Formattable, Format, Print)]
155pub struct VisItem {
156 pub vis: Option<Visibility>,
157 #[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.vis.is_some()))]
158 pub inner: VisItemInner,
159}
160
161#[derive(PartialEq, Eq, Clone, Debug)]
162#[derive(serde::Serialize, serde::Deserialize)]
163#[derive(Parse, Formattable, Format, Print)]
164pub enum VisItemInner {
165 Module(Module),
166 ExternCrate(ExternCrate),
167 Use(UseDeclaration),
168 Function(Function),
169 TypeAlias(TypeAlias),
170 Struct(Struct),
171 Enum(Enumeration),
172 Union(Union),
173 Constant(ConstantItem),
174 Static(StaticItem),
175 Trait(Trait),
176 Implementation(Implementation),
177 ExternBlock(ExternBlock),
178 DeclMacro(DeclMacro),
179}
180
181#[derive(PartialEq, Eq, Clone, Debug)]
183#[derive(serde::Serialize, serde::Deserialize)]
184#[derive(Parse, Formattable, Format, Print)]
185pub enum MacroItem {
186 Invocation(MacroInvocationSemi),
187 Definition(MacroRulesDefinition),
188}
189
190
191#[derive(PartialEq, Eq, Clone, Debug)]
193#[derive(serde::Serialize, serde::Deserialize)]
194#[derive(Parse, Formattable, Format, Print)]
195pub struct DeclMacro {
196 pub macro_: token::Macro,
197 #[parse(fatal)]
198 #[format(prefix_ws = Whitespace::SINGLE)]
199 pub ident: Identifier,
200 #[format(prefix_ws = match self.body {
201 DeclMacroBody::Branches(_) => Whitespace::SINGLE,
202 DeclMacroBody::Inline(_) => Whitespace::REMOVE,
203 })]
204 pub body: DeclMacroBody,
205}
206
207#[derive(PartialEq, Eq, Clone, Debug)]
208#[derive(serde::Serialize, serde::Deserialize)]
209#[derive(Parse, Formattable, Format, Print)]
210pub enum DeclMacroBody {
211 Branches(DeclMacroBodyBranches),
212 Inline(DeclMacroBodyInline),
213}
214
215#[derive(PartialEq, Eq, Clone, Debug)]
216#[derive(serde::Serialize, serde::Deserialize)]
217#[derive(Parse, Formattable, Format, Print)]
218pub struct DeclMacroBodyInline {
219 #[format(args = delimited::fmt_indent_if_non_blank())]
220 pub args: Parenthesized<DelimTokenTreeInner>,
221 #[format(prefix_ws = Whitespace::SINGLE)]
222 #[format(args = delimited::fmt_indent_if_non_blank())]
223 pub body: Braced<DelimTokenTreeInner>,
224}
225
226#[derive(PartialEq, Eq, Clone, Debug)]
227#[derive(serde::Serialize, serde::Deserialize)]
228#[derive(Parse, Formattable, Format, Print)]
229pub struct DeclMacroBodyBranches(
230 #[format(args = delimited::fmt_indent_if_non_blank())]
231 pub Braced<DeclMacroBodyBranchesInner>,
232);
233
234#[derive(PartialEq, Eq, Clone, Debug)]
235#[derive(serde::Serialize, serde::Deserialize)]
236#[derive(Parse, Formattable, Format, Print)]
237pub struct DeclMacroBodyBranchesInner(
238 #[format(args = punct::fmt(Whitespace::INDENT, Whitespace::REMOVE))]
239 pub PunctuatedTrailing<DeclMacroBranch, token::Comma>,
240);
241
242#[derive(PartialEq, Eq, Clone, Debug)]
243#[derive(serde::Serialize, serde::Deserialize)]
244#[derive(Parse, Formattable, Format, Print)]
245pub struct DeclMacroBranch {
246 pub extra: Option<DeclMacroBranchExtra>,
247 #[format(prefix_ws(expr = Whitespace::SINGLE, if_ = self.extra.is_some()))]
248 pub args: DelimTokenTree,
249 #[format(prefix_ws = Whitespace::SINGLE)]
250 pub arrow: token::FatArrow,
251 #[format(prefix_ws = Whitespace::SINGLE)]
252 pub body: DelimTokenTree,
253}
254
255#[derive(PartialEq, Eq, Clone, Debug)]
256#[derive(serde::Serialize, serde::Deserialize)]
257#[derive(Parse, Formattable, Format, Print)]
258pub enum DeclMacroBranchExtra {
259 Attr(DeclMacroBranchAttr),
260 Derive(DeclMacroBranchDerive),
261}
262
263#[derive(PartialEq, Eq, Clone, Debug)]
264#[derive(serde::Serialize, serde::Deserialize)]
265#[derive(Parse, Formattable, Format, Print)]
266pub struct DeclMacroBranchAttr {
267 pub attr: token::Attr,
268 #[format(prefix_ws = Whitespace::REMOVE)]
269 #[format(args = delimited::FmtRemove)]
270 pub args: Parenthesized<DelimTokenTreeInner>,
271}
272
273#[derive(PartialEq, Eq, Clone, Debug)]
274#[derive(serde::Serialize, serde::Deserialize)]
275#[derive(Parse, Formattable, Format, Print)]
276pub struct DeclMacroBranchDerive {
277 pub derive: token::Derive,
278 #[format(prefix_ws = Whitespace::REMOVE)]
279 #[format(args = delimited::FmtArgs {
280 indent: false,
281 value_non_blank: (),
282 value_blank: (),
283 suffix_non_blank: Whitespace::REMOVE,
284 suffix_blank: Whitespace::REMOVE,
285 prefix_args: (),
286 value_args: (),
287 suffix_args: ()
288 })]
289 pub args: Parenthesized<()>,
290}