squid 2.0.3

A RISC-V emulator with AOT compilation for fuzzing
Documentation
#[cfg(feature = "tui")]
use core::time::Duration;
use std::{
    borrow::Cow,
    fmt::Display,
};

use colored::Colorize;
use indicatif::{
    ProgressBar,
    ProgressStyle,
};

/// The Logger is a helper struct that displays log messages to the terminal.
///
/// If the feature `tui` is activated, it also displays some nice TUI animations.
/// Use the functions [`Logger::info`], [`Logger::warning`], [`Logger::error`] to emit log messages
/// at the corresponding log levels.
pub struct Logger {
    bar: ProgressBar,
    running: bool,
    prefix: Option<String>,
}

#[cfg(feature = "tui")]
const ANIMATION: &[&str; 9] = &[".  ", ".. ", "...", " ..", "  .", " ..", "...", "..", ""];

#[cfg(not(feature = "tui"))]
const ANIMATION: &[&str; 2] = &["...", ""];

impl Logger {
    pub(crate) fn spinner() -> Self {
        let bar = ProgressBar::new_spinner();
        bar.set_style(
            ProgressStyle::with_template("{prefix:.magenta/red} {msg} {spinner}").unwrap().tick_strings(ANIMATION),
        );
        bar.set_prefix("[🦑]");

        Self {
            bar,
            running: false,
            prefix: None,
        }
    }

    pub(crate) fn set_prefix<S: Into<String>>(&mut self, prefix: S) {
        self.prefix = Some(prefix.into());
    }

    pub(crate) fn clear_prefix(&mut self) {
        self.prefix = None;
    }

    pub(crate) fn set_title(&mut self, title: impl Into<Cow<'static, str>>) {
        #[cfg(feature = "tui")]
        if !self.running {
            self.bar.enable_steady_tick(Duration::from_millis(100));
            self.running = true;
        }
        self.bar.set_message(title.into());
    }

    fn stop(&mut self) {
        if self.running {
            self.running = false;
            self.bar.finish_and_clear();
        }
    }

    fn emit<L: Display, S: AsRef<str>>(&self, level: L, msg: S) {
        if let Some(prefix) = &self.prefix {
            self.bar.println(format!("{} {}{}{} {}", level, "(".bold(), prefix.bold(), ")".bold(), msg.as_ref()))
        } else {
            self.bar.println(format!("{} {}", level, msg.as_ref()));
        }
    }

    /// Emit a log message with log level "INFO"
    pub fn info<S: AsRef<str>>(&self, msg: S) {
        self.emit("[🦑::INFO]".blue().bold(), msg);
    }

    /// Emit a log message with log level "WARN"
    pub fn warning<S: AsRef<str>>(&self, msg: S) {
        self.emit("[🦑::WARN]".yellow().bold(), msg);
    }

    /// Emit a log message with log level "DEBUG"
    pub fn debug<S: AsRef<str>>(&self, _msg: S) {
        #[cfg(debug_assertions)]
        {
            self.emit("[🦑::DEBUG]".black().on_white(), _msg);
        }
    }

    /// Emit a log message with log level "ERROR"
    pub fn error<S: AsRef<str>>(&self, msg: S) {
        self.emit("[🦑::ERROR]".red().bold(), msg);
    }
}

impl Drop for Logger {
    fn drop(&mut self) {
        self.stop();
    }
}

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

    #[test]
    #[ignore]
    fn test_style() {
        let mut logger = Logger::spinner();
        logger.set_title("TITLE HERE");
        logger.info("info");
        logger.warning("warning");
        logger.debug("debug");
        logger.error("error");

        std::thread::sleep(std::time::Duration::from_secs(5));
    }
}