#![warn(missing_docs)]
use fidl_fuchsia_diagnostics as fdiagnostics;
use std::str::FromStr;
use std::{cmp, fmt};
#[cfg(feature = "serde")]
#[doc(hidden)]
pub mod serde_ext;
#[cfg_attr(feature = "serde", derive(schemars::JsonSchema))]
#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
#[repr(u8)]
pub enum Severity {
Trace = 0x10,
Debug = 0x20,
Info = 0x30,
Warn = 0x40,
Error = 0x50,
Fatal = 0x60,
}
#[cfg(feature = "serde")]
impl serde::Serialize for Severity {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serde_ext::severity::serialize(self, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for Severity {
fn deserialize<D>(deserializer: D) -> Result<Severity, D::Error>
where
D: serde::Deserializer<'de>,
{
serde_ext::severity::deserialize(deserializer)
}
}
impl Severity {
pub fn parse_exact(raw_severity: u8) -> (Option<u8>, Severity) {
if raw_severity == Severity::Trace as u8 {
(None, Severity::Trace)
} else if raw_severity == Severity::Debug as u8 {
(None, Severity::Debug)
} else if raw_severity == Severity::Info as u8 {
(None, Severity::Info)
} else if raw_severity == Severity::Warn as u8 {
(None, Severity::Warn)
} else if raw_severity == Severity::Error as u8 {
(None, Severity::Error)
} else if raw_severity == Severity::Fatal as u8 {
(None, Severity::Fatal)
} else {
(Some(raw_severity), Severity::from(raw_severity))
}
}
pub fn as_str(&self) -> &'static str {
match self {
Severity::Trace => "TRACE",
Severity::Debug => "DEBUG",
Severity::Info => "INFO",
Severity::Warn => "WARN",
Severity::Error => "ERROR",
Severity::Fatal => "FATAL",
}
}
}
macro_rules! impl_from_signed {
($($type:ty),*) => {
$(
impl From<$type> for Severity {
fn from(value: $type) -> Severity {
match value {
..0x00 => Severity::Trace,
0x00..=0x10 => Severity::Trace,
0x11..=0x20 => Severity::Debug,
0x21..=0x30 => Severity::Info,
0x31..=0x40 => Severity::Warn,
0x41..=0x50 => Severity::Error,
0x51.. => Severity::Fatal,
}
}
}
)*
}
}
macro_rules! impl_from_unsigned {
($($type:ty),*) => {
$(
impl From<$type> for Severity {
fn from(value: $type) -> Severity {
match value {
0x00..=0x10 => Severity::Trace,
0x11..=0x20 => Severity::Debug,
0x21..=0x30 => Severity::Info,
0x31..=0x40 => Severity::Warn,
0x41..=0x50 => Severity::Error,
0x51.. => Severity::Fatal,
}
}
}
)*
}
}
impl_from_signed!(i8, i16, i32, i64, i128);
impl_from_unsigned!(u8, u16, u32, u64, u128);
impl From<Severity> for tracing::Level {
fn from(s: Severity) -> tracing::Level {
match s {
Severity::Trace => tracing::Level::TRACE,
Severity::Debug => tracing::Level::DEBUG,
Severity::Info => tracing::Level::INFO,
Severity::Warn => tracing::Level::WARN,
Severity::Fatal | Severity::Error => tracing::Level::ERROR,
}
}
}
impl From<tracing::Level> for Severity {
fn from(level: tracing::Level) -> Severity {
match level {
tracing::Level::TRACE => Severity::Trace,
tracing::Level::DEBUG => Severity::Debug,
tracing::Level::INFO => Severity::Info,
tracing::Level::WARN => Severity::Warn,
tracing::Level::ERROR => Severity::Error,
}
}
}
impl From<log::Level> for Severity {
fn from(level: log::Level) -> Severity {
match level {
log::Level::Trace => Severity::Trace,
log::Level::Debug => Severity::Debug,
log::Level::Info => Severity::Info,
log::Level::Warn => Severity::Warn,
log::Level::Error => Severity::Error,
}
}
}
impl From<Severity> for fdiagnostics::Severity {
fn from(s: Severity) -> fdiagnostics::Severity {
match s {
Severity::Trace => fdiagnostics::Severity::Trace,
Severity::Debug => fdiagnostics::Severity::Debug,
Severity::Info => fdiagnostics::Severity::Info,
Severity::Warn => fdiagnostics::Severity::Warn,
Severity::Error => fdiagnostics::Severity::Error,
Severity::Fatal => fdiagnostics::Severity::Fatal,
}
}
}
impl From<fdiagnostics::Severity> for Severity {
fn from(s: fdiagnostics::Severity) -> Severity {
match s {
fdiagnostics::Severity::Trace => Severity::Trace,
fdiagnostics::Severity::Debug => Severity::Debug,
fdiagnostics::Severity::Info => Severity::Info,
fdiagnostics::Severity::Warn => Severity::Warn,
fdiagnostics::Severity::Error => Severity::Error,
fdiagnostics::Severity::Fatal => Severity::Fatal,
}
}
}
impl AsRef<str> for Severity {
fn as_ref(&self) -> &str {
self.as_str()
}
}
impl fmt::Display for Severity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("invalid severity: {0}")]
Invalid(String),
}
impl FromStr for Severity {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"trace" => Ok(Severity::Trace),
"debug" => Ok(Severity::Debug),
"info" => Ok(Severity::Info),
"warn" | "warning" => Ok(Severity::Warn),
"error" => Ok(Severity::Error),
"fatal" => Ok(Severity::Fatal),
other => Err(Error::Invalid(other.to_string())),
}
}
}
impl PartialEq<fdiagnostics::Severity> for Severity {
fn eq(&self, other: &fdiagnostics::Severity) -> bool {
matches!(
(self, other),
(Severity::Trace, fdiagnostics::Severity::Trace)
| (Severity::Debug, fdiagnostics::Severity::Debug)
| (Severity::Info, fdiagnostics::Severity::Info)
| (Severity::Warn, fdiagnostics::Severity::Warn)
| (Severity::Error, fdiagnostics::Severity::Error)
| (Severity::Fatal, fdiagnostics::Severity::Fatal)
)
}
}
impl PartialOrd<fdiagnostics::Severity> for Severity {
fn partial_cmp(&self, other: &fdiagnostics::Severity) -> Option<cmp::Ordering> {
let other = Severity::from(*other);
self.partial_cmp(&other)
}
}