time_dilation/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/piot/time-dilation
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5use std::time::{Duration, Instant};
6
7
8#[macro_export]
9macro_rules! time_block {
10    ($name:expr, $body:block) => {{
11        let _timer = $crate::ScopedTimer::new($name);
12        let __td_result = (|| $body )();
13        __td_result
14    }};
15}
16
17#[allow(dead_code)]
18fn format_duration(nanos: f64) -> String {
19    if nanos < 1_000.0 {
20        format!("{nanos:.2} ns")
21    } else if nanos < 100_000.0 {
22        format!("{:.2} us", nanos / 1_000.0)
23    } else if nanos < 1_000_000_000.0 {
24        format!("{:.2} ms", nanos / 1_000_000.0)
25    } else {
26        format!("{:.2} s", nanos / 1_000_000_000.0)
27    }
28}
29
30pub enum Grade {
31    Great,
32    Good,
33    Warning,
34    Bad,
35}
36
37#[cfg(feature = "enable_summary")]
38fn grade_from_nano(nanos: f64) -> Grade {
39    let ms = (nanos / 1_000_000.0) as u64;
40    if ms < 10 {
41        Grade::Great
42    } else if ms < 40 {
43        Grade::Good
44    } else if ms < 70 {
45        Grade::Warning
46    } else {
47        Grade::Bad
48    }
49}
50
51#[cfg(feature = "enable_summary")]
52
53const RESET: &str = "\x1B[0m";
54#[cfg(feature = "enable_summary")]
55const RED: &str = "\x1B[31m";
56#[cfg(feature = "enable_summary")]
57const GREEN: &str = "\x1B[32m";
58#[cfg(feature = "enable_summary")]
59const YELLOW_BOLD: &str = "\x1B[1;33m";
60#[cfg(feature = "enable_summary")]
61const CYAN: &str = "\x1B[36m";
62#[cfg(feature = "enable_summary")]
63const BLUE: &str = "\x1B[34m";
64
65
66#[cfg(feature = "enable_summary")]
67pub fn summary(name: &str, total_execution_time: Duration) {
68    let duration = total_execution_time;
69    let total_nanos = duration.as_nanos() as f64;
70
71    let grade = grade_from_nano(total_nanos);
72    let grade_color_string = match grade {
73        Grade::Great => GREEN,
74        Grade::Good => CYAN,
75        Grade::Warning => YELLOW_BOLD,
76        Grade::Bad => RED,
77    };
78
79    eprintln!(
80        "timer '{}{}{}' completed in {}{}{}",
81        BLUE,
82        name,
83        RESET,
84        grade_color_string,
85        format_duration(total_nanos),
86        RESET,
87    );
88}
89
90/// A simple timer that records elapsed time from its creation until it's dropped.
91///
92/// If the `enable_summary` feature is active, it prints the elapsed time
93/// when dropped.
94#[derive(Debug)]
95pub struct ScopedTimer<'a> {
96    start: Instant,
97    #[allow(dead_code)]
98    name: &'a str,
99}
100
101impl<'a> ScopedTimer<'a> {
102    /// Creates a new timer and records the start time.
103    ///
104    /// # Arguments
105    ///
106    /// * `name` - A static string slice used to identify the timer in the summary output.
107    #[must_use]
108    pub fn new(name: &'a str) -> Self {
109        Self {
110            start: Instant::now(),
111            name,
112        }
113    }
114
115    /// Manually get the elapsed duration without dropping the timer.
116    #[must_use]
117    pub fn elapsed(&self) -> Duration {
118        self.start.elapsed()
119    }
120}
121
122impl Drop for ScopedTimer<'_> {
123    fn drop(&mut self) {
124        #[cfg(feature = "enable_summary")]
125        {
126            let elapsed = self.start.elapsed();
127            summary(self.name, elapsed);
128        }
129    }
130}