use spdlog_internal::pattern_parser::{
error::TemplateError,
parse::{Template, TemplateToken},
BuiltInFormatter, Error as PatternParserError, PatternKind as GenericPatternKind,
PatternRegistry as GenericPatternRegistry, Result as PatternParserResult,
};
use super::{__pattern as pattern, Pattern, PatternContext};
use crate::{
error::{BuildPatternError, Error},
Record, Result, StringBuf,
};
type Patterns = Vec<Box<dyn Pattern>>;
type PatternCreator = Box<dyn Fn() -> Box<dyn Pattern>>;
type PatternRegistry = GenericPatternRegistry<PatternCreator>;
type PatternKind = GenericPatternKind<PatternCreator>;
pub use spdlog_macros::runtime_pattern;
#[rustfmt::skip] #[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
#[derive(Clone)]
pub struct RuntimePattern(Patterns);
impl RuntimePattern {
#[doc(hidden)]
pub fn __with_custom_patterns(template: &str, registry: PatternRegistry) -> Result<Self> {
Template::parse(template)
.and_then(|template| {
Synthesiser::new(registry)
.synthesize(template)
.map(RuntimePattern)
})
.map_err(|err| Error::BuildPattern(BuildPatternError(err)))
}
}
impl Pattern for RuntimePattern {
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> Result<()> {
for pattern in &self.0 {
pattern.format(record, dest, ctx)?;
}
Ok(())
}
}
struct Synthesiser {
registry: PatternRegistry,
}
impl Synthesiser {
fn new(registry: PatternRegistry) -> Self {
Self { registry }
}
fn synthesize(&self, template: Template) -> PatternParserResult<Patterns> {
self.build_patterns(template, false)
}
fn build_patterns(
&self,
template: Template,
mut style_range_seen: bool,
) -> PatternParserResult<Patterns> {
let mut patterns = Patterns::new();
for token in template.tokens {
let pattern = match token {
TemplateToken::Literal(t) => Box::new(t.literal),
TemplateToken::Formatter(t) => {
let pattern = self.registry.find(t.has_custom_prefix, t.placeholder)?;
match pattern {
PatternKind::BuiltIn(builtin) => build_builtin_pattern(builtin),
PatternKind::Custom { factory, .. } => factory(),
}
}
TemplateToken::StyleRange(style_range) => {
if style_range_seen {
return Err(PatternParserError::Template(
TemplateError::MultipleStyleRange,
));
}
style_range_seen = true;
Box::new(pattern::StyleRange::new(
self.build_patterns(style_range.body, true)?,
))
}
};
patterns.push(pattern);
}
Ok(patterns)
}
}
fn build_builtin_pattern(builtin: &BuiltInFormatter) -> Box<dyn Pattern> {
macro_rules! match_builtin {
( $($name:ident),+ $(,)? ) => {
match builtin {
$(BuiltInFormatter::$name => Box::<pattern::$name>::default()),+
}
};
}
match_builtin!(
AbbrWeekdayName,
WeekdayName,
AbbrMonthName,
MonthName,
FullDateTime,
ShortYear,
Year,
ShortDate,
Date,
Month,
Day,
Hour,
Hour12,
Minute,
Second,
Millisecond,
Microsecond,
Nanosecond,
AmPm,
Time12,
ShortTime,
Time,
TzOffset,
UnixTimestamp,
Full,
Level,
ShortLevel,
Source,
SourceFilename,
SourceFile,
SourceLine,
SourceColumn,
SourceModulePath,
LoggerName,
Payload,
KV,
ProcessId,
ThreadId,
Eol
)
}