Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement RuntimePattern #45

Merged
merged 4 commits into from
Mar 27, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -43,7 +43,7 @@ jobs:
fail-fast: false
matrix:
os: ['ubuntu-latest', 'windows-latest', 'macos-latest']
fn_features: ['', 'log native libsystemd multi-thread']
fn_features: ['', 'log native libsystemd multi-thread runtime-pattern']
cfg_feature: ['', 'flexible-string', 'source-location']
runs-on: ${{ matrix.os }}
steps:
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -2,5 +2,6 @@
resolver = "2"
members = [
"spdlog",
"spdlog-internal",
"spdlog-macros",
]
11 changes: 11 additions & 0 deletions spdlog-internal/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "spdlog-internal"
version = "0.1.0"
edition = "2021"
rust-version = "1.56"

[dependencies]
nom = "7.1.3"
strum = { version = "0.24.1", features = ["derive"] }
strum_macros = "0.24.3"
thiserror = "1.0.40"
12 changes: 12 additions & 0 deletions spdlog-internal/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pub mod pattern_parser;

#[macro_export]
macro_rules! impossible {
( $dbg_lit:literal, $($fmt_arg:expr),* ) => {
panic!(
"this should not happen, please open an issue on 'spdlog-rs' Bug Tracker\n\nsource: {}\ndebug:{}",
format!("{}:{}", file!(), line!()),
format!($dbg_lit, $($fmt_arg),*),
)
};
}
164 changes: 164 additions & 0 deletions spdlog-internal/src/pattern_parser/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
use std::fmt::{self, Display};

use nom::error::Error as NomError;
use thiserror::Error;

use super::PatternKind;
use crate::impossible;

#[derive(Error, Debug, PartialEq)]
pub enum Error {
ConflictName {
existing: PatternKind<()>,
incoming: PatternKind<()>,
},
Template(TemplateError),
Parse(NomError<String>),
Multiple(Vec<Error>),
#[cfg(test)]
__ForInternalTestsUseOnly(usize),
}

impl Error {
pub fn push_err<T>(result: Result<T>, new: Self) -> Result<T> {
match result {
Ok(_) => Err(new),
Err(Self::Multiple(mut errors)) => {
errors.push(new);
Err(Self::Multiple(errors))
}
Err(prev) => Err(Error::Multiple(vec![prev, new])),
}
}

pub fn push_result<T, N>(result: Result<T>, new: Result<N>) -> Result<T> {
match new {
Ok(_) => result,
Err(err) => Self::push_err(result, err),
}
}
}

impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::ConflictName { existing, incoming } => match (existing, incoming) {
(PatternKind::BuiltIn(_), PatternKind::Custom { .. }) => {
write!(
f,
"'{}' is already a built-in pattern, please try another name",
existing.placeholder()
)
}
(PatternKind::Custom { .. }, PatternKind::Custom { .. }) => {
write!(
f,
"the constructor of custom pattern '{}' is specified more than once",
existing.placeholder()
)
}
(_, PatternKind::BuiltIn { .. }) => {
impossible!("{}", self)
}
},
Error::Template(err) => {
write!(f, "template ill-format: {}", err)
}
Error::Parse(err) => {
write!(f, "failed to parse template string: {}", err)
}
Error::Multiple(errs) => {
writeln!(f, "{} errors detected:", errs.len())?;
for err in errs {
writeln!(f, " - {}", err)?;
}
Ok(())
}
#[cfg(test)]
Error::__ForInternalTestsUseOnly(value) => {
write!(f, "{}", value)
}
}
}
}

#[derive(Error, Debug, Eq, PartialEq)]
pub enum TemplateError {
WrongPatternKindReference {
is_builtin_as_custom: bool,
placeholder: String,
},
UnknownPatternReference {
is_custom: bool,
placeholder: String,
},
MultipleStyleRange,
}

impl Display for TemplateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TemplateError::WrongPatternKindReference {
is_builtin_as_custom,
placeholder,
} => {
if *is_builtin_as_custom {
write!(
f,
"'{}' is a built-in pattern, it cannot be used as a custom pattern. try to replace it with `{{{}}}`",
placeholder, placeholder
)
} else {
write!(
f,
"'{}' is a custom pattern, it cannot be used as a built-in pattern. try to replace it with `{{${}}}`",
placeholder, placeholder
)
}
}
TemplateError::UnknownPatternReference {
is_custom,
placeholder,
} => {
if *is_custom {
write!(
f,
"the constructor of custom pattern '{}' is not specified",
placeholder
)
} else {
write!(f, "no built-in pattern named '{}'", placeholder)
}
}
TemplateError::MultipleStyleRange => {
write!(f, "multiple style ranges are not currently supported")
}
}
}
}

