use serde::{Deserialize, Serialize};
use std::{convert::TryFrom, error::Error, fmt, str::FromStr};
#[derive(Debug, Clone)]
pub struct ParseLogLevelError {
pub invalid_value: String,
}
impl ParseLogLevelError {
#[must_use]
pub fn new(invalid_value: &str) -> Self {
Self {
invalid_value: invalid_value.to_string(),
}
}
}
impl fmt::Display for ParseLogLevelError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Invalid log level: {0}", self.invalid_value)
}
}
impl Error for ParseLogLevelError {}
#[derive(
Clone,
Copy,
Debug,
Default,
Deserialize,
Eq,
Hash,
Ord,
PartialEq,
PartialOrd,
Serialize,
)]
pub enum LogLevel {
ALL,
NONE,
DISABLED,
TRACE,
DEBUG,
VERBOSE,
#[default]
INFO,
WARN,
ERROR,
FATAL,
CRITICAL,
}
macro_rules! define_log_levels {
( $( $variant:ident, $num:expr, $upper:expr, $lower:expr );+ $(;)? ) => {
impl LogLevel {
#[must_use]
pub const fn to_numeric(self) -> u8 {
match self { $( Self::$variant => $num, )+ }
}
#[must_use]
pub const fn as_str(&self) -> &'static str {
match self { $( Self::$variant => $upper, )+ }
}
#[must_use]
pub const fn as_str_lowercase(&self) -> &'static str {
match self { $( Self::$variant => $lower, )+ }
}
#[must_use]
pub const fn from_numeric(value: u8) -> Option<Self> {
match value {
$( $num => Some(Self::$variant), )+
_ => None,
}
}
}
impl FromStr for LogLevel {
type Err = ParseLogLevelError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
match s.to_uppercase().as_str() {
$( $upper => Ok(Self::$variant), )+
_ => Err(ParseLogLevelError::new(s)),
}
}
}
};
}
define_log_levels! {
ALL, 0, "ALL", "all";
NONE, 1, "NONE", "none";
DISABLED, 2, "DISABLED", "disabled";
TRACE, 3, "TRACE", "trace";
DEBUG, 4, "DEBUG", "debug";
VERBOSE, 5, "VERBOSE", "verbose";
INFO, 6, "INFO", "info";
WARN, 7, "WARN", "warn";
ERROR, 8, "ERROR", "error";
FATAL, 9, "FATAL", "fatal";
CRITICAL, 10, "CRITICAL", "critical";
}
impl LogLevel {
#[must_use]
pub const fn includes(self, other: Self) -> bool {
match self {
Self::ALL => true, Self::NONE => false, _ => self.to_numeric() >= other.to_numeric(), }
}
}
impl TryFrom<String> for LogLevel {
type Error = ParseLogLevelError;
fn try_from(value: String) -> Result<Self, Self::Error> {
Self::from_str(&value)
}
}
impl fmt::Display for LogLevel {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}