1use 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#[derive(Debug)]
95pub struct ScopedTimer<'a> {
96 start: Instant,
97 #[allow(dead_code)]
98 name: &'a str,
99}
100
101impl<'a> ScopedTimer<'a> {
102 #[must_use]
108 pub fn new(name: &'a str) -> Self {
109 Self {
110 start: Instant::now(),
111 name,
112 }
113 }
114
115 #[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}