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}