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