use core::any::TypeId;
use std::collections::HashMap;
use tracing::Level;
use crate::Origin;
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
#[cfg_attr(feature = "facet", derive(::facet::Facet))]
pub struct FieldDescriptor {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "facet", facet(skip_serializing_if = Option::is_none))]
pub deprecated: Option<&'static str>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "facet", facet(skip_serializing_if = Option::is_none))]
pub doc: Option<&'static str>,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "pairs_empty", serialize_with = "serde::pairs")
)]
#[cfg_attr(feature = "facet", facet(proxy = MetaMap, skip_serializing_if = pairs_empty))]
pub meta: &'static [(&'static str, &'static str)],
pub name: &'static str,
#[cfg_attr(feature = "facet", facet(rename = "type"))]
pub r#type: &'static str,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
#[cfg_attr(feature = "facet", derive(::facet::Facet))]
#[allow(non_camel_case_types)]
#[repr(u8)]
pub enum LevelName {
TRACE,
DEBUG,
INFO,
WARN,
ERROR,
}
#[derive(Debug)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize))]
#[cfg_attr(feature = "facet", derive(::facet::Facet))]
pub struct MessageDescriptor {
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "facet", facet(skip_serializing_if = Option::is_none))]
pub deprecated: Option<&'static str>,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(feature = "facet", facet(skip_serializing_if = Option::is_none))]
pub doc: Option<&'static str>,
pub fields: &'static [FieldDescriptor],
pub level: LevelName,
#[cfg_attr(
feature = "serde",
serde(skip_serializing_if = "pairs_empty", serialize_with = "serde::pairs")
)]
#[cfg_attr(feature = "facet", facet(proxy = MetaMap, skip_serializing_if = pairs_empty))]
pub meta: &'static [(&'static str, &'static str)],
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "facet", facet(skip))]
pub msg: &'static str,
#[cfg_attr(feature = "serde", serde(serialize_with = "serde::origin"))]
pub origin: Origin,
#[cfg_attr(feature = "serde", serde(skip_serializing_if = "tags_empty"))]
#[cfg_attr(feature = "facet", facet(skip_serializing_if = tags_empty))]
pub tags: &'static [&'static str],
#[cfg_attr(feature = "serde", serde(skip))]
#[cfg_attr(feature = "facet", facet(skip))]
pub type_id: TypeId,
}
impl LevelName {
pub const fn as_str(&self) -> &'static str {
match self {
LevelName::TRACE => "TRACE",
LevelName::DEBUG => "DEBUG",
LevelName::INFO => "INFO",
LevelName::WARN => "WARN",
LevelName::ERROR => "ERROR",
}
}
}
impl From<LevelName> for Level {
fn from(name: LevelName) -> Self {
match name {
LevelName::TRACE => Level::TRACE,
LevelName::DEBUG => Level::DEBUG,
LevelName::INFO => Level::INFO,
LevelName::WARN => Level::WARN,
LevelName::ERROR => Level::ERROR,
}
}
}
#[cfg(feature = "facet")]
#[derive(::facet::Facet)]
#[facet(transparent)]
struct MetaMap(std::collections::BTreeMap<&'static str, &'static str>);
#[cfg(feature = "facet")]
#[allow(clippy::infallible_try_from)]
impl TryFrom<&&'static [(&'static str, &'static str)]> for MetaMap {
type Error = core::convert::Infallible;
fn try_from(pairs: &&'static [(&'static str, &'static str)]) -> Result<Self, Self::Error> {
Ok(MetaMap(pairs.iter().copied().collect()))
}
}
#[cfg(feature = "facet")]
impl TryFrom<MetaMap> for &'static [(&'static str, &'static str)] {
type Error = &'static str;
fn try_from(_: MetaMap) -> Result<Self, Self::Error> {
Err("the catalogue is serialize-only")
}
}
#[cfg(any(feature = "serde", feature = "facet"))]
fn pairs_empty(pairs: &&'static [(&'static str, &'static str)]) -> bool {
pairs.is_empty()
}
#[cfg(any(feature = "serde", feature = "facet"))]
fn tags_empty(tags: &&'static [&'static str]) -> bool {
tags.is_empty()
}
#[cfg(feature = "serde")]
mod serde {
use ::serde::{Serializer, ser::SerializeMap};
use crate::Origin;
pub(super) fn origin<S: Serializer>(origin: &Origin, s: S) -> Result<S::Ok, S::Error> {
s.collect_str(origin)
}
pub(super) fn pairs<S: Serializer>(
pairs: &&'static [(&'static str, &'static str)],
s: S,
) -> Result<S::Ok, S::Error> {
let mut map = s.serialize_map(Some(pairs.len()))?;
for (k, v) in pairs.iter() {
map.serialize_entry(k, v)?;
}
map.end()
}
}
pub fn all() -> impl Iterator<Item = &'static MessageDescriptor> {
inventory::iter::<MessageDescriptor>.into_iter()
}
pub fn duplicates() -> Vec<&'static str> {
let mut counts = HashMap::new();
for descriptor in all() {
*counts.entry(descriptor.msg).or_insert(0_usize) += 1;
}
let mut keys: Vec<&'static str> = counts
.into_iter()
.filter_map(|(msg, count)| (count > 1).then_some(msg))
.collect();
keys.sort_unstable();
keys
}
inventory::collect!(MessageDescriptor);