wasm_js/
progressbar.rs

1//! Fancy progress bar functionality.
2
3use anyhow::{bail, Error, Result};
4use console::style;
5use std::sync::atomic::{AtomicBool, AtomicU8, Ordering};
6
7#[repr(u8)]
8#[derive(Debug, Clone, Copy)]
9/// The maximum log level
10// The ordering is important: the least verbose must be at
11// the top and the most verbose at the bottom
12pub enum LogLevel {
13    /// Logs only error
14    Error,
15    /// Logs only warn and error
16    Warn,
17    /// Logs everything
18    Info,
19}
20
21impl std::str::FromStr for LogLevel {
22    type Err = Error;
23    fn from_str(s: &str) -> Result<Self> {
24        match s {
25            "error" => Ok(LogLevel::Error),
26            "warn" => Ok(LogLevel::Warn),
27            "info" => Ok(LogLevel::Info),
28            _ => bail!("Unknown log-level: {}", s),
29        }
30    }
31}
32
33/// Synchronized progress bar and status message printing.
34pub struct ProgressOutput {
35    quiet: AtomicBool,
36    log_level: AtomicU8,
37}
38
39impl ProgressOutput {
40    /// Returns a new ProgressOutput
41    pub const fn new() -> Self {
42        Self {
43            quiet: AtomicBool::new(false),
44            log_level: AtomicU8::new(LogLevel::Info as u8),
45        }
46    }
47
48    /// Print the given message.
49    fn message(&self, message: &str) {
50        eprintln!("{}", message);
51    }
52
53    /// Returns whether it should silence stdout or not
54    pub fn quiet(&self) -> bool {
55        self.quiet.load(Ordering::SeqCst)
56    }
57
58    /// Causes it to silence stdout
59    pub fn set_quiet(&self, quiet: bool) {
60        self.quiet.store(quiet, Ordering::SeqCst);
61    }
62
63    /// Returns whether the specified log level is enabled or not
64    pub fn is_log_enabled(&self, level: LogLevel) -> bool {
65        (level as u8) <= self.log_level.load(Ordering::SeqCst)
66    }
67
68    /// Sets the log level
69    pub fn set_log_level(&self, log_level: LogLevel) {
70        self.log_level.store(log_level as u8, Ordering::SeqCst);
71    }
72
73    /// Add an informational message.
74    pub fn info(&self, message: &str) {
75        if !self.quiet() && self.is_log_enabled(LogLevel::Info) {
76            let info = format!("{}: {}", style("[INFO]").bold().dim(), message,);
77            self.message(&info);
78        }
79    }
80
81    /// Add a warning message.
82    pub fn warn(&self, message: &str) {
83        if !self.quiet() && self.is_log_enabled(LogLevel::Warn) {
84            let warn = format!("{}: {}", style("[WARN]").bold().dim(), message);
85            self.message(&warn);
86        }
87    }
88
89    /// Add an error message.
90    pub fn error(&self, message: &str) {
91        if self.is_log_enabled(LogLevel::Error) {
92            let err = format!("{}: {}", style("[ERR]").bold().dim(), message);
93            self.message(&err);
94        }
95    }
96}
97
98impl Default for ProgressOutput {
99    fn default() -> Self {
100        ProgressOutput::new()
101    }
102}