1#![allow(unused_imports)]
18pub use inner::*;
19
20#[cfg(feature = "print-trace")]
21#[macro_use]
22pub mod inner {
23 use std::{sync::atomic::AtomicUsize, time::Instant};
24
25 pub use colored::Colorize;
26
27 pub static NUM_INDENT: AtomicUsize = AtomicUsize::new(0);
28 pub const PAD_CHAR: &str = "·";
29
30 pub struct TimerInfo {
31 pub msg: String,
32 pub time: Instant,
33 }
34
35 #[macro_export]
36 macro_rules! start_timer {
37 ($msg:expr) => {{
38 use std::{sync::atomic::Ordering, time::Instant};
39 use $crate::{compute_indent, Colorize, NUM_INDENT, PAD_CHAR};
40
41 let msg = $msg();
42 let start_info = "Start:".yellow().bold();
43 let indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
44 let indent = compute_indent(indent_amount);
45
46 println!("{}{:8} {}", indent, start_info, msg);
47 NUM_INDENT.fetch_add(1, Ordering::Relaxed);
48 $crate::TimerInfo {
49 msg: msg.to_string(),
50 time: Instant::now(),
51 }
52 }};
53 }
54
55 #[macro_export]
56 macro_rules! end_timer {
57 ($time:expr) => {{
58 end_timer!($time, || "");
59 }};
60 ($time:expr, $msg:expr) => {{
61 use std::sync::atomic::Ordering;
62 use $crate::{compute_indent, Colorize, NUM_INDENT, PAD_CHAR};
63
64 let time = $time.time;
65 let final_time = time.elapsed();
66 let final_time = {
67 let secs = final_time.as_secs();
68 let millis = final_time.subsec_millis();
69 let micros = final_time.subsec_micros() % 1000;
70 let nanos = final_time.subsec_nanos() % 1000;
71 if secs != 0 {
72 format!("{}.{}s", secs, millis).bold()
73 } else if millis > 0 {
74 format!("{}.{}ms", millis, micros).bold()
75 } else if micros > 0 {
76 format!("{}.{}µs", micros, nanos).bold()
77 } else {
78 format!("{}ns", final_time.subsec_nanos()).bold()
79 }
80 };
81
82 let end_info = "End:".green().bold();
83 let message = format!("{} {}", $time.msg, $msg());
84
85 NUM_INDENT.fetch_sub(1, Ordering::Relaxed);
86 let indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
87 let indent = compute_indent(indent_amount);
88
89 println!(
92 "{}{:8} {:.<pad$}{}",
93 indent,
94 end_info,
95 message,
96 final_time,
97 pad = 75 - indent_amount
98 );
99 }};
100 }
101
102 #[macro_export]
103 macro_rules! add_to_trace {
104 ($title:expr, $msg:expr) => {{
105 use std::sync::atomic::Ordering;
106 use $crate::{compute_indent, compute_indent_whitespace, Colorize, NUM_INDENT, PAD_CHAR};
107
108 let start_msg = "StartMsg".yellow().bold();
109 let end_msg = "EndMsg".green().bold();
110 let title = $title();
111 let start_msg = format!("{}: {}", start_msg, title);
112 let end_msg = format!("{}: {}", end_msg, title);
113
114 let start_indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
115 let start_indent = compute_indent(start_indent_amount);
116
117 let msg_indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed) + 2;
118 let msg_indent = compute_indent_whitespace(msg_indent_amount);
119 let mut final_message = "\n".to_string();
120 for line in $msg().lines() {
121 final_message += &format!("{}{}\n", msg_indent, line,);
122 }
123
124 println!("{}{}", start_indent, start_msg);
127 println!("{}{}", msg_indent, final_message,);
128 println!("{}{}", start_indent, end_msg);
129 }};
130 }
131
132 pub fn compute_indent_whitespace(indent_amount: usize) -> String {
133 let mut indent = String::new();
134 for _ in 0..indent_amount {
135 indent.push(' ');
136 }
137 indent
138 }
139
140 pub fn compute_indent(indent_amount: usize) -> String {
141 use std::env::var;
142 let mut indent = String::new();
143 let pad_string = match var("CLICOLOR") {
144 Ok(val) => {
145 if val == "0" {
146 " "
147 } else {
148 PAD_CHAR
149 }
150 }
151 Err(_) => PAD_CHAR,
152 };
153 for _ in 0..indent_amount {
154 indent.push_str(&pad_string.white());
155 }
156 indent
157 }
158}
159
160#[cfg(not(feature = "print-trace"))]
161#[macro_use]
162mod inner {
163 pub struct TimerInfo;
164
165 #[macro_export]
166 macro_rules! start_timer {
167 ($msg:expr) => {
168 $crate::TimerInfo
169 };
170 }
171 #[macro_export]
172 macro_rules! add_to_trace {
173 ($title:expr, $msg:expr) => {
174 let _ = $msg;
175 };
176 }
177
178 #[macro_export]
179 macro_rules! end_timer {
180 ($time:expr, $msg:expr) => {
181 let _ = $msg;
182 let _ = $time;
183 };
184 ($time:expr) => {
185 let _ = $time;
186 };
187 }
188}
189
190mod tests {
191 use super::*;
192
193 #[test]
194 fn print_start_end() {
195 let start = start_timer!(|| "Hello");
196 end_timer!(start);
197 }
198
199 #[test]
200 fn print_add() {
201 let start = start_timer!(|| "Hello");
202 add_to_trace!(|| "HelloMsg", || "Hello, I\nAm\nA\nMessage");
203 end_timer!(start);
204 }
205}