pub type Result<T> = std::result::Result<T, Error>;

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn push_err() {
macro_rules! make_err {
( $($inputs:tt)+ ) => {
Error::__ForInternalTestsUseOnly($($inputs)*)
};
}

assert!(matches!(
Error::push_err(Ok(()), make_err!(1)),
Err(make_err!(1))
));

assert!(matches!(
Error::push_err::<()>(Err(make_err!(1)), make_err!(2)),
Err(Error::Multiple(v)) if matches!(v[..], [make_err!(1), make_err!(2)])
));
}
}
File renamed without changes.
144 changes: 144 additions & 0 deletions spdlog-internal/src/pattern_parser/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
use std::borrow::Cow;

use strum::IntoEnumIterator;
use strum_macros::{EnumDiscriminants, EnumIter, EnumString, IntoStaticStr};

pub mod error;
mod helper;
pub mod parse;
mod registry;

pub use error::{Error, Result};
pub use registry::{check_custom_pattern_names, PatternRegistry};

#[derive(
Clone, Copy, Debug, Eq, PartialEq, IntoStaticStr, EnumDiscriminants, EnumIter, EnumString,
)]
#[strum_discriminants(derive(IntoStaticStr))]
pub enum BuiltInFormatterInner {
#[strum(serialize = "weekday_name")]
AbbrWeekdayName,
#[strum(serialize = "weekday_name_full")]
WeekdayName,
#[strum(serialize = "month_name")]
AbbrMonthName,
#[strum(serialize = "month_name_full")]
MonthName,
#[strum(serialize = "datetime")]
FullDateTime,
#[strum(serialize = "year_short")]
ShortYear,
#[strum(serialize = "year")]
Year,
#[strum(serialize = "date_short")]
ShortDate,
#[strum(serialize = "date")]
Date,
#[strum(serialize = "month")]
Month,
#[strum(serialize = "day")]
Day,
#[strum(serialize = "hour")]
Hour,
#[strum(serialize = "hour_12")]
Hour12,
#[strum(serialize = "minute")]
Minute,
#[strum(serialize = "second")]
Second,
#[strum(serialize = "millisecond")]
Millisecond,
#[strum(serialize = "microsecond")]
Microsecond,
#[strum(serialize = "nanosecond")]
Nanosecond,
#[strum(serialize = "am_pm")]
AmPm,
#[strum(serialize = "time_12")]
Time12,
#[strum(serialize = "time_short")]
ShortTime,
#[strum(serialize = "time")]
Time,
#[strum(serialize = "tz_offset")]
TzOffset,
#[strum(serialize = "unix_timestamp")]
UnixTimestamp,
#[strum(serialize = "full")]
Full,
#[strum(serialize = "level")]
Level,
#[strum(serialize = "level_short")]
ShortLevel,
#[strum(serialize = "source")]
Source,
#[strum(serialize = "file_name")]
SourceFilename,
#[strum(serialize = "file")]
SourceFile,
#[strum(serialize = "line")]
SourceLine,
#[strum(serialize = "column")]
SourceColumn,
#[strum(serialize = "module_path")]
SourceModulePath,
#[strum(serialize = "logger")]
LoggerName,
#[strum(serialize = "payload")]
Payload,
#[strum(serialize = "pid")]
ProcessId,
#[strum(serialize = "tid")]
ThreadId,
#[strum(serialize = "eol")]
Eol,
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub struct BuiltInFormatter(BuiltInFormatterInner);

impl BuiltInFormatter {
pub fn iter() -> impl Iterator<Item = BuiltInFormatter> {
BuiltInFormatterInner::iter().map(BuiltInFormatter)
}

pub fn struct_name(&self) -> &'static str {
BuiltInFormatterInnerDiscriminants::from(self.0).into()
}

pub fn placeholder(&self) -> &'static str {
self.0.into()
}

pub fn inner(&self) -> BuiltInFormatterInner {
self.0
}
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum PatternKind<F> {
BuiltIn(BuiltInFormatter),
Custom {
placeholder: Cow<'static, str>,
factory: F,
},
}

impl<F> PatternKind<F> {
pub(crate) fn placeholder(&self) -> &str {
match self {
PatternKind::BuiltIn(f) => f.placeholder(),
PatternKind::Custom { placeholder, .. } => placeholder,
}
}

pub(crate) fn to_factory_erased(&self) -> PatternKind<()> {
match self {
PatternKind::BuiltIn(b) => PatternKind::BuiltIn(b.clone()),
PatternKind::Custom { placeholder, .. } => PatternKind::Custom {
placeholder: placeholder.clone(),
factory: (),
},
}
}
}
Loading