tea_timer/lib.rs
1//! # Tea Timer
2//!
3//! Tea Timer is a simple and efficient Rust library for measuring and reporting the duration of tasks. It provides an easy-to-use API for creating timers, measuring elapsed time, and formatting durations.
4//!
5//! ## Features
6//!
7//! - Create named timers
8//! - Measure elapsed time
9//! - Format durations in a human-readable format
10//! - Restart timers with new task names
11//! - Optional logging support using the `log` crate
12//!
13//! ## Installation
14//!
15//! Add this to your `Cargo.toml`:
16//!
17//! ```toml
18//! tea-timer = "0.1.0"
19//! ```
20//!
21//! ## Usage
22//!
23//! ### Macro Usage
24//! ```rust
25//!
26//! let result = tea_timer::took! {
27//! // ...any code
28//! };
29//! // this will print elapsed time and get result of thecode block
30//! ```
31//!
32//! ### Function Usage
33//! ```rust
34//! use tea_timer::took;
35//!
36//! let result = took(|| {
37//! // ...any code
38//! }, "task");
39//! // this will print elapsed time and get result of the function
40//! ```
41//!
42//! ### Basic Usage
43//! ```rust
44//! use tea_timer::Timer;
45//! use std::thread::sleep;
46//! use std::time::Duration;
47//!
48//! let mut timer = Timer::new("task");
49//! // Simulate some work with a sleep
50//! sleep(Duration::from_secs(2));
51//! // this will print elapsed time
52//! timer.elapsed();
53//! // Restart the timer with a new task name
54//! timer.restart("new_task");
55//! // Simulate more work
56//! sleep(Duration::from_millis(500));
57//! // Measure elapsed time again
58//! // consume timer and print elapsed time
59//! timer.stop();
60//! ```
61//!
62//! ### Logging Usage
63//! ```rust
64//! use tea_timer::Timer;
65//! use std::thread::sleep;
66//! use std::time::Duration;
67//!
68//! let mut timer = Timer::new("task");
69//! timer.log(); // This will log the elapsed time using the log crate
70//! ```
71
72mod display;
73
74use std::time::Instant;
75
76/// A struct for measuring and reporting the duration of tasks.
77///
78/// # Examples
79///
80/// ```
81/// use tea_timer::Timer;
82/// use std::thread::sleep;
83/// use std::time::Duration;
84///
85/// let timer = Timer::new("Some Task");
86/// sleep(Duration::from_millis(100));
87/// timer.stop(); // This will print the duration of the task
88/// ```
89pub struct Timer {
90 pub start_time: Instant,
91 pub task_name: String,
92}
93
94impl Default for Timer {
95 #[inline]
96 fn default() -> Self {
97 Timer::new("")
98 }
99}
100
101impl std::fmt::Debug for Timer {
102 #[inline]
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(f, "{}", self.elapsed_str())
105 }
106}
107
108impl std::fmt::Display for Timer {
109 #[inline]
110 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
111 write!(f, "{}", self.elapsed_str())
112 }
113}
114
115impl Timer {
116 /// Creates a new `Timer` instance with the given task name.
117 ///
118 /// # Examples
119 ///
120 /// ```
121 /// use tea_timer::Timer;
122 ///
123 /// let timer = Timer::new("My Task");
124 /// assert_eq!(timer.task_name, "My Task");
125 /// ```
126 #[inline]
127 pub fn new(task_name: &str) -> Self {
128 Timer {
129 start_time: Instant::now(),
130 task_name: task_name.to_string(),
131 }
132 }
133
134 /// Restarts the timer with a new task name.
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use tea_timer::Timer;
140 ///
141 /// let mut timer = Timer::new("Task 1");
142 /// // Do some work...
143 /// timer.restart("Task 2");
144 /// assert_eq!(timer.task_name, "Task 2");
145 /// // Timer now measures a new task
146 /// ```
147 #[inline]
148 pub fn restart(&mut self, task_name: &str) {
149 self.start_time = Instant::now();
150 self.task_name = task_name.to_string();
151 }
152
153 /// Returns the duration elapsed since the timer started.
154 ///
155 /// # Examples
156 ///
157 /// ```
158 /// use tea_timer::Timer;
159 /// use std::thread::sleep;
160 /// use std::time::Duration;
161 ///
162 /// let timer = Timer::new("Test Task");
163 /// sleep(Duration::from_millis(10));
164 /// assert!(timer.duration().as_millis() >= 10);
165 /// ```
166 #[inline]
167 pub fn duration(&self) -> std::time::Duration {
168 self.start_time.elapsed()
169 }
170
171 /// Returns a formatted string representation of the elapsed duration.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use tea_timer::Timer;
177 /// use std::thread::sleep;
178 /// use std::time::Duration;
179 ///
180 /// let timer = Timer::new("Test Task");
181 /// sleep(Duration::from_millis(10));
182 /// assert!(timer.duration_str().contains("ms"));
183 /// ```
184 #[inline]
185 pub fn duration_str(&self) -> String {
186 display::format_duration(self.duration())
187 }
188
189 #[inline]
190 pub fn elapsed_str(&self) -> String {
191 format!("{} elapsed {}", self.task_name, self.duration_str())
192 }
193
194 #[inline]
195 pub fn took_str(&self) -> String {
196 format!("{} took {}", self.task_name, self.duration_str())
197 }
198
199 /// Prints the elapsed time for the task.
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// use tea_timer::Timer;
205 /// use std::thread::sleep;
206 /// use std::time::Duration;
207 ///
208 /// let timer = Timer::new("Test Task");
209 /// sleep(Duration::from_millis(10));
210 /// timer.elapsed(); // This will print to stdout
211 /// ```
212 #[inline]
213 pub fn elapsed(&self) {
214 println!("{}", self.elapsed_str());
215 }
216
217 /// Stops the timer and prints the duration of the task.
218 ///
219 /// # Examples
220 ///
221 /// ```
222 /// use tea_timer::Timer;
223 /// use std::thread::sleep;
224 /// use std::time::Duration;
225 ///
226 /// let timer = Timer::new("Sleep Task");
227 /// sleep(Duration::from_millis(100));
228 /// timer.stop(); // This will print: "Sleep Task took 100.00ms" (approximately)
229 /// ```
230 #[inline]
231 pub fn stop(self) {
232 println!("{}", self.took_str());
233 }
234
235 /// Logs the elapsed time using the `log` crate.
236 ///
237 /// This method is only available when the `log` feature is enabled.
238 ///
239 /// # Examples
240 ///
241 /// ```
242 /// # #[cfg(feature = "log")]
243 /// # {
244 /// use tea_timer::Timer;
245 /// use std::thread::sleep;
246 /// use std::time::Duration;
247 ///
248 /// let timer = Timer::new("Log Task");
249 /// sleep(Duration::from_millis(10));
250 /// timer.log(); // This will log using the log crate
251 /// # }
252 /// ```
253 #[inline]
254 #[cfg(feature = "log")]
255 pub fn log(&self) {
256 log::info!("{}", self.elapsed_str());
257 }
258}
259
260#[inline]
261pub fn took<F: FnOnce() -> R, R>(f: F, task_name: &str) -> R {
262 let timer = Timer::new(task_name);
263 let result = f();
264 timer.stop();
265 result
266}
267
268#[inline]
269pub fn ltook<F: FnOnce() -> R, R>(f: F, task_name: &str) -> R {
270 let timer = Timer::new(task_name);
271 let result = f();
272 timer.log();
273 result
274}
275
276#[macro_export]
277macro_rules! took {
278 ($($tt:tt)*) => {
279 {
280 let timer = $crate::Timer::new("");
281 let res = {$($tt)*};
282 timer.stop();
283 res
284 }
285 };
286}
287
288#[macro_export]
289macro_rules! ltook {
290 ($($tt:tt)*) => {
291 {
292 let timer = $crate::Timer::new("");
293 let res = {$($tt)*};
294 timer.log();
295 res
296 }
297 };
298}
299
300#[cfg(test)]
301mod tests {
302 use super::*;
303 use std::thread::sleep;
304 use std::time::Duration;
305
306 #[test]
307 fn test_timer_new() {
308 let timer = Timer::new("Test Task");
309 assert_eq!(timer.task_name, "Test Task");
310 }
311
312 #[test]
313 fn test_timer_restart() {
314 let mut timer = Timer::new("Task 1");
315 timer.restart("Task 2");
316 assert_eq!(timer.task_name, "Task 2");
317 }
318
319 #[test]
320 fn test_timer_duration() {
321 let timer = Timer::new("Duration Test");
322 sleep(Duration::from_millis(10));
323 assert!(timer.duration().as_millis() >= 10);
324 }
325
326 #[test]
327 fn test_timer_duration_str() {
328 let timer = Timer::new("Duration Str Test");
329 sleep(Duration::from_millis(10));
330 assert!(timer.duration_str().contains("ms"));
331 }
332
333 #[test]
334 fn test_timer_default() {
335 let timer = Timer::default();
336 assert_eq!(timer.task_name, "");
337 }
338
339 #[test]
340 fn test_took() {
341 let result = took(
342 || {
343 sleep(Duration::from_millis(10));
344 42
345 },
346 "Test Task",
347 );
348 assert_eq!(result, 42);
349 }
350
351 #[test]
352 fn test_took_macro() {
353 let result = took! {
354 sleep(Duration::from_millis(10));
355 42
356 };
357 assert_eq!(result, 42);
358 }
359 // Note: We can't easily test the `stop` method as it prints to stdout.
360 // In a real-world scenario, we might want to refactor to return the duration
361 // instead of printing it, which would make it more testable.
362}