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}