Skip to main content

powerfmt/
ext.rs

1//! Extension traits.
2
3use core::fmt::{Alignment, Arguments, Formatter, Result, Write};
4
5mod sealed {
6    pub trait Sealed {}
7
8    impl Sealed for core::fmt::Formatter<'_> {}
9}
10
11/// An extension trait for [`core::fmt::Formatter`].
12pub trait FormatterExt: sealed::Sealed {
13    /// Writes the given arguments to the formatter, padding them with the given width. If `width`
14    /// is incorrect, the resulting output will not be the requested width.
15    fn pad_with_width(&mut self, width: usize, args: Arguments<'_>) -> Result;
16}
17
18impl FormatterExt for Formatter<'_> {
19    #[inline]
20    fn pad_with_width(&mut self, args_width: usize, args: Arguments<'_>) -> Result {
21        let Some(final_width) = self.width() else {
22            // The caller has not requested a width. Write the arguments as-is.
23            return self.write_fmt(args);
24        };
25        let Some(fill_width @ 1..) = final_width.checked_sub(args_width) else {
26            // No padding will be present. Write the arguments as-is.
27            return self.write_fmt(args);
28        };
29
30        let alignment = self.align().unwrap_or(Alignment::Left);
31        let fill = self.fill();
32
33        let left_fill_width = match alignment {
34            Alignment::Left => 0,
35            Alignment::Right => fill_width,
36            Alignment::Center => fill_width / 2,
37        };
38        let right_fill_width = match alignment {
39            Alignment::Left => fill_width,
40            Alignment::Right => 0,
41            // When the fill is not even on both sides, the extra fill goes on the right.
42            Alignment::Center => (fill_width + 1) / 2,
43        };
44
45        for _ in 0..left_fill_width {
46            self.write_char(fill)?;
47        }
48        self.write_fmt(args)?;
49        for _ in 0..right_fill_width {
50            self.write_char(fill)?;
51        }
52
53        Ok(())
54    }
55}