xuko 0.10.0

Rust utility library
Documentation
//! Timers

use std::time::{Duration, SystemTime, SystemTimeError};

/// The [`Timer`] structure stores how long it takes to do a task.
///
/// # Examples
///
/// ```
/// use std::{time::Duration, thread::sleep};
/// use xuko::timer::Timer;
///
/// let mut timer = Timer::new("sleep");
/// sleep(Duration::from_millis(10));
///
/// let elapsed = timer.elapsed_millis().unwrap();
/// assert!(elapsed >= 10);
///
/// sleep(Duration::from_millis(10));
/// // the result is saved!
/// assert_eq!(timer.elapsed_millis().unwrap(), elapsed);
/// ```
pub struct Timer {
    name: String,
    start: SystemTime,
    time_taken: Option<Duration>,
}

impl Timer {
    /// Create a new [`Timer`]
    pub fn new<S: AsRef<str>>(name: S) -> Self {
        Self {
            name: name.as_ref().to_owned(),
            start: SystemTime::now(),
            time_taken: None,
        }
    }

    /// Same as [`Self::elapsed`], except maps the result with [`Duration::as_millis`]
    pub fn elapsed_millis(&mut self) -> Result<u128, SystemTimeError> {
        self.elapsed().map(|d| d.as_millis())
    }

    /// Return how much time has passed since the start of this [`Timer`] as a [`Duration`]
    ///
    /// This can only fail once, as the result will be saved in the [`Timer`] structure.
    pub fn elapsed(&mut self) -> Result<Duration, SystemTimeError> {
        if let Some(d) = self.time_taken {
            Ok(d)
        } else {
            let d = self.start.elapsed()?;
            self.time_taken = Some(d);
            Ok(d)
        }
    }

    /// Same as [`Self::elapsed`] but ignoring the cache
    pub fn elapsed_no_cache(&self) -> Result<Duration, SystemTimeError> {
        self.start.elapsed()
    }

    /// Get the name of this [`Timer`]
    pub fn name(&self) -> &str {
        &self.name
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn elapsed_millis() {
        let mut timer = Timer::new("fake network request");

        std::thread::sleep(Duration::from_secs_f64(0.025));

        let elapsed = timer.elapsed_millis().expect("time went backwards!");
        assert!(elapsed >= 25);
        println!("`{}` took {elapsed} milliseconds", timer.name());
    }
}