gglib_core/utils/
timing.rs

1//! Timing utilities shared across crates.
2
3use std::time::Instant;
4
5/// Convert `Instant::elapsed()` to whole milliseconds, clamping to `u64::MAX`.
6///
7/// Used wherever `wait_ms` / `duration_ms` fields are populated so that the
8/// same `u64::try_from(…).unwrap_or(u64::MAX)` boilerplate is not repeated.
9#[inline]
10pub fn elapsed_ms(start: Instant) -> u64 {
11    u64::try_from(start.elapsed().as_millis()).unwrap_or(u64::MAX)
12}
13
14/// Format a millisecond duration into a compact human-readable string.
15///
16/// ```
17/// use gglib_core::utils::timing::format_duration_human;
18///
19/// assert_eq!(format_duration_human(0), "0ms");
20/// assert_eq!(format_duration_human(125), "125ms");
21/// assert_eq!(format_duration_human(1500), "1.5s");
22/// assert_eq!(format_duration_human(60_000), "1m 0s");
23/// assert_eq!(format_duration_human(135_000), "2m 15s");
24/// ```
25pub fn format_duration_human(ms: u64) -> String {
26    if ms < 1_000 {
27        format!("{ms}ms")
28    } else if ms < 60_000 {
29        #[allow(clippy::cast_precision_loss)] // ms values are ≤60k here; no precision issue
30        {
31            format!("{:.1}s", ms as f64 / 1_000.0)
32        }
33    } else {
34        let mins = ms / 60_000;
35        let secs = (ms % 60_000) / 1_000;
36        format!("{mins}m {secs}s")
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    #[test]
45    fn elapsed_ms_returns_small_value_immediately() {
46        let start = Instant::now();
47        let ms = elapsed_ms(start);
48        assert!(
49            ms < 1000,
50            "elapsed_ms should be near zero for an immediate call"
51        );
52    }
53
54    #[test]
55    fn duration_human_milliseconds() {
56        assert_eq!(format_duration_human(0), "0ms");
57        assert_eq!(format_duration_human(125), "125ms");
58        assert_eq!(format_duration_human(999), "999ms");
59    }
60
61    #[test]
62    fn duration_human_seconds() {
63        assert_eq!(format_duration_human(1_000), "1.0s");
64        assert_eq!(format_duration_human(1_500), "1.5s");
65        assert_eq!(format_duration_human(59_999), "60.0s");
66    }
67
68    #[test]
69    fn duration_human_minutes() {
70        assert_eq!(format_duration_human(60_000), "1m 0s");
71        assert_eq!(format_duration_human(135_000), "2m 15s");
72    }
73}