1use std::{borrow::Cow, fmt, io, time::Duration};
2
3pub use crate::write::{Termcolor, Write, HTML};
4use crate::{markup, Markup, MarkupElement};
5
6#[derive(Clone, Copy)]
8pub enum MarkupElements<'a> {
9 Root,
10 Node(&'a Self, &'a [MarkupElement<'a>]),
11}
12
13impl<'a> MarkupElements<'a> {
14 pub fn for_each(
16 &self,
17 func: &mut impl FnMut(&'a [MarkupElement]) -> io::Result<()>,
18 ) -> io::Result<()> {
19 if let Self::Node(parent, elem) = self {
20 parent.for_each(func)?;
21 func(elem)?;
22 }
23
24 Ok(())
25 }
26
27 pub fn for_each_rev(
29 &self,
30 func: &mut impl FnMut(&'a [MarkupElement]) -> io::Result<()>,
31 ) -> io::Result<()> {
32 if let Self::Node(parent, elem) = self {
33 func(elem)?;
34 parent.for_each(func)?;
35 }
36
37 Ok(())
38 }
39}
40
41pub struct Formatter<'fmt> {
48 state: MarkupElements<'fmt>,
50 writer: &'fmt mut dyn Write,
52}
53
54impl<'fmt> Formatter<'fmt> {
55 pub fn new(writer: &'fmt mut dyn Write) -> Self {
57 Self {
58 state: MarkupElements::Root,
59 writer,
60 }
61 }
62
63 pub fn wrap_writer<'b: 'c, 'c>(
64 &'b mut self,
65 wrap: impl FnOnce(&'b mut dyn Write) -> &'c mut dyn Write,
66 ) -> Formatter<'c> {
67 Formatter {
68 state: self.state,
69 writer: wrap(self.writer),
70 }
71 }
72
73 fn with_elements<'b>(&'b mut self, elements: &'b [MarkupElement]) -> Formatter<'b> {
75 Formatter {
76 state: MarkupElements::Node(&self.state, elements),
77 writer: self.writer,
78 }
79 }
80
81 pub fn write_markup(&mut self, markup: Markup) -> io::Result<()> {
83 for node in markup.0 {
84 let mut fmt = self.with_elements(node.elements);
85 node.content.fmt(&mut fmt)?;
86 }
87
88 Ok(())
89 }
90
91 pub fn write_str(&mut self, content: &str) -> io::Result<()> {
93 self.writer.write_str(&self.state, content)
94 }
95
96 pub fn write_fmt(&mut self, content: fmt::Arguments) -> io::Result<()> {
98 self.writer.write_fmt(&self.state, content)
99 }
100}
101
102pub trait Display {
130 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()>;
131}
132
133impl<T> Display for &T
135where
136 T: Display + ?Sized,
137{
138 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
139 T::fmt(self, fmt)
140 }
141}
142
143impl<T> Display for Box<T>
145where
146 T: Display + ?Sized,
147{
148 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
149 T::fmt(&**self, fmt)
150 }
151}
152
153impl<T> Display for Cow<'_, T>
154where
155 T: Display + ToOwned + ?Sized,
156{
157 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
158 T::fmt(self, fmt)
159 }
160}
161
162impl Display for str {
165 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
166 fmt.write_str(self)
167 }
168}
169
170impl Display for String {
171 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
172 fmt.write_str(self)
173 }
174}
175
176impl Display for Markup<'_> {
178 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
179 fmt.write_markup(*self)
180 }
181}
182
183impl Display for std::fmt::Arguments<'_> {
184 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
185 fmt.write_fmt(*self)
186 }
187}
188
189macro_rules! impl_std_display {
192 ($ty:ty) => {
193 impl Display for $ty {
194 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
195 write!(fmt, "{self}")
196 }
197 }
198 };
199}
200
201impl_std_display!(char);
202impl_std_display!(i8);
203impl_std_display!(i16);
204impl_std_display!(i32);
205impl_std_display!(i64);
206impl_std_display!(i128);
207impl_std_display!(isize);
208impl_std_display!(u8);
209impl_std_display!(u16);
210impl_std_display!(u32);
211impl_std_display!(u64);
212impl_std_display!(u128);
213impl_std_display!(usize);
214
215impl Display for Duration {
216 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
217 use crate as biome_console;
218
219 let secs = self.as_secs();
220 if secs > 1 {
221 return fmt.write_markup(markup! {
222 {secs}<Dim>"s"</Dim>
223 });
224 }
225
226 let millis = self.as_millis();
227 if millis > 1 {
228 return fmt.write_markup(markup! {
229 {millis}<Dim>"ms"</Dim>
230 });
231 }
232
233 let micros = self.as_micros();
234 if micros > 1 {
235 return fmt.write_markup(markup! {
236 {micros}<Dim>"µs"</Dim>
237 });
238 }
239
240 let nanos = self.as_nanos();
241 fmt.write_markup(markup! {
242 {nanos}<Dim>"ns"</Dim>
243 })
244 }
245}
246
247#[repr(transparent)]
248#[derive(Clone, Copy, Debug)]
249pub struct Bytes(pub usize);
250
251impl std::fmt::Display for Bytes {
252 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
253 let Self(mut value) = *self;
254
255 if value < 1024 {
256 return write!(fmt, "{value} B");
257 }
258
259 const PREFIX: [char; 4] = ['K', 'M', 'G', 'T'];
260 let prefix = PREFIX
261 .into_iter()
262 .find(|_| {
263 let next_value = value / 1024;
264 if next_value < 1024 {
265 return true;
266 }
267
268 value = next_value;
269 false
270 })
271 .unwrap_or('T');
272
273 write!(fmt, "{:.1} {prefix}iB", value as f32 / 1024.0)
274 }
275}
276
277impl Display for Bytes {
278 fn fmt(&self, fmt: &mut Formatter) -> io::Result<()> {
279 write!(fmt, "{self}")
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use crate::fmt::Bytes;
286
287 #[test]
288 fn display_bytes() {
289 assert_eq!(Bytes(0).to_string(), "0 B");
291 assert_eq!(Bytes(27).to_string(), "27 B");
292 assert_eq!(Bytes(999).to_string(), "999 B");
293 assert_eq!(Bytes(1_000).to_string(), "1000 B");
294 assert_eq!(Bytes(1_023).to_string(), "1023 B");
295 assert_eq!(Bytes(1_024).to_string(), "1.0 KiB");
296 assert_eq!(Bytes(1_728).to_string(), "1.7 KiB");
297 assert_eq!(Bytes(110_592).to_string(), "108.0 KiB");
298 assert_eq!(Bytes(999_999).to_string(), "976.6 KiB");
299 assert_eq!(Bytes(7_077_888).to_string(), "6.8 MiB");
300 assert_eq!(Bytes(452_984_832).to_string(), "432.0 MiB");
301 assert_eq!(Bytes(28_991_029_248).to_string(), "27.0 GiB");
302 assert_eq!(Bytes(1_855_425_871_872).to_string(), "1.7 TiB");
303
304 #[cfg(target_pointer_width = "32")]
305 assert_eq!(Bytes(usize::MAX).to_string(), "4.0 GiB");
306 #[cfg(target_pointer_width = "64")]
307 assert_eq!(Bytes(usize::MAX).to_string(), "16384.0 TiB");
308 }
309}