#[doc(hidden)]
#[path = "pattern/mod.rs"]
pub mod __pattern;
#[cfg(feature = "runtime-pattern")]
mod runtime;
use std::{fmt::Write as _, sync::Arc};
use dyn_clone::*;
#[cfg(feature = "runtime-pattern")]
pub use runtime::*;
use crate::{
formatter::{Formatter, FormatterContext, TimeDate, TimeDateLazyLocked},
Error, Record, StringBuf,
};
#[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"))]
#[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"))]
#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
pub use ::spdlog_macros::pattern;
#[cfg(not(feature = "runtime-pattern"))]
pub use crate::__runtime_pattern_disabled as runtime_pattern;
#[cfg(not(feature = "runtime-pattern"))]
#[doc(hidden)]
#[macro_export]
macro_rules! __runtime_pattern_disabled {
($($_:tt)*) => {
compile_error!(
"macro `runtime_pattern` required to enable crate feature `runtime-pattern` for spdlog-rs"
);
};
}
#[derive(Clone)]
pub struct PatternFormatter<P> {
pattern: P,
}
impl<P> PatternFormatter<P>
where
P: Pattern,
{
#[must_use]
pub fn new(pattern: P) -> Self {
Self { pattern }
}
}
impl<P> Formatter for PatternFormatter<P>
where
P: 'static + Clone + Pattern,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
fmt_ctx: &mut FormatterContext,
) -> crate::Result<()> {
#[cfg(not(feature = "flexible-string"))]
dest.reserve(crate::string_buf::RESERVE_SIZE);
fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
{
let mut pat_ctx = PatternContext { fmt_ctx };
self.pattern.format(record, dest, &mut pat_ctx)?;
}
fmt_ctx.locked_time_date = None;
Ok(())
}
}
#[derive(Debug)]
pub struct PatternContext<'a, 'b> {
fmt_ctx: &'a mut FormatterContext<'b>,
}
impl PatternContext<'_, '_> {
#[must_use]
fn time_date(&mut self) -> TimeDate<'_> {
self.fmt_ctx.locked_time_date.as_mut().unwrap().get()
}
}
pub trait Pattern: Send + Sync + DynClone {
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()>;
}
clone_trait_object!(Pattern);
impl Pattern for String {
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
<&str as Pattern>::format(&&**self, record, dest, ctx)
}
}
impl Pattern for str {
fn format(
&self,
_record: &Record,
dest: &mut StringBuf,
_ctx: &mut PatternContext,
) -> crate::Result<()> {
dest.write_str(self).map_err(Error::FormatRecord)
}
}
impl<T> Pattern for &T
where
T: ?Sized + Pattern,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
<T as Pattern>::format(*self, record, dest, ctx)
}
}
impl<T> Pattern for Box<T>
where
T: ?Sized + Pattern,
Self: Clone,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
<T as Pattern>::format(&**self, record, dest, ctx)
}
}
impl<T> Pattern for Arc<T>
where
T: ?Sized + Pattern,
Self: Clone,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
<T as Pattern>::format(&**self, record, dest, ctx)
}
}
impl<T> Pattern for &[T]
where
T: Pattern,
Self: Clone,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
for p in *self {
<T as Pattern>::format(p, record, dest, ctx)?;
}
Ok(())
}
}
impl<T, const N: usize> Pattern for [T; N]
where
T: Pattern,
Self: Clone,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
for p in self {
<T as Pattern>::format(p, record, dest, ctx)?;
}
Ok(())
}
}
impl<T> Pattern for Vec<T>
where
T: Pattern,
Self: Clone,
{
fn format(
&self,
record: &Record,
dest: &mut StringBuf,
ctx: &mut PatternContext,
) -> crate::Result<()> {
for p in self {
<T as Pattern>::format(p, record, dest, ctx)?;
}
Ok(())
}
}
macro_rules! last {
( $a:tt, ) => { $a };
( $a:tt, $($rest:tt,)+ ) => { last!($($rest,)+) };
}
macro_rules! tuple_pattern {
(
$(
$Tuple:ident {
$(
($idx:tt) -> $T:ident
)+
}
)+
) => {
$(
impl<$($T,)+> Pattern for ($($T,)+)
where
$($T : Pattern,)+
last!($($T,)+) : ?Sized,
Self: Clone,
{
fn format(&self, record: &Record, dest: &mut StringBuf, ctx: &mut PatternContext) -> crate::Result<()> {
$(
<$T as Pattern>::format(&self.$idx, record, dest, ctx)?;
)+
Ok(())
}
}
)+
};
}
impl Pattern for () {
fn format(
&self,
_record: &Record,
_dest: &mut StringBuf,
_ctx: &mut PatternContext,
) -> crate::Result<()> {
Ok(())
}
}
tuple_pattern! {
Tuple1 {
(0) -> T0
}
Tuple2 {
(0) -> T0
(1) -> T1
}
Tuple3 {
(0) -> T0
(1) -> T1
(2) -> T2
}
Tuple4 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
}
Tuple5 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
}
Tuple6 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
}
Tuple7 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
}
Tuple8 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
}
Tuple9 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
}
Tuple10 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
}
Tuple11 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
}
Tuple12 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
}
Tuple13 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
}
Tuple14 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
}
Tuple15 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
}
Tuple16 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
}
Tuple17 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
}
Tuple18 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
}
Tuple19 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
}
Tuple20 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
}
Tuple21 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
}
Tuple22 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
}
Tuple23 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
}
Tuple24 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
}
Tuple25 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
}
Tuple26 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
}
Tuple27 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
}
Tuple28 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
(27) -> T27
}
Tuple29 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
(27) -> T27
(28) -> T28
}
Tuple30 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
(27) -> T27
(28) -> T28
(29) -> T29
}
Tuple31 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
(27) -> T27
(28) -> T28
(29) -> T29
(30) -> T30
}
Tuple32 {
(0) -> T0
(1) -> T1
(2) -> T2
(3) -> T3
(4) -> T4
(5) -> T5
(6) -> T6
(7) -> T7
(8) -> T8
(9) -> T9
(10) -> T10
(11) -> T11
(12) -> T12
(13) -> T13
(14) -> T14
(15) -> T15
(16) -> T16
(17) -> T17
(18) -> T18
(19) -> T19
(20) -> T20
(21) -> T21
(22) -> T22
(23) -> T23
(24) -> T24
(25) -> T25
(26) -> T26
(27) -> T27
(28) -> T28
(29) -> T29
(30) -> T30
(31) -> T31
}
}
#[cfg(test)]
mod tests {
use std::ops::Range;
use super::*;
use crate::{Level, SourceLocation};
#[must_use]
fn get_mock_record() -> Record<'static> {
Record::new(
Level::Info,
"record_payload",
Some(SourceLocation::__new("module", "file", 10, 20)),
Some("logger_name"),
&[],
)
}
fn test_pattern<P, T>(pattern: P, formatted: T, style_range: Option<Range<usize>>)
where
P: Pattern,
T: AsRef<str>,
{
let record = get_mock_record();
let mut output = StringBuf::new();
let mut fmt_ctx = FormatterContext::new();
fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
let mut pat_ctx = PatternContext {
fmt_ctx: &mut fmt_ctx,
};
pattern.format(&record, &mut output, &mut pat_ctx).unwrap();
fmt_ctx.locked_time_date = None;
assert_eq!(output.as_str(), formatted.as_ref());
assert_eq!(fmt_ctx.style_range(), style_range);
}
#[test]
fn test_string_as_pattern() {
test_pattern(String::from("literal"), "literal", None);
}
#[test]
fn test_str_as_pattern() {
test_pattern("literal", "literal", None);
}
#[test]
fn test_pattern_ref_as_pattern() {
#[allow(unknown_lints)]
#[allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args)]
test_pattern(&String::from("literal"), "literal", None);
}
#[test]
fn test_pattern_mut_as_pattern() {
#[allow(clippy::deref_addrof)]
test_pattern(&*&mut String::from("literal"), "literal", None);
}
#[test]
fn test_box_as_pattern() {
test_pattern(Box::new(String::from("literal")), "literal", None);
}
#[test]
fn test_arc_as_pattern() {
test_pattern(Arc::new(String::from("literal")), "literal", None);
}
#[test]
fn test_slice_as_pattern() {
let pat: &[String] = &[String::from("literal1"), String::from("literal2")];
test_pattern(pat, "literal1literal2", None);
}
#[test]
fn test_empty_slice_as_pattern() {
let pat: &[String] = &[];
test_pattern(pat, "", None);
}
#[test]
fn test_array_as_pattern() {
let pat: [String; 3] = [
String::from("literal1"),
String::from("literal2"),
String::from("literal3"),
];
test_pattern(pat, "literal1literal2literal3", None);
}
#[test]
fn test_empty_array_as_pattern() {
let pat: [String; 0] = [];
test_pattern(pat, "", None);
}
#[test]
fn test_vec_as_pattern() {
let pat = vec![
String::from("literal1"),
String::from("literal2"),
String::from("literal3"),
];
test_pattern(pat, "literal1literal2literal3", None);
}
#[test]
fn test_empty_vec_as_pattern() {
let pat: Vec<String> = vec![];
test_pattern(pat, "", None);
}
#[test]
fn test_tuple_as_pattern() {
let pat = (
String::from("literal1"),
"literal2",
String::from("literal3"),
);
test_pattern(pat, "literal1literal2literal3", None);
}
#[test]
fn test_unit_as_pattern() {
test_pattern((), "", None);
}
}