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