1#![feature(
5 decl_macro,
6 never_type,
7 coverage_attribute,
8 macro_metavar_expr_concat,
9 trait_alias,
10 iter_advance_by
11)]
12
13mod tag;
15pub mod vec;
16pub mod whitespace;
17pub mod output;
18
19pub use {
21 self::{
22 output::{FormatMultilineOutput, FormatOutput},
23 tag::{FormatTag, FormatTags},
24 whitespace::{WhitespaceFormat, WhitespaceFormatKind},
25 },
26 rustidy_macros::{Format, Formattable},
27};
28
29use {
31 crate as rustidy_format,
32 arcstr::ArcStr,
33 core::{marker::PhantomData, ops::ControlFlow},
34 rustidy_util::{ArenaData, ArenaIdx, AstStr, Config, Oob, Whitespace},
35 std::borrow::Cow,
36};
37
38pub trait Formattable {
40 fn with_prefix_ws<O>(
47 &mut self,
48 ctx: &mut Context,
49 f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
50 ) -> Result<O, ControlFlow<()>>;
51
52 fn prefix_ws_is_pure(&mut self, ctx: &mut Context) -> Option<bool> {
54 self
55 .with_prefix_ws(ctx, &mut |ws, _ctx| ws.is_pure())
56 .ok()
57 }
58
59 fn prefix_ws_join_prefix(&mut self, ctx: &mut Context, ws: Whitespace) -> Result<(), Whitespace> {
61 let mut join_ws = Some(ws);
62 let _ = self.with_prefix_ws(ctx, &mut |ws, _| {
63 ws.join_prefix(
64 join_ws
65 .take()
66 .expect("`with_prefix_ws` called multiple times")
67 );
68 });
69
70 match join_ws {
71 Some(ws) => Err(ws),
72 None => Ok(()),
73 }
74 }
75
76 fn with_strings<O>(
83 &mut self,
84 ctx: &mut Context,
85 exclude_prefix_ws: bool,
86 f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
87 ) -> ControlFlow<O, bool>;
88
89 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput;
91}
92
93pub trait Format<PrefixWs, Args>: Formattable {
95 fn format(
100 &mut self,
101 ctx: &mut Context,
102 prefix_ws: PrefixWs,
103 args: Args
104 ) -> FormatOutput;
105}
106
107impl<T: Formattable> Formattable for &'_ mut T {
108 fn with_prefix_ws<O>(
109 &mut self,
110 ctx: &mut Context,
111 f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
112 ) -> Result<O, ControlFlow<()>> {
113 (**self).with_prefix_ws(ctx, f)
114 }
115
116 fn with_strings<O>(
117 &mut self,
118 ctx: &mut Context,
119 exclude_prefix_ws: bool,
120 f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
121 ) -> ControlFlow<O, bool> {
122 (**self)
123 .with_strings(ctx, exclude_prefix_ws, f)
124 }
125
126 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput {
127 (**self).format_output(ctx)
128 }
129}
130
131impl<T: Format<PrefixWs, Args>, PrefixWs, Args> Format<PrefixWs, Args> for &'_ mut T {
132 fn format(
133 &mut self,
134 ctx: &mut Context,
135 prefix_ws: PrefixWs,
136 args: Args
137 ) -> FormatOutput {
138 (**self).format(ctx, prefix_ws, args)
139 }
140}
141
142impl<T: Formattable> Formattable for Box<T> {
143 fn with_prefix_ws<O>(
144 &mut self,
145 ctx: &mut Context,
146 f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
147 ) -> Result<O, ControlFlow<()>> {
148 (**self).with_prefix_ws(ctx, f)
149 }
150
151 fn with_strings<O>(
152 &mut self,
153 ctx: &mut Context,
154 exclude_prefix_ws: bool,
155 f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
156 ) -> ControlFlow<O, bool> {
157 (**self)
158 .with_strings(ctx, exclude_prefix_ws, f)
159 }
160
161 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput {
162 (**self).format_output(ctx)
163 }
164}
165
166impl<T: Format<PrefixWs, Args>, PrefixWs, Args> Format<PrefixWs, Args> for Box<T> {
167 fn format(
168 &mut self,
169 ctx: &mut Context,
170 prefix_ws: PrefixWs,
171 args: Args
172 ) -> FormatOutput {
173 (**self).format(ctx, prefix_ws, args)
174 }
175}
176
177impl<T: Formattable> Formattable for Option<T> {
178 fn with_prefix_ws<O>(
179 &mut self,
180 ctx: &mut Context,
181 f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
182 ) -> Result<O, ControlFlow<()>> {
183 match self {
184 Self::Some(value) => value.with_prefix_ws(ctx, f),
185 Self::None => Err(ControlFlow::Continue(())),
186 }
187 }
188
189 fn with_strings<O>(
190 &mut self,
191 ctx: &mut Context,
192 exclude_prefix_ws: bool,
193 f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
194 ) -> ControlFlow<O, bool> {
195 match self {
196 Some(value) => value.with_strings(ctx, exclude_prefix_ws, f),
197 None => ControlFlow::Continue(true),
198 }
199 }
200
201 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput {
202 match self {
203 Self::Some(value) => value.format_output(ctx),
204 Self::None => FormatOutput::default(),
205 }
206 }
207}
208
209impl<T: Format<PrefixWs, Args>, PrefixWs, Args> Format<PrefixWs, Args> for Option<T> {
210 fn format(
211 &mut self,
212 ctx: &mut Context,
213 prefix_ws: PrefixWs,
214 args: Args
215 ) -> FormatOutput {
216 match self {
217 Some(value) => value.format(ctx, prefix_ws, args),
218 _ => FormatOutput::default(),
219 }
220 }
221}
222
223impl Formattable for ! {
224 fn with_prefix_ws<O>(
225 &mut self,
226 _ctx: &mut Context,
227 _f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
228 ) -> Result<O, ControlFlow<()>> {
229 *self
230 }
231
232 fn with_strings<O>(
233 &mut self,
234 _ctx: &mut Context,
235 _exclude_prefix_ws: bool,
236 _f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
237 ) -> ControlFlow<O, bool> {
238 *self
239 }
240
241 fn format_output(&mut self, _ctx: &mut Context) -> FormatOutput {
242 *self
243 }
244}
245
246impl<PrefixWs, Args> Format<PrefixWs, Args> for ! {
247 fn format(
248 &mut self,
249 _ctx: &mut Context,
250 _prefix_ws: PrefixWs,
251 _args: Args
252 ) -> FormatOutput {
253 *self
254 }
255}
256
257impl<T> Formattable for PhantomData<T> {
258 fn with_prefix_ws<O>(
259 &mut self,
260 _ctx: &mut Context,
261 _f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
262 ) -> Result<O, ControlFlow<()>> {
263 Err(ControlFlow::Continue(()))
264 }
265
266 fn with_strings<O>(
267 &mut self,
268 _ctx: &mut Context,
269 _exclude_prefix_ws: bool,
270 _f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
271 ) -> ControlFlow<O, bool> {
272 ControlFlow::Continue(true)
273 }
274
275 fn format_output(&mut self, _ctx: &mut Context) -> FormatOutput {
276 FormatOutput::default()
277 }
278}
279
280impl<T> Format<(), ()> for PhantomData<T> {
281 fn format(&mut self, _ctx: &mut Context, _prefix_ws: (), _args: ()) -> FormatOutput {
282 FormatOutput::default()
283 }
284}
285
286impl Formattable for () {
287 fn with_prefix_ws<O>(
288 &mut self,
289 _ctx: &mut Context,
290 _f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
291 ) -> Result<O, ControlFlow<()>> {
292 Err(ControlFlow::Continue(()))
293 }
294
295 fn with_strings<O>(
296 &mut self,
297 _ctx: &mut Context,
298 _exclude_prefix_ws: bool,
299 _f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
300 ) -> ControlFlow<O, bool> {
301 ControlFlow::Continue(true)
302 }
303
304 fn format_output(&mut self, _ctx: &mut Context) -> FormatOutput {
305 FormatOutput::default()
306 }
307}
308
309impl Format<(), ()> for () {
310 fn format(&mut self, _ctx: &mut Context, _prefix_ws: (), _args: ()) -> FormatOutput {
311 FormatOutput::default()
312 }
313}
314
315macro tuple_impl(
316 $N:literal, $($T:ident),* $(,)?
317) {
318 #[derive(Debug, Formattable, Format)]
319 #[expect(non_snake_case)]
320 struct ${concat( Tuple, $N )}< $( $T, )* > {
321 $( $T: $T, )*
322 }
323
324 #[automatically_derived]
325 #[expect(non_snake_case)]
326 impl< $($T: Formattable,)* > Formattable for ( $($T,)* ) {
327 fn with_prefix_ws<O>(
328 &mut self,
329 ctx: &mut Context,
330 f: &mut impl FnMut(&mut Whitespace, &mut Context) -> O,
331 ) -> Result<O, ControlFlow<()>> {
332 let ( $($T,)* ) = self;
333 ${concat( Tuple, $N )} { $( $T, )* }.with_prefix_ws(ctx, f)
334 }
335
336 fn with_strings<O>(
337 &mut self,
338 ctx: &mut Context,
339 exclude_prefix_ws: bool,
340 f: &mut impl FnMut(&mut AstStr, &mut Context) -> ControlFlow<O>,
341 ) -> ControlFlow<O, bool> {
342 let ( $($T,)* ) = self;
343 ${concat( Tuple, $N )} { $( $T, )* }.with_strings(ctx, exclude_prefix_ws, f)
344 }
345
346 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput {
347 let ( $($T,)* ) = self;
348 ${concat( Tuple, $N )} { $( $T, )* }.format_output(ctx)
349 }
350 }
351
352 #[automatically_derived]
354 #[expect(non_snake_case)]
355 impl< $($T: Format<WhitespaceConfig, ()>,)*> Format<WhitespaceConfig, ()> for ( $($T,)* ) {
356 fn format(&mut self, ctx: &mut Context, prefix_ws: WhitespaceConfig, args: ()) -> FormatOutput {
357 let ( $($T,)* ) = self;
358 ${concat( Tuple, $N )} { $( $T, )* }.format(ctx, prefix_ws, args)
359 }
360 }
361}
362
363tuple_impl! { 1, T0 }
364tuple_impl! { 2, T0, T1 }
365tuple_impl! { 3, T0, T1, T2 }
366
367impl Formattable for AstStr {
368 fn with_prefix_ws<O>(
369 &mut self,
370 _ctx: &mut Context,
371 _f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
372 ) -> Result<O, ControlFlow<()>> {
373 match self.is_empty() {
374 true => Err(ControlFlow::Continue(())),
375 false => Err(ControlFlow::Break(())),
376 }
377 }
378
379 fn with_strings<O>(
380 &mut self,
381 ctx: &mut Context,
382 _exclude_prefix_ws: bool,
383 f: &mut impl FnMut(&mut Self,&mut Context) -> ControlFlow<O>,
384 ) -> ControlFlow<O, bool> {
385 f(self, ctx)?;
386
387 ControlFlow::Continue(self.is_empty())
388 }
389
390 fn format_output(&mut self, _ctx: &mut Context) -> FormatOutput {
391 FormatOutput {
393 prefix_ws_len: None,
394 len: self.len(),
395 is_empty: self.is_empty(),
396 is_blank: self.is_blank(),
397 multiline: FormatMultilineOutput::from_ast_str_repr(self.repr())
398 }
399 }
400}
401
402impl<T: ArenaData + Formattable> Formattable for ArenaIdx<T> {
403 fn with_prefix_ws<O>(
404 &mut self,
405 ctx: &mut Context,
406 f: &mut impl FnMut(&mut Whitespace,&mut Context) -> O,
407 ) -> Result<O, ControlFlow<()>> {
408 (**self).with_prefix_ws(ctx, f)
409 }
410
411 fn with_strings<O>(
412 &mut self,
413 ctx: &mut Context,
414 exclude_prefix_ws: bool,
415 f: &mut impl FnMut(&mut AstStr,&mut Context) -> ControlFlow<O>,
416 ) -> ControlFlow<O, bool> {
417 (**self)
418 .with_strings(ctx, exclude_prefix_ws, f)
419 }
420
421 fn format_output(&mut self, ctx: &mut Context) -> FormatOutput {
422 (**self).format_output(ctx)
423 }
424}
425
426impl<T: ArenaData + Format<PrefixWs, Args>, PrefixWs, Args> Format<PrefixWs, Args> for ArenaIdx<T> {
427 fn format(
428 &mut self,
429 ctx: &mut Context,
430 prefix_ws: PrefixWs,
431 args: Args
432 ) -> FormatOutput {
433 (**self).format(ctx, prefix_ws, args)
434 }
435}
436
437pub struct Context<'a> {
439 input: ArcStr,
440 config: Cow<'a, Config>,
441 indent_depth: usize,
442 tags: Oob<'a, FormatTags>,
443}
444
445impl<'a> Context<'a> {
446 #[must_use]
448 pub fn new(input: impl Into<ArcStr>, config: &'a Config) -> Self {
449 Self {
450 input: input.into(),
451 config: Cow::Borrowed(config),
452 indent_depth: 0,
453 tags: Oob::Owned(FormatTags::new()),
454 }
455 }
456
457 pub fn format<T, PrefixWs>(&mut self, value: &mut T, prefix_ws: PrefixWs) -> FormatOutput
459 where
460 T: Format<PrefixWs, ()>
461 {
462 self.format_with(value, prefix_ws, ())
463 }
464
465 pub fn format_with<T, PrefixWs, A>(&mut self, value: &mut T, prefix_ws: PrefixWs, args: A) -> FormatOutput
467 where
468 T: Format<PrefixWs, A>
469 {
470 match self.config().skip {
471 true => value.format_output(self),
472 false => value.format(self, prefix_ws, args),
473 }
474 }
475
476 #[must_use]
478 pub const fn input(&self) -> &ArcStr {
479 &self.input
480 }
481
482 #[must_use]
484 pub fn config(&self) -> &Config {
485 &self.config
486 }
487
488 #[must_use]
490 pub fn config_mut(&mut self) -> &mut Config {
491 Cow::to_mut(&mut self.config)
492 }
493
494 #[must_use]
496 pub const fn indent(&self) -> usize {
497 self.indent_depth
498 }
499
500 pub fn with_indent<O>(&mut self, f: impl FnOnce(&mut Self) -> O) -> O {
502 self.with_indent_offset(1, f)
503 }
504
505 pub fn with_indent_if<O>(&mut self, pred: bool, f: impl FnOnce(&mut Self) -> O) -> O {
507 self.with_indent_offset_if(1, pred, f)
508 }
509
510 pub fn without_indent<O>(&mut self, f: impl for<'b> FnOnce(&'b mut Self) -> O) -> O {
513 self.with_indent_offset(-1, f)
514 }
515
516 pub fn without_indent_if<O>(
519 &mut self,
520 pred: bool,
521 f: impl for<'b> FnOnce(&'b mut Self) -> O
522 ) -> O {
523 self.with_indent_offset_if(-1, pred, f)
524 }
525
526 pub fn with_indent_offset<O>(
528 &mut self,
529 offset: i16,
530 f: impl for<'b> FnOnce(&'b mut Self) -> O
531 ) -> O {
532 let prev_depth = self.indent_depth;
533 self.indent_depth = prev_depth
534 .saturating_add_signed(isize::from(offset));
535 let output = f(self);
536 self.indent_depth = prev_depth;
537 output
538 }
539
540 pub fn with_indent_offset_if<O>(
542 &mut self,
543 offset: i16,
544 pred: bool,
545 f: impl for<'b> FnOnce(&'b mut Self) -> O,
546 ) -> O {
547 match pred {
548 true => self.with_indent_offset(offset, f),
549 false => f(self),
550 }
551 }
552
553 #[doc(hidden)]
554 pub const fn set_indent_depth(&mut self, indent_depth: usize) {
555 self.indent_depth = indent_depth;
556 }
557
558 pub fn sub_context(&mut self) -> Context<'_> {
562 Context {
563 input: ArcStr::clone(&self.input),
564 config: Cow::Borrowed(&self.config),
565 indent_depth: self.indent_depth,
566 tags: Oob::Borrowed(&mut self.tags),
567 }
568 }
569
570 pub fn add_tag(&mut self, tag: FormatTag) -> bool {
574 self.tags.add(tag)
575 }
576
577 pub fn remove_tag(&mut self, tag: FormatTag) -> bool {
581 self.tags.remove(tag)
582 }
583
584 pub fn set_tag(&mut self, tag: FormatTag, present: bool) -> bool {
588 self.tags.set(tag, present)
589 }
590
591 #[must_use]
593 pub fn has_tag(&self, tag: FormatTag) -> bool {
594 self.tags.contains(tag)
595 }
596
597 pub fn with_tag<O>(&mut self, tag: FormatTag, f: impl FnOnce(&mut Self) -> O) -> O {
599 let was_present = self.add_tag(tag);
600 let output = f(self);
601 self.set_tag(tag, was_present);
602
603 output
604 }
605
606 pub fn with_tag_if<O>(
608 &mut self,
609 pred: bool,
610 tag: FormatTag,
611 f: impl FnOnce(&mut Self) -> O
612 ) -> O {
613 match pred {
614 true => self.with_tag(tag, f),
615 false => f(self),
616 }
617 }
618
619 pub fn without_tag<O>(&mut self, tag: FormatTag, f: impl FnOnce(&mut Self) -> O) -> O {
621 let was_present = self.remove_tag(tag);
622 let output = f(self);
623 self.set_tag(tag, was_present);
624
625 output
626 }
627
628 pub fn without_tag_if<O>(
630 &mut self,
631 pred: bool,
632 tag: FormatTag,
633 f: impl FnOnce(&mut Self) -> O
634 ) -> O {
635 match pred {
636 true => self.without_tag(tag, f),
637 false => f(self),
638 }
639 }
640}
641
642#[derive(Clone, Copy, Debug)]
644pub struct WhitespaceConfig {
645 format: Option<WhitespaceFormatKind>,
646}
647
648const _: () = const {
649 assert!(size_of::<WhitespaceConfig>() <= 8);
650};