jupiter_rs/
fmt.rs

1use std::fmt::Write;
2use std::time::Duration;
3
4pub fn format_micros(micros: i32, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
5    return if micros < 1_000 {
6        write!(f, "{} us", micros)
7    } else if micros < 10_000 {
8        write!(f, "{:.2} ms", micros as f32 / 1_000.)
9    } else if micros < 100_000 {
10        write!(f, "{:.1} ms", micros as f32 / 1_000.)
11    } else if micros < 1_000_000 {
12        write!(f, "{} ms", micros / 1_000)
13    } else if micros < 10_000_000 {
14        write!(f, "{:.2} s", micros as f32 / 1_000_000.)
15    } else if micros < 100_000_000 {
16        write!(f, "{:.1} s", micros as f32 / 1_000_000.)
17    } else {
18        write!(f, "{} s", micros / 1_000_000)
19    };
20}
21
22pub fn format_short_duration(duration_in_micros: i32) -> String {
23    let mut result = String::new();
24    let _ = format_micros(duration_in_micros, &mut result);
25    return result;
26}
27
28pub fn format_bytes(size_in_bytes: usize, f: &mut dyn std::fmt::Write) -> std::fmt::Result {
29    if size_in_bytes == 1 {
30        return write!(f, "1 byte");
31    } else if size_in_bytes < 1024 {
32        return write!(f, "{} bytes", size_in_bytes);
33    }
34
35    let mut magnitude = 0;
36    let mut size = size_in_bytes as f32;
37    while size > 1024. && magnitude < 5 {
38        size /= 1024.;
39        magnitude += 1;
40    }
41
42    if size <= 10. {
43        write!(f, "{:2} ", size)?;
44    } else if size <= 100. {
45        write!(f, "{:1} ", size)?;
46    } else {
47        write!(f, "{:0} ", size)?;
48    }
49
50    match magnitude {
51        0 => write!(f, "Bytes"),
52        1 => write!(f, "KiB"),
53        2 => write!(f, "MiB"),
54        3 => write!(f, "GiB"),
55        4 => write!(f, "TiB"),
56        _ => write!(f, "PiB"),
57    }
58}
59
60pub fn format_size(size_in_bytes: usize) -> String {
61    let mut result = String::new();
62    let _ = format_bytes(size_in_bytes, &mut result);
63    return result;
64}
65
66pub fn parse_size(str: impl AsRef<str>) -> anyhow::Result<usize> {
67    lazy_static::lazy_static! {
68        static ref NUMBER_AND_SUFFIX: regex::Regex =
69            regex::Regex::new(r"^ *(\d+) *([kKmMgGtT]?).*").unwrap();
70    }
71
72    match NUMBER_AND_SUFFIX.captures(str.as_ref()) {
73        Some(captures) => {
74            let number = captures[1].parse::<usize>().unwrap();
75            match &captures[2] {
76                "k" | "K" => Ok(number * 1024),
77                "m" | "M" => Ok(number * 1024* 1024),
78                "g" | "G" => Ok(number * 1024* 1024* 1024),
79                "t" | "T" => Ok(number * 1024* 1024* 1024* 1024),
80                _ => Ok(number)
81            }
82        }
83        None => Err(anyhow::anyhow!("Cannot parse '{}' into a size expression. Only 'k', 'm', 'g' and 't' are accepted as suffixes.", str.as_ref()))
84    }
85}
86
87pub fn parse_duration(str: impl AsRef<str>) -> anyhow::Result<Duration> {
88    lazy_static::lazy_static! {
89        static ref NUMBER_AND_SUFFIX: regex::Regex =
90            regex::Regex::new(r"^ *(\d+) *((ms|s|m|h|d|MS|S|M|H|D)?).*").unwrap();
91    }
92
93    match NUMBER_AND_SUFFIX.captures(str.as_ref()) {
94        Some(captures) => {
95            let number = captures[1].parse::<u64>().unwrap();
96            match &captures[2] {
97                "s" | "S" => Ok(Duration::from_secs(number)),
98                "m" | "M" => Ok(Duration::from_secs(number * 60)),
99                "h" | "H" => Ok(Duration::from_secs(number * 60 * 60)),
100                "d" | "D" => Ok(Duration::from_secs(number * 60 * 60 * 24)),
101                _ => Ok(Duration::from_millis(number))
102            }
103        }
104        None => Err(anyhow::anyhow!("Cannot parse '{}' into a duration expression. Only 'ms', 's', 'm', 'h' and 'd' are accepted as suffixes.", str.as_ref()))
105    }
106}
107
108pub fn format_duration(duration: Duration) -> String {
109    let mut result = String::new();
110
111    let mut value = duration.as_millis();
112    {
113        let days = value / (1000 * 60 * 60 * 24);
114        if days > 0 {
115            let _ = write!(result, "{}d", days);
116            value = value % (1000 * 60 * 60 * 24);
117        }
118    }
119    {
120        let hours = value / (1000 * 60 * 60);
121        if hours > 0 {
122            if !result.is_empty() {
123                result.push(' ');
124            }
125            let _ = write!(result, "{}h", hours);
126            value = value % (1000 * 60 * 60);
127        }
128    }
129    {
130        let minutes = value / (1000 * 60);
131        if minutes > 0 {
132            if !result.is_empty() {
133                result.push(' ');
134            }
135            let _ = write!(result, "{}m", minutes);
136            value = value % (1000 * 60);
137        }
138    }
139    {
140        let seconds = value / 1000;
141        if seconds > 0 {
142            if !result.is_empty() {
143                result.push(' ');
144            }
145            let _ = write!(result, "{}s", seconds);
146            value = value % 1000 * 60;
147        }
148    }
149    if value > 0 {
150        if !result.is_empty() {
151            result.push(' ');
152        }
153        let _ = write!(result, "{}ms", value);
154    }
155
156    result
157}