dsi_progress_logger/
utils.rs

1/*
2 * SPDX-FileCopyrightText: 2023 Inria
3 * SPDX-FileCopyrightText: 2023 Sebastiano Vigna
4 *
5 * SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
6 */
7
8#[derive(Debug, Copy, Clone)]
9
10pub enum TimeUnit {
11    NanoSeconds,
12    MicroSeconds,
13    MilliSeconds,
14    Seconds,
15    Minutes,
16    Hours,
17    Days,
18}
19
20impl TimeUnit {
21    pub const VALUES: [TimeUnit; 7] = [
22        TimeUnit::NanoSeconds,
23        TimeUnit::MicroSeconds,
24        TimeUnit::MilliSeconds,
25        TimeUnit::Seconds,
26        TimeUnit::Minutes,
27        TimeUnit::Hours,
28        TimeUnit::Days,
29    ];
30
31    pub fn label(&self) -> &'static str {
32        match self {
33            TimeUnit::NanoSeconds => "ns",
34            TimeUnit::MicroSeconds => "μs",
35            TimeUnit::MilliSeconds => "ms",
36            TimeUnit::Seconds => "s",
37            TimeUnit::Minutes => "m",
38            TimeUnit::Hours => "h",
39            TimeUnit::Days => "d",
40        }
41    }
42
43    pub fn as_seconds(&self) -> f64 {
44        match self {
45            TimeUnit::NanoSeconds => 1.0e-9,
46            TimeUnit::MicroSeconds => 1.0e-6,
47            TimeUnit::MilliSeconds => 1.0e-3,
48            TimeUnit::Seconds => 1.0,
49            TimeUnit::Minutes => 60.0,
50            TimeUnit::Hours => 3600.0,
51            TimeUnit::Days => 86400.0,
52        }
53    }
54
55    pub fn nice_time_unit(seconds: f64) -> Self {
56        for unit in TimeUnit::VALUES.iter().rev() {
57            if seconds >= unit.as_seconds() {
58                return *unit;
59            }
60        }
61        TimeUnit::NanoSeconds
62    }
63
64    pub fn nice_speed_unit(seconds: f64) -> Self {
65        for unit in TimeUnit::VALUES[3..].iter() {
66            if seconds <= unit.as_seconds() {
67                return *unit;
68            }
69        }
70        TimeUnit::Days
71    }
72
73    pub fn pretty_print(milliseconds: u128) -> String {
74        let mut result = String::new();
75
76        if milliseconds < 1000 {
77            return format!("{}ms", milliseconds);
78        }
79
80        let mut seconds = milliseconds / 1000;
81
82        for unit in [TimeUnit::Days, TimeUnit::Hours, TimeUnit::Minutes] {
83            let to_seconds = unit.as_seconds() as u128;
84            if seconds >= to_seconds {
85                result.push_str(&format!("{}{} ", seconds / to_seconds, unit.label(),));
86                seconds %= to_seconds;
87            }
88        }
89
90        result.push_str(&format!("{}s", seconds));
91
92        result
93    }
94}
95
96pub fn scale(mut val: f64) -> (f64, &'static str) {
97    const UNITS: &[&str] = &["", "k", "M", "G", "T", "P", "E", "Z", "Y"];
98    for unit in UNITS.iter() {
99        if val < 1000.0 {
100            return (val, unit);
101        }
102        val /= 1000.0;
103    }
104
105    (val, "Y")
106}
107
108pub fn humanize(val: f64) -> String {
109    let (val, unit) = scale(val);
110    format!("{:.2}{}", val, unit)
111}
112
113#[cfg(test)]
114
115mod test {
116    use super::*;
117    #[test]
118    fn test_scale() {
119        assert_eq!(scale(1000.0), (1.0, "k"));
120        assert_eq!(scale(300_000.0), (300.0, "k"));
121        assert_eq!(scale(1_000_000_000.0), (1.0, "G"));
122    }
123    #[test]
124
125    fn test_humanize() {
126        assert_eq!(humanize(1000.0), "1.00k");
127        assert_eq!(humanize(12_345.0), "12.35k");
128        assert_eq!(humanize(1_234_567_890.0), "1.23G");
129    }
130}