time_dilation/
lib.rs

1use std::time::{Duration, Instant};
2
3#[allow(dead_code)]
4fn format_duration(nanos: f64) -> String {
5    if nanos < 1_000.0 {
6        format!("{nanos:.2} ns")
7    } else if nanos < 100_000.0 {
8        format!("{:.2} μs", nanos / 1_000.0)
9    } else if nanos < 1_000_000_000.0 {
10        format!("{:.2} ms", nanos / 1_000_000.0)
11    } else {
12        format!("{:.2} s", nanos / 1_000_000_000.0)
13    }
14}
15
16pub enum Grade {
17    Great,
18    Good,
19    Warning,
20    Bad,
21}
22
23fn grade_from_nano(nanos: f64) -> Grade {
24    let ms = (nanos / 1_000_000.0) as u64;
25    if ms < 10 {
26        Grade::Great
27    } else if ms < 40 {
28        Grade::Good
29    } else if ms < 70 {
30        Grade::Warning
31    } else {
32        Grade::Bad
33    }
34}
35
36const RESET: &str = "\x1B[0m";
37const RED: &str = "\x1B[31m";
38const GREEN: &str = "\x1B[32m";
39const YELLOW_BOLD: &str = "\x1B[1;33m";
40const CYAN: &str = "\x1B[36m";
41const BLUE: &str = "\x1B[34m";
42
43#[cfg(feature = "enable_summary")]
44pub fn summary(name: &str, total_execution_time: Duration) {
45    let duration = total_execution_time;
46    let total_nanos = duration.as_nanos() as f64;
47
48    let grade = grade_from_nano(total_nanos);
49    let grade_color_string = match grade {
50        Grade::Great => GREEN,
51        Grade::Good => CYAN,
52        Grade::Warning => YELLOW_BOLD,
53        Grade::Bad => RED,
54    };
55
56    println!(
57        "timer '{}{}{}' completed in {}{}{}",
58        BLUE,
59        name,
60        RESET,
61        grade_color_string,
62        format_duration(total_nanos),
63        RESET,
64    );
65}
66
67/// A simple timer that records elapsed time from its creation until it's dropped.
68///
69/// If the `enable_summary` feature is active, it prints the elapsed time
70/// when dropped.
71#[derive(Debug)]
72pub struct ScopedTimer<'a> {
73    start: Instant,
74    #[allow(dead_code)]
75    name: &'a str,
76}
77
78impl<'a> ScopedTimer<'a> {
79    /// Creates a new timer and records the start time.
80    ///
81    /// # Arguments
82    ///
83    /// * `name` - A static string slice used to identify the timer in the summary output.
84    #[must_use]
85    pub fn new(name: &'a str) -> Self {
86        Self {
87            start: Instant::now(),
88            name,
89        }
90    }
91
92    /// Manually get the elapsed duration without dropping the timer.
93    #[must_use]
94    pub fn elapsed(&self) -> Duration {
95        self.start.elapsed()
96    }
97}
98
99impl Drop for ScopedTimer<'_> {
100    fn drop(&mut self) {
101        #[cfg(feature = "enable_summary")]
102        {
103            let elapsed = self.start.elapsed();
104            summary(self.name, elapsed);
105        }
106    }
107}