xuko-misc 0.6.1

Miscellaneous utilities for xuko
Documentation
//! Profiling

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

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

    time_taken: Option<Duration>,
}

impl Profile {
    /// Create a new [`Profile`]
    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_duration`], except maps the result with [`Duration::as_millis`]
    pub fn elapsed(&mut self) -> Result<u128, SystemTimeError> {
        self.elapsed_duration().map(|d| d.as_millis())
    }

    /// Return how much time has passed since the start of this [`Profile`] as a [`Duration`]
    ///
    /// This can only fail once, as the result will be saved in the [`Profile`] structure.
    pub fn elapsed_duration(&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)
        }
    }

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

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

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

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

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