Skip to main content

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}