use std;
use std::fmt;
use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use owo_colors::Style;
pub static ENABLE_DEBUG: AtomicBool = AtomicBool::new(false);
#[macro_export]
macro_rules! errorln {
($($arg:tt)*) => { $crate::diagnostic!($crate::error::Severity::Error; $($arg)*); }
}
#[macro_export]
macro_rules! infoln {
($($arg:tt)*) => { $crate::diagnostic!($crate::error::Severity::Info; $($arg)*); }
}
#[macro_export]
#[cfg(debug_assertions)]
macro_rules! debugln {
($($arg:tt)*) => {
if $crate::error::ENABLE_DEBUG.load(std::sync::atomic::Ordering::Relaxed) {
$crate::diagnostic!($crate::error::Severity::Debug; $($arg)*);
}
}
}
#[macro_export]
macro_rules! stageln {
($stage_name:expr, $($arg:tt)*) => { $crate::diagnostic!($crate::error::Severity::Stage($stage_name); $($arg)*); }
}
#[macro_export]
#[cfg(not(debug_assertions))]
macro_rules! debugln {
($($arg:tt)*) => {};
}
#[macro_export]
macro_rules! diagnostic {
($severity:expr; $($arg:tt)*) => {
$crate::diagnostic::Diagnostics::eprintln(&format!("{} {}", $severity, format!($($arg)*)))
}
}
#[derive(PartialEq, Eq)]
pub enum Severity {
Debug,
Info,
Error,
Stage(&'static str),
}
impl fmt::Display for Severity {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (severity, style) = match *self {
Severity::Error => ("Error:", Style::new().red().bold()),
Severity::Info => ("Info:", Style::new().white().bold()),
Severity::Debug => ("Debug:", Style::new().blue().bold()),
Severity::Stage(name) => (name, Style::new().green().bold()),
};
write!(f, "{:>14}", crate::fmt_with_style!(severity, style))
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Debug)]
pub struct Error {
pub msg: String,
pub cause: Option<Arc<dyn std::error::Error + Send + Sync>>,
}
impl Error {
pub fn new<S: Into<String>>(msg: S) -> Error {
Error {
msg: msg.into(),
cause: None,
}
}
pub fn chain<S, E>(msg: S, cause: E) -> Error
where
S: Into<String>,
E: std::error::Error + Send + Sync + 'static,
{
Error {
msg: msg.into(),
cause: Some(Arc::new(cause)),
}
}
}
impl std::error::Error for Error {
fn description(&self) -> &str {
&self.msg
}
fn cause(&self) -> Option<&dyn std::error::Error> {
match self.cause {
Some(ref b) => Some(b.as_ref()),
None => None,
}
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.msg)?;
if let Some(ref c) = self.cause {
write!(f, " {}", c)?
}
Ok(())
}
}
impl From<Error> for String {
fn from(err: Error) -> String {
format!("{}", err)
}
}
impl From<std::io::Error> for Error {
fn from(err: std::io::Error) -> Error {
Error::chain("Cannot startup runtime.".to_string(), err)
}
}