Skip to main content

literator/
fmt.rs

1//! General formatting utilities.
2
3use core::fmt::{Debug, Display, Formatter, Result, Write};
4
5/// Polyfill for the unstable
6/// [`std::fmt::from_fn()`](https://doc.rust-lang.org/stable/std/fmt/fn.from_fn.html).
7pub fn from_fn<F>(f: F) -> FromFn<F> {
8    FromFn(f)
9}
10
11/// Helper for [`from_fn()`].
12pub struct FromFn<F>(F);
13
14impl<F> Display for FromFn<F>
15where
16    F: Fn(&mut Formatter) -> Result,
17{
18    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
19        (self.0)(f)
20    }
21}
22
23impl<F> Debug for FromFn<F>
24where
25    F: Fn(&mut Formatter) -> Result,
26{
27    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
28        (self.0)(f)
29    }
30}
31
32/// Adapter whose `Display` implementation displays `T` repeated `n` times.
33///
34/// This can be used to programmatically create indentation and spacing.
35///
36/// # Example
37///
38/// ```
39/// # use literator::fmt::repeat;
40/// assert_eq!(repeat('æ', 5).to_string(), "æææææ");
41/// ```
42pub fn repeat<T>(item: T, n: usize) -> Repeat<T> {
43    Repeat { item, n }
44}
45
46/// Helper for [`repeat()`].
47#[derive(Clone, Copy)]
48pub struct Repeat<T> {
49    /// The item to repeat.
50    pub item: T,
51    /// The number of times to display `item`.
52    pub n: usize,
53}
54
55impl<T: Display> Display for Repeat<T> {
56    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
57        for _ in 0..self.n {
58            self.item.fmt(f)?;
59        }
60        Ok(())
61    }
62}
63
64/// Wrapper type whose `Display` and `Debug` implementations call `F`.
65pub struct FormatWith<T, F> {
66    /// The item to pass to `F`.
67    pub item: T,
68    /// The function to call.
69    pub with: F,
70}
71
72impl<T, F> Display for FormatWith<T, F>
73where
74    F: Fn(&T, &mut Formatter) -> Result,
75{
76    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
77        (self.with)(&self.item, f)
78    }
79}
80
81impl<T, F> Debug for FormatWith<T, F>
82where
83    F: Fn(&T, &mut Formatter) -> Result,
84{
85    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
86        (self.with)(&self.item, f)
87    }
88}
89
90/// Display `T` in uppercase using [`char::to_uppercase()`]. Unicode compatible.
91///
92/// Due to current limitations in the standard library, this only works with
93/// `Display`, not other formatting traits.
94///
95/// # Example
96///
97/// ```
98/// # use literator::fmt::*;
99/// assert_eq!(Uppercase("abc").to_string(), "ABC");
100/// assert_eq!(Uppercase("äöå").to_string(), "ÄÖÅ");
101/// ```
102pub struct Uppercase<T>(pub T);
103
104/// Display `T` in uppercase using [`char::to_lowercase()`]. Unicode compatible.
105///
106/// Due to current limitations in the standard library, this only works with
107/// `Display`, not other formatting traits.
108///
109/// # Example
110///
111/// ```
112/// # use literator::fmt::*;
113/// assert_eq!(Lowercase("ABC").to_string(), "abc");
114/// assert_eq!(Lowercase("ÄÖÅ").to_string(), "äöå");
115/// ```
116pub struct Lowercase<T>(pub T);
117
118/// Display `T`, converting the first printed character to uppercase using
119/// [`char::to_uppercase()`]. Unicode compatible.
120///
121/// Due to current limitations in the standard library, this only works with
122/// `Display`, not other formatting traits.
123///
124/// # Example
125///
126/// ```
127/// # use literator::{fmt::*, Literator};
128/// assert_eq!(Capitalize("hello").to_string(), "Hello");
129/// assert_eq!(Capitalize("δεκαήμερο").to_string(), "Δεκαήμερο");
130/// assert_eq!(Capitalize("æblegrød").to_string(), "Æblegrød");
131///
132/// assert_eq!(
133///     ["hello", "δεκαήμερο", "æblegrød"]
134///         .iter()
135///         .map(Capitalize)
136///         .join(", ")
137///         .to_string(),
138///     "Hello, Δεκαήμερο, Æblegrød",
139/// );
140/// ```
141pub struct Capitalize<T>(pub T);
142
143impl<T: Display> Display for Uppercase<T> {
144    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
145        struct UppercaseWriter<'a, 'b>(&'a mut Formatter<'b>);
146        impl<'a, 'b> Write for UppercaseWriter<'a, 'b> {
147            fn write_str(&mut self, s: &str) -> Result {
148                // TODO: This can be optimized by specializing ranges of ASCII.
149                for ch in s.chars() {
150                    write!(self.0, "{}", ch.to_uppercase())?;
151                }
152                Ok(())
153            }
154
155            #[inline]
156            fn write_char(&mut self, c: char) -> Result {
157                write!(self.0, "{}", c.to_uppercase())
158            }
159        }
160
161        write!(&mut UppercaseWriter(f), "{}", self.0)
162    }
163}
164
165impl<T: Display> Display for Lowercase<T> {
166    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
167        struct LowercaseWriter<'a, 'b>(&'a mut Formatter<'b>);
168        impl<'a, 'b> Write for LowercaseWriter<'a, 'b> {
169            fn write_str(&mut self, s: &str) -> Result {
170                // TODO: This can be optimized by specializing ranges of ASCII.
171                for ch in s.chars() {
172                    write!(self.0, "{}", ch.to_lowercase())?;
173                }
174                Ok(())
175            }
176
177            #[inline]
178            fn write_char(&mut self, c: char) -> Result {
179                write!(self.0, "{}", c.to_lowercase())
180            }
181        }
182
183        write!(&mut LowercaseWriter(f), "{}", self.0)
184    }
185}
186
187impl<T: Display> Display for Capitalize<T> {
188    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
189        struct CapitalizeWriter<'a, 'b>(&'a mut Formatter<'b>, bool);
190        impl<'a, 'b> Write for CapitalizeWriter<'a, 'b> {
191            fn write_str(&mut self, s: &str) -> Result {
192                if !self.1 {
193                    let mut chars = s.chars();
194                    if let Some(first) = chars.next() {
195                        self.1 = true;
196                        write!(self.0, "{}", first.to_uppercase())?;
197                        self.0.write_str(chars.as_str())
198                    } else {
199                        Ok(())
200                    }
201                } else {
202                    self.0.write_str(s)
203                }
204            }
205
206            #[inline]
207            fn write_char(&mut self, c: char) -> Result {
208                if !self.1 {
209                    self.1 = true;
210                    write!(self.0, "{}", c.to_uppercase())
211                } else {
212                    write!(self.0, "{c}")
213                }
214            }
215        }
216
217        write!(&mut CapitalizeWriter(f, false), "{}", self.0)
218    }
219}
220
221/// Utility type with an empty `Display` implementation (no output).
222#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
223pub struct Empty;
224
225impl Display for Empty {
226    #[inline(always)]
227    fn fmt(&self, _: &mut Formatter<'_>) -> Result {
228        Ok(())
229    }
230}