#[macro_use]
extern crate lazy_static;
#[cfg(feature = "colours")]
extern crate console;
use std::sync::RwLock;
lazy_static! {
static ref PREFIXES: RwLock<LogPrefixes> = RwLock::new(LogPrefixes::new());
static ref VERBOSE: RwLock<bool> = RwLock::new(false);
static ref DEBUG: RwLock<bool> = RwLock::new(false);
}
#[macro_export]
macro_rules! err {
($($arg:tt)+) => (
$crate::_log($crate::Severity::Err, format!($($arg)+));
)
}
#[macro_export]
macro_rules! warn {
($($arg:tt)+) => (
$crate::_log($crate::Severity::Warn, format!($($arg)+));
)
}
#[macro_export]
macro_rules! info {
($($arg:tt)+) => ({
$crate::_log($crate::Severity::Info, format!($($arg)+));
})
}
#[macro_export]
macro_rules! verbose {
($($arg:tt)+) => ({
$crate::_log($crate::Severity::Verbose, format!($($arg)+));
})
}
#[macro_export]
macro_rules! debug {
($($arg:tt)+) => ({
$crate::_log($crate::Severity::Debug, format!($($arg)+));
})
}
#[macro_export]
macro_rules! bail {
($($arg:tt)+) => ({
$crate::err!($($arg)+);
std::process::exit(1);
});
}
#[doc(hidden)]
pub fn _log(severity: Severity, msg: String) {
use std::io::{stderr, stdout, Write};
if severity.suppressed() {
return
}
let txt = format!("{} {}\n", severity.prefix(), msg);
#[cfg(feature = "colours")]
let txt = severity.style(txt).to_string();
if severity.to_stderr() {
let _ = stderr().lock().write_all(txt.as_bytes());
} else {
let _ = stdout().lock().write_all(txt.as_bytes());
}
}
pub fn set_debug(val: bool) {
let mut dbg = DEBUG.write().unwrap();
*dbg = val;
}
pub fn set_verbose(val: bool) {
let mut v = VERBOSE.write().unwrap();
*v = val;
}
pub fn error_prefix_str(s: String) {
let mut pre = PREFIXES.write().unwrap();
pre.err_str = s;
}
pub fn warning_prefix_str(s: String) {
let mut pre = PREFIXES.write().unwrap();
pre.warn_str = s;
}
pub fn info_prefix_str(s: String) {
let mut pre = PREFIXES.write().unwrap();
pre.info_str = s;
}
pub fn debug_prefix_str(s: String) {
let mut pre = PREFIXES.write().unwrap();
pre.debug_str = s;
}
pub fn error_prefix_fn(f: PrefixFn) {
let mut pre = PREFIXES.write().unwrap();
pre.err_fn = Some(f);
}
pub fn warning_prefix_fn(f: PrefixFn) {
let mut pre = PREFIXES.write().unwrap();
pre.warn_fn = Some(f);
}
pub fn info_prefix_fn(f: PrefixFn) {
let mut pre = PREFIXES.write().unwrap();
pre.info_fn = Some(f);
}
pub fn debug_prefix_fn(f: PrefixFn) {
let mut pre = PREFIXES.write().unwrap();
pre.debug_fn = Some(f);
}
#[doc(hidden)]
pub enum Severity {
Err,
Warn,
Info,
Verbose,
Debug,
}
impl Severity {
#[cfg(feature = "colours")]
pub fn style(&self, txt: String) -> console::StyledObject<String> {
use console::style;
use Severity::*;
let obj = match self {
Err => style(txt).red(),
Warn => style(txt).yellow(),
Info|Verbose => style(txt),
Debug => style(txt).dim(),
};
if self.to_stderr() {
obj.for_stderr()
} else {
obj.for_stdout()
}
}
pub fn to_stderr(&self) -> bool {
use Severity::*;
if cfg!(feature = "only_stderr") {
return true
}
if cfg!(feature = "only_stdout") {
return false
}
match self {
Err|Warn => true,
_ => false,
}
}
pub fn prefix(&self) -> String {
use Severity::*;
let pre = PREFIXES.read().unwrap();
match self {
Err => pre.err(),
Warn => pre.warn(),
Info|Verbose => pre.info(),
Debug => pre.debug(),
}
}
pub fn suppressed(&self) -> bool {
use Severity::*;
match self {
Debug => !*DEBUG.read().unwrap(),
Verbose => !*VERBOSE.read().unwrap(),
_ => false,
}
}
}
pub type PrefixFn = fn() -> String;
#[derive(Debug, Default)]
struct LogPrefixes {
err_fn: Option<PrefixFn>,
warn_fn: Option<PrefixFn>,
info_fn: Option<PrefixFn>,
debug_fn: Option<PrefixFn>,
err_str: String,
warn_str: String,
info_str: String,
debug_str: String,
}
impl LogPrefixes {
pub fn new() -> Self {
LogPrefixes {
err_str: "[!!]".to_string(),
warn_str: "[!]".to_string(),
info_str: "[*]".to_string(),
debug_str: "[~]".to_string(),
..Default::default()
}
}
pub fn err(&self) -> String {
match self.err_fn {
Some(f) => f(),
None => self.err_str.clone(),
}
}
pub fn warn(&self) -> String {
match self.warn_fn {
Some(f) => f(),
None => self.warn_str.clone(),
}
}
pub fn info(&self) -> String {
match self.info_fn {
Some(f) => f(),
None => self.info_str.clone(),
}
}
pub fn debug(&self) -> String {
match self.debug_fn {
Some(f) => f(),
None => self.debug_str.clone(),
}
}
}