Skip to main content

entrenar/monitor/tui/render/
format.rs

1//! Formatting utilities for duration, bytes, and learning rate display.
2
3use std::time::Duration;
4
5pub fn format_duration(d: Duration) -> String {
6    let secs = d.as_secs();
7    format!("{:02}:{:02}:{:02}", secs / 3600, (secs % 3600) / 60, secs % 60)
8}
9
10#[allow(clippy::cast_precision_loss)]
11pub fn format_bytes(bytes: u64) -> String {
12    if bytes >= 1024 * 1024 * 1024 {
13        // Both conversions are u64-to-f64 which may lose precision for very
14        // large values, but formatting to one decimal place makes this benign.
15        let gb_f = bytes as f64 / (1024.0 * 1024.0 * 1024.0);
16        format!("{gb_f:.1}G")
17    } else if bytes >= 1024 * 1024 {
18        let mb = bytes / (1024 * 1024);
19        format!("{mb}M")
20    } else if bytes >= 1024 {
21        let kb = bytes / 1024;
22        format!("{kb}K")
23    } else {
24        format!("{bytes}B")
25    }
26}
27
28pub fn format_lr(lr: f32) -> String {
29    if !lr.is_finite() {
30        return "???".to_string();
31    }
32    let lr = lr.max(0.0);
33    if lr >= 0.01 {
34        format!("{lr:.4}")
35    } else if lr >= 0.001 {
36        format!("{lr:.5}")
37    } else {
38        format!("{lr:.6}")
39    }
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    fn test_format_duration() {
48        assert_eq!(format_duration(Duration::from_secs(3661)), "01:01:01");
49        assert_eq!(format_duration(Duration::from_secs(0)), "00:00:00");
50    }
51
52    #[test]
53    fn test_format_bytes() {
54        assert_eq!(format_bytes(1024 * 1024 * 1024), "1.0G");
55        assert_eq!(format_bytes(512 * 1024 * 1024), "512M");
56        assert_eq!(format_bytes(1024), "1K");
57    }
58
59    #[test]
60    fn test_format_lr() {
61        assert_eq!(format_lr(0.01), "0.0100");
62        assert_eq!(format_lr(0.001), "0.00100");
63        assert_eq!(format_lr(0.0001), "0.000100");
64    }
65}