Skip to main content

canic_utils/
format.rs

1//!
2//! Small formatting helpers shared across logs and UI responses.
3//!
4
5///
6/// Truncate a string to at most `max_chars` Unicode scalar values.
7///
8/// Returns the original string when it already fits.
9///
10#[must_use]
11pub fn truncate(s: &str, max_chars: usize) -> String {
12    let mut chars = s.chars();
13    let truncated: String = chars.by_ref().take(max_chars).collect();
14
15    if chars.next().is_some() {
16        truncated
17    } else {
18        s.to_string()
19    }
20}
21
22///
23/// Format a byte size using IEC units with two decimal places.
24///
25/// Examples: `512.00 B`, `720.79 KiB`, `13.61 MiB`.
26///
27#[must_use]
28#[expect(clippy::cast_precision_loss)]
29pub fn byte_size(bytes: u64) -> String {
30    const UNITS: [&str; 5] = ["B", "KiB", "MiB", "GiB", "TiB"];
31
32    let mut value = bytes as f64;
33    let mut unit_index = 0usize;
34
35    while value >= 1024.0 && unit_index < UNITS.len() - 1 {
36        value /= 1024.0;
37        unit_index += 1;
38    }
39
40    format!("{value:.2} {}", UNITS[unit_index])
41}
42
43///
44/// TESTS
45///
46
47#[cfg(test)]
48mod tests {
49    use super::{byte_size, truncate};
50
51    #[test]
52    fn keeps_short_strings() {
53        assert_eq!(truncate("root", 9), "root");
54        assert_eq!(truncate("abcdefgh", 9), "abcdefgh");
55        assert_eq!(truncate("abcdefghi", 9), "abcdefghi");
56    }
57
58    #[test]
59    fn truncates_long_strings() {
60        assert_eq!(truncate("abcdefghijkl", 9), "abcdefghi");
61        assert_eq!(truncate("abcdefghijklmnopqrstuvwxyz", 9), "abcdefghi");
62    }
63
64    #[test]
65    fn formats_small_byte_sizes() {
66        assert_eq!(byte_size(0), "0.00 B");
67        assert_eq!(byte_size(512), "512.00 B");
68        assert_eq!(byte_size(1024), "1.00 KiB");
69    }
70
71    #[test]
72    fn formats_larger_byte_sizes() {
73        assert_eq!(byte_size(720_795), "703.90 KiB");
74        assert_eq!(byte_size(13_936_529), "13.29 MiB");
75        assert_eq!(byte_size(9_102_643), "8.68 MiB");
76    }
77}