1pub fn size_str(num: u64) -> String {
6 if num < 1000 {
7 return format!("{} B", num);
8 }
9 let units = ["B", "KB", "MB", "GB", "TB", "PB"];
10 let mut val = num as f64;
11 let mut unit_idx = 0;
12 while val >= 1000.0 && unit_idx < units.len() - 1 {
13 val /= 1000.0;
14 unit_idx += 1;
15 }
16 format!("{:.2} {}", val, units[unit_idx])
17}
18
19pub fn speed_str(bps: u64) -> String {
22 if bps < 1000 {
23 return format!("{} b/s", bps);
24 }
25 let units = ["b/s", "Kb/s", "Mb/s", "Gb/s", "Tb/s"];
26 let mut val = bps as f64;
27 let mut unit_idx = 0;
28 while val >= 1000.0 && unit_idx < units.len() - 1 {
29 val /= 1000.0;
30 unit_idx += 1;
31 }
32 format!("{:.2} {}", val, units[unit_idx])
33}
34
35pub fn prettyhexrep(hash: &[u8]) -> String {
38 hash.iter()
39 .map(|b| format!("{:02x}", b))
40 .collect::<Vec<_>>()
41 .join("")
42}
43
44pub fn prettytime(secs: f64) -> String {
47 if secs < 0.0 {
48 return "now".into();
49 }
50 let total_secs = secs as u64;
51 if total_secs == 0 {
52 return "now".into();
53 }
54
55 let days = total_secs / 86400;
56 let hours = (total_secs % 86400) / 3600;
57 let minutes = (total_secs % 3600) / 60;
58 let secs = total_secs % 60;
59
60 let mut parts = Vec::new();
61 if days > 0 {
62 parts.push(format!("{}d", days));
63 }
64 if hours > 0 {
65 parts.push(format!("{}h", hours));
66 }
67 if minutes > 0 {
68 parts.push(format!("{}m", minutes));
69 }
70 if secs > 0 && days == 0 {
71 parts.push(format!("{}s", secs));
72 }
73
74 if parts.is_empty() {
75 "now".into()
76 } else {
77 parts.join(" ")
78 }
79}
80
81pub fn prettyfrequency(freq: f64) -> String {
84 if freq <= 0.0 {
85 return "none".into();
86 }
87 let per_minute = freq * 60.0;
89 let per_hour = freq * 3600.0;
90
91 if per_hour < 1.0 {
92 format!("{:.2}/h", per_hour)
93 } else if per_minute < 1.0 {
94 format!("{:.1}/h", per_hour)
95 } else {
96 format!("{:.1}/m", per_minute)
97 }
98}
99
100pub fn base32_encode(data: &[u8]) -> String {
102 const ALPHABET: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
103 let mut result = String::new();
104 let mut bits: u32 = 0;
105 let mut num_bits: u32 = 0;
106
107 for &byte in data {
108 bits = (bits << 8) | byte as u32;
109 num_bits += 8;
110 while num_bits >= 5 {
111 num_bits -= 5;
112 result.push(ALPHABET[((bits >> num_bits) & 0x1F) as usize] as char);
113 }
114 }
115 if num_bits > 0 {
116 result.push(ALPHABET[((bits << (5 - num_bits)) & 0x1F) as usize] as char);
117 }
118 while result.len() % 8 != 0 {
120 result.push('=');
121 }
122 result
123}
124
125pub fn base32_decode(s: &str) -> Option<Vec<u8>> {
127 let s = s.trim_end_matches('=');
128 let mut result = Vec::new();
129 let mut bits: u32 = 0;
130 let mut num_bits: u32 = 0;
131
132 for c in s.chars() {
133 let val = match c {
134 'A'..='Z' => c as u32 - 'A' as u32,
135 'a'..='z' => c as u32 - 'a' as u32,
136 '2'..='7' => c as u32 - '2' as u32 + 26,
137 _ => return None,
138 };
139 bits = (bits << 5) | val;
140 num_bits += 5;
141 if num_bits >= 8 {
142 num_bits -= 8;
143 result.push((bits >> num_bits) as u8);
144 }
145 }
146 Some(result)
147}
148
149#[cfg(test)]
150mod tests {
151 use super::*;
152
153 #[test]
154 fn test_size_str() {
155 assert_eq!(size_str(0), "0 B");
156 assert_eq!(size_str(500), "500 B");
157 assert_eq!(size_str(1234), "1.23 KB");
158 assert_eq!(size_str(1234567), "1.23 MB");
159 assert_eq!(size_str(1234567890), "1.23 GB");
160 }
161
162 #[test]
163 fn test_speed_str() {
164 assert_eq!(speed_str(500), "500 b/s");
165 assert_eq!(speed_str(10_000_000), "10.00 Mb/s");
166 assert_eq!(speed_str(1_000_000), "1.00 Mb/s");
167 }
168
169 #[test]
170 fn test_prettyhexrep() {
171 assert_eq!(prettyhexrep(&[0xab, 0xcd, 0xef]), "abcdef");
172 assert_eq!(prettyhexrep(&[0x00, 0xff]), "00ff");
173 }
174
175 #[test]
176 fn test_prettytime() {
177 assert_eq!(prettytime(0.0), "now");
178 assert_eq!(prettytime(30.0), "30s");
179 assert_eq!(prettytime(90.0), "1m 30s");
180 assert_eq!(prettytime(3661.0), "1h 1m 1s");
181 assert_eq!(prettytime(86400.0), "1d");
182 assert_eq!(prettytime(90061.0), "1d 1h 1m");
183 }
184
185 #[test]
186 fn test_prettyfrequency() {
187 assert_eq!(prettyfrequency(0.0), "none");
188 assert_eq!(prettyfrequency(-1.0), "none");
189 assert_eq!(prettyfrequency(1.0 / 3600.0), "1.0/h");
191 assert_eq!(prettyfrequency(10.0 / 60.0), "10.0/m");
193 }
194
195 #[test]
196 fn test_base32_encode() {
197 assert_eq!(base32_encode(b""), "");
198 assert_eq!(base32_encode(b"f"), "MY======");
199 assert_eq!(base32_encode(b"fo"), "MZXQ====");
200 assert_eq!(base32_encode(b"foo"), "MZXW6===");
201 assert_eq!(base32_encode(b"foob"), "MZXW6YQ=");
202 assert_eq!(base32_encode(b"fooba"), "MZXW6YTB");
203 assert_eq!(base32_encode(b"foobar"), "MZXW6YTBOI======");
204 }
205
206 #[test]
207 fn test_base32_decode() {
208 assert_eq!(base32_decode("").unwrap(), b"");
209 assert_eq!(base32_decode("MY======").unwrap(), b"f");
210 assert_eq!(base32_decode("MZXQ====").unwrap(), b"fo");
211 assert_eq!(base32_decode("MZXW6===").unwrap(), b"foo");
212 assert_eq!(base32_decode("MZXW6YQ=").unwrap(), b"foob");
213 assert_eq!(base32_decode("MZXW6YTB").unwrap(), b"fooba");
214 assert_eq!(base32_decode("MZXW6YTBOI======").unwrap(), b"foobar");
215 assert_eq!(base32_decode("mzxw6===").unwrap(), b"foo");
217 assert!(base32_decode("!!!").is_none());
219 }
220
221 #[test]
222 fn test_base32_roundtrip() {
223 let data = [0xDE, 0xAD, 0xBE, 0xEF, 0x01, 0x02, 0x03];
224 let encoded = base32_encode(&data);
225 let decoded = base32_decode(&encoded).unwrap();
226 assert_eq!(decoded, data);
227 }
228}