quicklatex 0.1.0

A program to help me write LaTeX quickly
Documentation
use std::time::{Duration, Instant};

use anyhow::{bail, Context, Error};

#[derive(Debug, PartialEq, Eq)]
enum Timer
{
    Running(Instant),
    Finished(Duration),
}

/// Holds all timers
///
/// Start a timer with [`Timers::start`](Self::start) and finish it
/// with [`Timers::stop`](Self::stop).
#[derive(Debug, Default, PartialEq, Eq)]
pub struct Timers
{
    timers: Vec<(String, Timer)>,
    max_name_length: usize,
}

impl Timers
{
    /// Starts a timer
    ///
    /// This function starts the timer with name `name`.
    ///
    /// # Errors
    /// This function returns an error if the timer was already used.
    /// A stopped timer is still in use.
    pub fn start(&mut self, name: &str) -> Result<(), Error>
    {
        if self.max_name_length < name.len()
        {
            self.max_name_length = name.len();
        }

        if self.timers.iter().any(|(other_name, _)| other_name == name)
        {
            bail!("Timer {name:?} already used");
        }
        self.timers.push((name.to_string(), Timer::Running(Instant::now())));

        Ok(())
    }

    /// Stops a timer
    ///
    /// This function stops the timer with name `name`.
    ///
    /// # Errors
    /// This function panics if the timer hasn't started yet or was
    /// already stopped.
    pub fn stop(&mut self, name: &str) -> Result<(), Error>
    {
        let index_of_timer = self
            .timers
            .iter()
            .enumerate()
            .find(|(_, (other_name, _))| other_name == name)
            .with_context(|| format!("Timer {name} wasn't started yet"))?
            .0;

        match &self.timers[index_of_timer].1
        {
            Timer::Running(start) =>
            {
                self.timers[index_of_timer] = (name.to_string(), Timer::Finished(start.elapsed()));
            }
            Timer::Finished(time) => bail!("Timer with name {name} already finished with time {time:?}"),
        }

        Ok(())
    }

    /// Prints all timers
    ///
    /// This function prints all timers (finished and not) with their name.
    pub fn print_all(&self)
    {
        println!();
        println!();
        println!();

        for (name, timer) in &self.timers
        {
            let additional_space = " ".repeat(self.max_name_length - name.len());

            match timer
            {
                Timer::Running(start) => println!(
                    "Timer {name:?} started {additional_space}{} seconds ago and is still running",
                    start.elapsed().as_secs_f64()
                ),
                Timer::Finished(time) => println!(
                    "Timer {name:?} ran for {additional_space}{} seconds",
                    time.as_secs_f64()
                ),
            }
        }

        println!();
        println!();
        println!();
    }
}

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

    #[test]
    fn timer_single_start()
    {
        Timers::default().start("abc").unwrap();
    }

    #[test]
    fn timer_double_start()
    {
        let mut timers = Timers::default();

        timers.start("def").unwrap();
        assert!(timers.start("def").is_err());
        assert!(timers.start("def").is_err());
        assert!(timers.start("def").is_err());
        timers.start("hij").unwrap();
    }

    #[test]
    fn timer_nested_run()
    {
        let mut timers = Timers::default();

        timers.start("a").unwrap();
        timers.start("b").unwrap();
        timers.stop("b").unwrap();
        timers.stop("a").unwrap();
    }

    #[test]
    fn timer_no_start()
    {
        assert!(Timers::default().stop("a").is_err());
    }

    #[test]
    fn timer_reinit()
    {
        let mut timers = Timers::default();

        timers.start("a").unwrap();
        timers.start("b").unwrap();
        timers.start("c").unwrap();
        timers.stop("a").unwrap();
        timers.stop("b").unwrap();

        let mut timers = Timers::default();

        timers.start("a").unwrap();
        timers.start("b").unwrap();
        timers.start("c").unwrap();
        timers.stop("a").unwrap();
        timers.stop("b").unwrap();
        timers.stop("c").unwrap();
    }

    #[test]
    #[should_panic = "called `Result::unwrap()` on an `Err` value: Timer c wasn't started yet"]
    fn timer_reinit_fail()
    {
        let mut timers = Timers::default();

        timers.start("a").unwrap();
        timers.start("b").unwrap();
        timers.start("c").unwrap();
        timers.stop("a").unwrap();
        timers.stop("b").unwrap();

        let mut timers = Timers::default();

        timers.stop("c").unwrap();
    }

    #[test]
    #[should_panic = "called `Result::unwrap()` on an `Err` value: Timer \"a\" already used"]
    fn timer_double()
    {
        let mut timers = Timers::default();

        timers.start("a").unwrap();
        timers.start("a").unwrap();
    }
}