spdlog/formatter/pattern_formatter/mod.rs
1#[doc(hidden)]
2#[path = "pattern/mod.rs"]
3pub mod __pattern;
4
5#[cfg(feature = "runtime-pattern")]
6mod runtime;
7
8use std::{fmt::Write, sync::Arc};
9
10use dyn_clone::*;
11#[cfg(feature = "runtime-pattern")]
12pub use runtime::*;
13
14use crate::{
15 formatter::{Formatter, FormatterContext, TimeDate, TimeDateLazyLocked},
16 Error, Record, StringBuf,
17};
18
19#[rustfmt::skip] // rustfmt currently breaks some empty lines if `#[doc = include_str!("xxx")]` exists
20/// Builds a pattern from a template literal string at compile-time.
21///
22/// It accepts inputs in the form:
23///
24/// ```ignore
25/// // This is not exactly a valid declarative macro, just for intuition.
26/// macro_rules! pattern {
27/// ( $template:literal $(,)? ) => {};
28/// ( $template:literal, $( {$$custom:ident} => $ctor:expr ),+ $(,)? ) => {};
29/// }
30/// ```
31///
32/// Examples of valid inputs:
33///
34/// ```
35/// # use spdlog::formatter::pattern;
36/// # #[derive(Default)]
37/// # struct MyPattern;
38/// pattern!("text");
39/// pattern!("current line: {line}{eol}");
40/// pattern!("custom: {$my_pattern}{eol}", {$my_pattern} => MyPattern::default);
41/// ```
42///
43/// Its first argument accepts only a literal string that is known at compile-time.
44/// If you want to build a pattern from a runtime string, use
45/// [`runtime_pattern!`] macro instead.
46///
47/// # Note
48///
49/// The value returned by this macro is implementation details and users should
50/// not access them. If these details are changed in the future, it may not be
51/// considered as a breaking change.
52///
53/// # Basic Usage
54///
55/// In its simplest form, `pattern` receives a **literal** template string and
56/// converts it into a zero-cost pattern:
57/// ```
58/// use spdlog::formatter::{pattern, PatternFormatter};
59///
60/// let formatter = PatternFormatter::new(pattern!("template string"));
61/// ```
62///
63/// # Using Built-in Patterns
64///
65/// A pattern that always outputs a fixed string is boring and useless.
66/// Luckily, the pattern template string can contain placeholders that
67/// represents built-in patterns. For example, to include the log level and
68/// payload in the pattern, we can simply use `{level}` and `{payload}` in the
69/// pattern template string:
70/// ```
71/// # use spdlog::formatter::{pattern, PatternFormatter};
72/// use spdlog::info;
73#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
74///
75/// let formatter = PatternFormatter::new(pattern!("[{level}] {payload}{eol}"));
76/// # let (doctest, sink) = test_utils::echo_logger_from_formatter(formatter, None);
77///
78/// info!(logger: doctest, "Interesting log message");
79/// # assert_eq!(
80/// # sink.clone_string().replace("\r", ""),
81/// /* Output */ "[info] Interesting log message\n"
82/// # );
83/// ```
84///
85/// Here, `{level}` and `{payload}` are "placeholders" that will be replaced by
86/// the output of the corresponding built-in patterns when formatting log
87/// records.
88///
89/// What if you want to output a literal `{` or `}` character? Simply use `{{`
90/// and `}}`:
91/// ```
92/// # use spdlog::{
93/// # formatter::{pattern, PatternFormatter},
94/// # info,
95/// # };
96#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
97/// let formatter = PatternFormatter::new(pattern!("[{{escaped}}] {payload}{eol}"));
98/// # let (doctest, sink) = test_utils::echo_logger_from_formatter(formatter, None);
99///
100/// info!(logger: doctest, "Interesting log message");
101/// # assert_eq!(
102/// # sink.clone_string().replace("\r", ""),
103/// /* Output */ "[{escaped}] Interesting log message\n"
104/// # );
105/// ```
106///
107/// You can find a full list of all built-in patterns and their corresponding
108/// placeholders at [Appendix](#appendix-a-full-list-of-built-in-patterns)
109/// below.
110///
111/// # Using Style Range
112///
113/// A specific portion of a formatted log message can be specified as "style
114/// range". Formatted text in the style range will be rendered in a different
115/// style by supported sinks. You can use `{^...}` to mark the style range in
116/// the pattern template string:
117/// ```
118/// # use spdlog::{
119/// # formatter::{pattern, PatternFormatter},
120/// # info,
121/// # };
122#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
123/// let formatter = PatternFormatter::new(pattern!("{^[{level}]} {payload}{eol}"));
124/// # let (doctest, sink) = test_utils::echo_logger_from_formatter(formatter, None);
125///
126/// info!(logger: doctest, "Interesting log message");
127/// # assert_eq!(
128/// # sink.clone_string().replace("\r", ""),
129/// /* Output */ "[info] Interesting log message\n"
130/// // ^^^^^^ <- style range
131/// # );
132/// ```
133///
134/// # Using Your Own Patterns
135///
136/// Yes, you can refer your own implementation of [`Pattern`] in the pattern
137/// template string! Let's say you have a struct that implements the
138/// [`Pattern`] trait. To refer `MyPattern` in the pattern template string, you
139/// need to use the extended syntax to associate `MyPattern` with a name so
140/// that `pattern!` can resolve it:
141/// ```
142/// use std::fmt::Write;
143///
144/// use spdlog::{
145/// formatter::{pattern, Pattern, PatternContext, PatternFormatter},
146/// Record, StringBuf, info
147/// };
148#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
149///
150/// #[derive(Default, Clone)]
151/// struct MyPattern;
152///
153/// impl Pattern for MyPattern {
154/// fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
155/// write!(dest, "My own pattern").map_err(spdlog::Error::FormatRecord)
156/// }
157/// }
158///
159/// let pat = pattern!("[{level}] {payload} - {$mypat}{eol}",
160/// {$mypat} => MyPattern::default,
161/// );
162/// let formatter = PatternFormatter::new(pat);
163/// # let (doctest, sink) = test_utils::echo_logger_from_formatter(formatter, None);
164///
165/// info!(logger: doctest, "Interesting log message");
166/// # assert_eq!(
167/// # sink.clone_string().replace("\r", ""),
168/// /* Output */ "[info] Interesting log message - My own pattern\n"
169/// # );
170/// ```
171///
172/// Note the special `{$name} => id` syntax given to the `pattern` macro.
173/// `name` is the name of your own pattern; placeholder `{$name}` in the
174/// template string will be replaced by the output of your own pattern. `name`
175/// can only be an identifier. `id` is a [path] that identifies a **function**
176/// that can be called with **no arguments**. Instances of your own pattern
177/// will be created by calling this function with no arguments.
178///
179/// [path]: https://doc.rust-lang.org/stable/reference/paths.html
180///
181/// ## Custom Pattern Creation
182///
183/// Each placeholder results in a new pattern instance. For example, consider a
184/// custom pattern that writes a unique ID to the output. If the pattern
185/// template string contains multiple placeholders that refer to `MyPattern`,
186/// each placeholder will eventually be replaced by different IDs.
187///
188/// ```
189/// # use std::{
190/// # fmt::Write,
191/// # sync::atomic::{AtomicU32, Ordering},
192/// # };
193/// # use spdlog::{
194/// # formatter::{pattern, Pattern, PatternContext, PatternFormatter},
195/// # prelude::*,
196/// # Record, StringBuf,
197/// # };
198#[doc = include_str!(concat!(env!("OUT_DIR"), "/test_utils/common_for_doc_test.rs"))]
199/// static NEXT_ID: AtomicU32 = AtomicU32::new(0);
200///
201/// #[derive(Clone)]
202/// struct MyPattern {
203/// id: u32,
204/// }
205///
206/// impl MyPattern {
207/// fn new() -> Self {
208/// Self {
209/// id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
210/// }
211/// }
212/// }
213///
214/// impl Pattern for MyPattern {
215/// fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
216/// write!(dest, "{}", self.id).map_err(spdlog::Error::FormatRecord)
217/// }
218/// }
219///
220/// let pat = pattern!("[{level}] {payload} - {$mypat} {$mypat} {$mypat}{eol}",
221/// {$mypat} => MyPattern::new,
222/// );
223/// let formatter = PatternFormatter::new(pat);
224/// # let (doctest, sink) = test_utils::echo_logger_from_formatter(formatter, None);
225///
226/// info!(logger: doctest, "Interesting log message");
227/// # assert_eq!(
228/// # sink.clone_string().replace("\r", ""),
229/// /* Output */ "[info] Interesting log message - 0 1 2\n"
230/// # );
231/// ```
232///
233/// Of course, you can have multiple custom patterns:
234/// ```
235/// # use spdlog::formatter::pattern;
236/// #
237/// # #[derive(Default)]
238/// # struct MyPattern;
239/// # #[derive(Default)]
240/// # struct MyOtherPattern;
241/// #
242/// let pat = pattern!("[{level}] {payload} - {$mypat} {$myotherpat}{eol}",
243/// {$mypat} => MyPattern::default,
244/// {$myotherpat} => MyOtherPattern::default,
245/// );
246/// ```
247///
248/// ## Name Conflicts are Hard Errors
249///
250/// It's a hard error if names of your own custom pattern conflicts with other
251/// patterns:
252///
253/// ```compile_fail
254/// # use spdlog::formatter::pattern;
255/// #
256/// # #[derive(Default)]
257/// # struct MyPattern;
258/// # #[derive(Default)]
259/// # struct MyOtherPattern;
260/// #
261/// let pattern = pattern!("[{level}] {payload} - {$mypat}{eol}",
262/// {$mypat} => MyPattern::new,
263/// // Error: name conflicts with another custom pattern
264/// {$mypat} => MyOtherPattern::new,
265/// );
266/// ```
267///
268/// ```compile_fail
269/// # use spdlog::formatter::pattern;
270/// #
271/// # #[derive(Default)]
272/// # struct MyPattern;
273/// #
274/// let pattern = pattern!("[{level}] {payload} - {$day}{eol}",
275/// // Error: name conflicts with a built-in pattern
276/// {$day} => MyPattern::new,
277/// );
278/// ```
279///
280/// # Appendix: Full List of Built-in Patterns
281///
282/// | Placeholders | Description | Example |
283/// | --------------------- | ---------------------------- | -------------------------------------------- |
284/// | `{weekday_name}` | Abbreviated weekday name | `Mon`, `Tue` |
285/// | `{weekday_name_full}` | Weekday name | `Monday`, `Tuesday` |
286/// | `{month_name}` | Abbreviated month name | `Jan`, `Feb` |
287/// | `{month_name_full}` | Month name | `January`, `February` |
288/// | `{datetime}` | Full date time | `Thu Aug 23 15:35:46 2014` |
289/// | `{year_short}` | Short year | `22`, `20` |
290/// | `{year}` | Year | `2022`, `2021` |
291/// | `{date_short}` | Short date | `04/01/22`, `12/31/21` |
292/// | `{date}` | Date (ISO 8601) | `2022-04-01`, `2021-12-31` |
293/// | `{month}` | Month | `01`, `12` |
294/// | `{day}` | Day in month | `01`, `12`, `31`, `30` |
295/// | `{hour}` | Hour in 24-hour | `01`, `12`, `23` |
296/// | `{hour_12}` | Hour in 12-hour | `01`, `12` |
297/// | `{minute}` | Minute | `00`, `05`, `59` |
298/// | `{second}` | Second | `00`, `05`, `59` |
299/// | `{millisecond}` | Millisecond | `231` |
300/// | `{microsecond}` | Microseconds within a second | `372152` |
301/// | `{nanosecond}` | Nanoseconds within a second | `482930154` |
302/// | `{am_pm}` | AM / PM | `AM`, `PM` |
303/// | `{time_12}` | Time in 12-hour format | `02:55:02 PM` |
304/// | `{time_short}` | Short time | `22:28`, `09:53` |
305/// | `{time}` | Time | `22:28:02`, `09:53:41` |
306/// | `{tz_offset}` | Timezone offset | `+08:00`, `+00:00`, `-06:00` |
307/// | `{unix_timestamp}` | Unix timestamp | `1528834770` |
308/// | `{full}` | Full log message | See [`FullFormatter`] |
309/// | `{level}` | Log level | `critical`, `error`, `warn` |
310/// | `{level_short}` | Short log level | `C`, `E`, `W` |
311/// | `{source}` | Source file and line | `path/to/main.rs:30` [^1] |
312/// | `{file_name}` | Source file name | `main.rs` [^1] |
313/// | `{file}` | Source file path | `path/to/main.rs` [^1] |
314/// | `{line}` | Source file line | `30` [^1] |
315/// | `{column}` | Source file column | `20` [^1] |
316/// | `{module_path}` | Source module path | `mod::module` [^1] |
317/// | `{logger}` | Logger name | `my-logger` |
318/// | `{payload}` | Log payload | `log message` |
319/// | `{kv}` | Key-values | `k1=123 k2=text` |
320/// | `{pid}` | Process ID | `3824` |
321/// | `{tid}` | Thread ID | `3132` |
322/// | `{eol}` | End of line | `\n` (on non-Windows) or `\r\n` (on Windows) |
323///
324/// [^1]: Patterns related to source location require that feature
325/// `source-location` is enabled, otherwise the output is empty.
326///
327/// [`runtime_pattern!`]: crate::formatter::runtime_pattern
328/// [`FullFormatter`]: crate::formatter::FullFormatter
329pub use ::spdlog_macros::pattern;
330
331// Emit a compile error if the feature is not enabled.
332#[cfg(not(feature = "runtime-pattern"))]
333pub use crate::__runtime_pattern_disabled as runtime_pattern;
334
335#[cfg(not(feature = "runtime-pattern"))]
336#[doc(hidden)]
337#[macro_export]
338macro_rules! __runtime_pattern_disabled {
339 ($($_:tt)*) => {
340 compile_error!(
341 "macro `runtime_pattern` required to enable crate feature `runtime-pattern` for spdlog-rs"
342 );
343 };
344}
345
346/// Formats logs according to a specified pattern.
347#[derive(Clone)]
348pub struct PatternFormatter<P> {
349 pattern: P,
350}
351
352impl<P> PatternFormatter<P>
353where
354 P: Pattern,
355{
356 /// Creates a new `PatternFormatter` object with the given pattern.
357 ///
358 /// Currently users can only create a `pattern` object by using:
359 ///
360 /// - Macro [`pattern!`] to build a pattern with a literal template string
361 /// at compile-time.
362 /// - Macro [`runtime_pattern!`] to build a pattern at runtime.
363 #[must_use]
364 pub fn new(pattern: P) -> Self {
365 Self { pattern }
366 }
367}
368
369impl<P> Formatter for PatternFormatter<P>
370where
371 P: 'static + Clone + Pattern,
372{
373 fn format(
374 &self,
375 record: &Record,
376 dest: &mut StringBuf,
377 fmt_ctx: &mut FormatterContext,
378 ) -> crate::Result<()> {
379 #[cfg(not(feature = "flexible-string"))]
380 dest.reserve(crate::string_buf::RESERVE_SIZE);
381
382 fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
383 {
384 let mut pat_ctx = PatternContext { fmt_ctx };
385 self.pattern.format(record, dest, &mut pat_ctx)?;
386 }
387 fmt_ctx.locked_time_date = None;
388 Ok(())
389 }
390}
391
392/// Provides context for patterns.
393///
394/// There is nothing to set up here at the moment, reserved for future use.
395#[derive(Debug)]
396pub struct PatternContext<'a, 'b> {
397 fmt_ctx: &'a mut FormatterContext<'b>,
398}
399
400impl PatternContext<'_, '_> {
401 #[must_use]
402 fn time_date(&mut self) -> TimeDate<'_> {
403 self.fmt_ctx.locked_time_date.as_mut().unwrap().get()
404 }
405}
406
407/// Represents a pattern for replacing a placeholder in templates.
408///
409/// A pattern will be used to replace placeholders that appear in a template
410/// string. Multiple patterns can form a new pattern. The [`PatternFormatter`]
411/// formats logs according to a given pattern.
412///
413/// # Built-in Patterns
414///
415/// `spdlog-rs` provides a rich set of built-in patterns. See the [`pattern`]
416/// macro.
417///
418/// # Custom Patterns
419///
420/// There are 3 approaches to create your own pattern:
421/// - Define a new type and implement this trait;
422/// - Use [`pattern`] macro to create a pattern from a literal template string.
423/// - Use [`runtime_pattern`] macro to create a pattern from a runtime template
424/// string.
425pub trait Pattern: Send + Sync + DynClone {
426 /// Format this pattern against the given log record and write the formatted
427 /// message into the output buffer.
428 ///
429 /// **For implementors:** the `ctx` parameter is reserved for future use.
430 /// For now, please ignore it.
431 fn format(
432 &self,
433 record: &Record,
434 dest: &mut StringBuf,
435 ctx: &mut PatternContext,
436 ) -> crate::Result<()>;
437}
438clone_trait_object!(Pattern);
439
440impl Pattern for String {
441 fn format(
442 &self,
443 record: &Record,
444 dest: &mut StringBuf,
445 ctx: &mut PatternContext,
446 ) -> crate::Result<()> {
447 <&str as Pattern>::format(&&**self, record, dest, ctx)
448 }
449}
450
451impl Pattern for str {
452 fn format(
453 &self,
454 _record: &Record,
455 dest: &mut StringBuf,
456 _ctx: &mut PatternContext,
457 ) -> crate::Result<()> {
458 dest.write_str(self).map_err(Error::FormatRecord)
459 }
460}
461
462impl<T> Pattern for &T
463where
464 T: ?Sized + Pattern,
465{
466 fn format(
467 &self,
468 record: &Record,
469 dest: &mut StringBuf,
470 ctx: &mut PatternContext,
471 ) -> crate::Result<()> {
472 <T as Pattern>::format(*self, record, dest, ctx)
473 }
474}
475
476impl<T> Pattern for Box<T>
477where
478 T: ?Sized + Pattern,
479 Self: Clone,
480{
481 fn format(
482 &self,
483 record: &Record,
484 dest: &mut StringBuf,
485 ctx: &mut PatternContext,
486 ) -> crate::Result<()> {
487 <T as Pattern>::format(&**self, record, dest, ctx)
488 }
489}
490
491impl<T> Pattern for Arc<T>
492where
493 T: ?Sized + Pattern,
494 Self: Clone,
495{
496 fn format(
497 &self,
498 record: &Record,
499 dest: &mut StringBuf,
500 ctx: &mut PatternContext,
501 ) -> crate::Result<()> {
502 <T as Pattern>::format(&**self, record, dest, ctx)
503 }
504}
505
506impl<T> Pattern for &[T]
507where
508 T: Pattern,
509 Self: Clone,
510{
511 fn format(
512 &self,
513 record: &Record,
514 dest: &mut StringBuf,
515 ctx: &mut PatternContext,
516 ) -> crate::Result<()> {
517 for p in *self {
518 <T as Pattern>::format(p, record, dest, ctx)?;
519 }
520 Ok(())
521 }
522}
523
524impl<T, const N: usize> Pattern for [T; N]
525where
526 T: Pattern,
527 Self: Clone,
528{
529 fn format(
530 &self,
531 record: &Record,
532 dest: &mut StringBuf,
533 ctx: &mut PatternContext,
534 ) -> crate::Result<()> {
535 for p in self {
536 <T as Pattern>::format(p, record, dest, ctx)?;
537 }
538 Ok(())
539 }
540}
541
542impl<T> Pattern for Vec<T>
543where
544 T: Pattern,
545 Self: Clone,
546{
547 fn format(
548 &self,
549 record: &Record,
550 dest: &mut StringBuf,
551 ctx: &mut PatternContext,
552 ) -> crate::Result<()> {
553 for p in self {
554 <T as Pattern>::format(p, record, dest, ctx)?;
555 }
556 Ok(())
557 }
558}
559
560macro_rules! last {
561 ( $a:tt, ) => { $a };
562 ( $a:tt, $($rest:tt,)+ ) => { last!($($rest,)+) };
563}
564
565macro_rules! tuple_pattern {
566 (
567 $(
568 $Tuple:ident {
569 $(
570 ($idx:tt) -> $T:ident
571 )+
572 }
573 )+
574 ) => {
575 $(
576 impl<$($T,)+> Pattern for ($($T,)+)
577 where
578 $($T : Pattern,)+
579 last!($($T,)+) : ?Sized,
580 Self: Clone,
581 {
582 fn format(&self, record: &Record, dest: &mut StringBuf, ctx: &mut PatternContext) -> crate::Result<()> {
583 $(
584 <$T as Pattern>::format(&self.$idx, record, dest, ctx)?;
585 )+
586 Ok(())
587 }
588 }
589 )+
590 };
591}
592
593impl Pattern for () {
594 fn format(
595 &self,
596 _record: &Record,
597 _dest: &mut StringBuf,
598 _ctx: &mut PatternContext,
599 ) -> crate::Result<()> {
600 Ok(())
601 }
602}
603
604tuple_pattern! {
605 Tuple1 {
606 (0) -> T0
607 }
608 Tuple2 {
609 (0) -> T0
610 (1) -> T1
611 }
612 Tuple3 {
613 (0) -> T0
614 (1) -> T1
615 (2) -> T2
616 }
617 Tuple4 {
618 (0) -> T0
619 (1) -> T1
620 (2) -> T2
621 (3) -> T3
622 }
623 Tuple5 {
624 (0) -> T0
625 (1) -> T1
626 (2) -> T2
627 (3) -> T3
628 (4) -> T4
629 }
630 Tuple6 {
631 (0) -> T0
632 (1) -> T1
633 (2) -> T2
634 (3) -> T3
635 (4) -> T4
636 (5) -> T5
637 }
638 Tuple7 {
639 (0) -> T0
640 (1) -> T1
641 (2) -> T2
642 (3) -> T3
643 (4) -> T4
644 (5) -> T5
645 (6) -> T6
646 }
647 Tuple8 {
648 (0) -> T0
649 (1) -> T1
650 (2) -> T2
651 (3) -> T3
652 (4) -> T4
653 (5) -> T5
654 (6) -> T6
655 (7) -> T7
656 }
657 Tuple9 {
658 (0) -> T0
659 (1) -> T1
660 (2) -> T2
661 (3) -> T3
662 (4) -> T4
663 (5) -> T5
664 (6) -> T6
665 (7) -> T7
666 (8) -> T8
667 }
668 Tuple10 {
669 (0) -> T0
670 (1) -> T1
671 (2) -> T2
672 (3) -> T3
673 (4) -> T4
674 (5) -> T5
675 (6) -> T6
676 (7) -> T7
677 (8) -> T8
678 (9) -> T9
679 }
680 Tuple11 {
681 (0) -> T0
682 (1) -> T1
683 (2) -> T2
684 (3) -> T3
685 (4) -> T4
686 (5) -> T5
687 (6) -> T6
688 (7) -> T7
689 (8) -> T8
690 (9) -> T9
691 (10) -> T10
692 }
693 Tuple12 {
694 (0) -> T0
695 (1) -> T1
696 (2) -> T2
697 (3) -> T3
698 (4) -> T4
699 (5) -> T5
700 (6) -> T6
701 (7) -> T7
702 (8) -> T8
703 (9) -> T9
704 (10) -> T10
705 (11) -> T11
706 }
707 Tuple13 {
708 (0) -> T0
709 (1) -> T1
710 (2) -> T2
711 (3) -> T3
712 (4) -> T4
713 (5) -> T5
714 (6) -> T6
715 (7) -> T7
716 (8) -> T8
717 (9) -> T9
718 (10) -> T10
719 (11) -> T11
720 (12) -> T12
721 }
722 Tuple14 {
723 (0) -> T0
724 (1) -> T1
725 (2) -> T2
726 (3) -> T3
727 (4) -> T4
728 (5) -> T5
729 (6) -> T6
730 (7) -> T7
731 (8) -> T8
732 (9) -> T9
733 (10) -> T10
734 (11) -> T11
735 (12) -> T12
736 (13) -> T13
737 }
738 Tuple15 {
739 (0) -> T0
740 (1) -> T1
741 (2) -> T2
742 (3) -> T3
743 (4) -> T4
744 (5) -> T5
745 (6) -> T6
746 (7) -> T7
747 (8) -> T8
748 (9) -> T9
749 (10) -> T10
750 (11) -> T11
751 (12) -> T12
752 (13) -> T13
753 (14) -> T14
754 }
755 Tuple16 {
756 (0) -> T0
757 (1) -> T1
758 (2) -> T2
759 (3) -> T3
760 (4) -> T4
761 (5) -> T5
762 (6) -> T6
763 (7) -> T7
764 (8) -> T8
765 (9) -> T9
766 (10) -> T10
767 (11) -> T11
768 (12) -> T12
769 (13) -> T13
770 (14) -> T14
771 (15) -> T15
772 }
773 Tuple17 {
774 (0) -> T0
775 (1) -> T1
776 (2) -> T2
777 (3) -> T3
778 (4) -> T4
779 (5) -> T5
780 (6) -> T6
781 (7) -> T7
782 (8) -> T8
783 (9) -> T9
784 (10) -> T10
785 (11) -> T11
786 (12) -> T12
787 (13) -> T13
788 (14) -> T14
789 (15) -> T15
790 (16) -> T16
791 }
792 Tuple18 {
793 (0) -> T0
794 (1) -> T1
795 (2) -> T2
796 (3) -> T3
797 (4) -> T4
798 (5) -> T5
799 (6) -> T6
800 (7) -> T7
801 (8) -> T8
802 (9) -> T9
803 (10) -> T10
804 (11) -> T11
805 (12) -> T12
806 (13) -> T13
807 (14) -> T14
808 (15) -> T15
809 (16) -> T16
810 (17) -> T17
811 }
812 Tuple19 {
813 (0) -> T0
814 (1) -> T1
815 (2) -> T2
816 (3) -> T3
817 (4) -> T4
818 (5) -> T5
819 (6) -> T6
820 (7) -> T7
821 (8) -> T8
822 (9) -> T9
823 (10) -> T10
824 (11) -> T11
825 (12) -> T12
826 (13) -> T13
827 (14) -> T14
828 (15) -> T15
829 (16) -> T16
830 (17) -> T17
831 (18) -> T18
832 }
833 Tuple20 {
834 (0) -> T0
835 (1) -> T1
836 (2) -> T2
837 (3) -> T3
838 (4) -> T4
839 (5) -> T5
840 (6) -> T6
841 (7) -> T7
842 (8) -> T8
843 (9) -> T9
844 (10) -> T10
845 (11) -> T11
846 (12) -> T12
847 (13) -> T13
848 (14) -> T14
849 (15) -> T15
850 (16) -> T16
851 (17) -> T17
852 (18) -> T18
853 (19) -> T19
854 }
855 Tuple21 {
856 (0) -> T0
857 (1) -> T1
858 (2) -> T2
859 (3) -> T3
860 (4) -> T4
861 (5) -> T5
862 (6) -> T6
863 (7) -> T7
864 (8) -> T8
865 (9) -> T9
866 (10) -> T10
867 (11) -> T11
868 (12) -> T12
869 (13) -> T13
870 (14) -> T14
871 (15) -> T15
872 (16) -> T16
873 (17) -> T17
874 (18) -> T18
875 (19) -> T19
876 (20) -> T20
877 }
878 Tuple22 {
879 (0) -> T0
880 (1) -> T1
881 (2) -> T2
882 (3) -> T3
883 (4) -> T4
884 (5) -> T5
885 (6) -> T6
886 (7) -> T7
887 (8) -> T8
888 (9) -> T9
889 (10) -> T10
890 (11) -> T11
891 (12) -> T12
892 (13) -> T13
893 (14) -> T14
894 (15) -> T15
895 (16) -> T16
896 (17) -> T17
897 (18) -> T18
898 (19) -> T19
899 (20) -> T20
900 (21) -> T21
901 }
902 Tuple23 {
903 (0) -> T0
904 (1) -> T1
905 (2) -> T2
906 (3) -> T3
907 (4) -> T4
908 (5) -> T5
909 (6) -> T6
910 (7) -> T7
911 (8) -> T8
912 (9) -> T9
913 (10) -> T10
914 (11) -> T11
915 (12) -> T12
916 (13) -> T13
917 (14) -> T14
918 (15) -> T15
919 (16) -> T16
920 (17) -> T17
921 (18) -> T18
922 (19) -> T19
923 (20) -> T20
924 (21) -> T21
925 (22) -> T22
926 }
927 Tuple24 {
928 (0) -> T0
929 (1) -> T1
930 (2) -> T2
931 (3) -> T3
932 (4) -> T4
933 (5) -> T5
934 (6) -> T6
935 (7) -> T7
936 (8) -> T8
937 (9) -> T9
938 (10) -> T10
939 (11) -> T11
940 (12) -> T12
941 (13) -> T13
942 (14) -> T14
943 (15) -> T15
944 (16) -> T16
945 (17) -> T17
946 (18) -> T18
947 (19) -> T19
948 (20) -> T20
949 (21) -> T21
950 (22) -> T22
951 (23) -> T23
952 }
953 Tuple25 {
954 (0) -> T0
955 (1) -> T1
956 (2) -> T2
957 (3) -> T3
958 (4) -> T4
959 (5) -> T5
960 (6) -> T6
961 (7) -> T7
962 (8) -> T8
963 (9) -> T9
964 (10) -> T10
965 (11) -> T11
966 (12) -> T12
967 (13) -> T13
968 (14) -> T14
969 (15) -> T15
970 (16) -> T16
971 (17) -> T17
972 (18) -> T18
973 (19) -> T19
974 (20) -> T20
975 (21) -> T21
976 (22) -> T22
977 (23) -> T23
978 (24) -> T24
979 }
980 Tuple26 {
981 (0) -> T0
982 (1) -> T1
983 (2) -> T2
984 (3) -> T3
985 (4) -> T4
986 (5) -> T5
987 (6) -> T6
988 (7) -> T7
989 (8) -> T8
990 (9) -> T9
991 (10) -> T10
992 (11) -> T11
993 (12) -> T12
994 (13) -> T13
995 (14) -> T14
996 (15) -> T15
997 (16) -> T16
998 (17) -> T17
999 (18) -> T18
1000 (19) -> T19
1001 (20) -> T20
1002 (21) -> T21
1003 (22) -> T22
1004 (23) -> T23
1005 (24) -> T24
1006 (25) -> T25
1007 }
1008 Tuple27 {
1009 (0) -> T0
1010 (1) -> T1
1011 (2) -> T2
1012 (3) -> T3
1013 (4) -> T4
1014 (5) -> T5
1015 (6) -> T6
1016 (7) -> T7
1017 (8) -> T8
1018 (9) -> T9
1019 (10) -> T10
1020 (11) -> T11
1021 (12) -> T12
1022 (13) -> T13
1023 (14) -> T14
1024 (15) -> T15
1025 (16) -> T16
1026 (17) -> T17
1027 (18) -> T18
1028 (19) -> T19
1029 (20) -> T20
1030 (21) -> T21
1031 (22) -> T22
1032 (23) -> T23
1033 (24) -> T24
1034 (25) -> T25
1035 (26) -> T26
1036 }
1037 Tuple28 {
1038 (0) -> T0
1039 (1) -> T1
1040 (2) -> T2
1041 (3) -> T3
1042 (4) -> T4
1043 (5) -> T5
1044 (6) -> T6
1045 (7) -> T7
1046 (8) -> T8
1047 (9) -> T9
1048 (10) -> T10
1049 (11) -> T11
1050 (12) -> T12
1051 (13) -> T13
1052 (14) -> T14
1053 (15) -> T15
1054 (16) -> T16
1055 (17) -> T17
1056 (18) -> T18
1057 (19) -> T19
1058 (20) -> T20
1059 (21) -> T21
1060 (22) -> T22
1061 (23) -> T23
1062 (24) -> T24
1063 (25) -> T25
1064 (26) -> T26
1065 (27) -> T27
1066 }
1067 Tuple29 {
1068 (0) -> T0
1069 (1) -> T1
1070 (2) -> T2
1071 (3) -> T3
1072 (4) -> T4
1073 (5) -> T5
1074 (6) -> T6
1075 (7) -> T7
1076 (8) -> T8
1077 (9) -> T9
1078 (10) -> T10
1079 (11) -> T11
1080 (12) -> T12
1081 (13) -> T13
1082 (14) -> T14
1083 (15) -> T15
1084 (16) -> T16
1085 (17) -> T17
1086 (18) -> T18
1087 (19) -> T19
1088 (20) -> T20
1089 (21) -> T21
1090 (22) -> T22
1091 (23) -> T23
1092 (24) -> T24
1093 (25) -> T25
1094 (26) -> T26
1095 (27) -> T27
1096 (28) -> T28
1097 }
1098 Tuple30 {
1099 (0) -> T0
1100 (1) -> T1
1101 (2) -> T2
1102 (3) -> T3
1103 (4) -> T4
1104 (5) -> T5
1105 (6) -> T6
1106 (7) -> T7
1107 (8) -> T8
1108 (9) -> T9
1109 (10) -> T10
1110 (11) -> T11
1111 (12) -> T12
1112 (13) -> T13
1113 (14) -> T14
1114 (15) -> T15
1115 (16) -> T16
1116 (17) -> T17
1117 (18) -> T18
1118 (19) -> T19
1119 (20) -> T20
1120 (21) -> T21
1121 (22) -> T22
1122 (23) -> T23
1123 (24) -> T24
1124 (25) -> T25
1125 (26) -> T26
1126 (27) -> T27
1127 (28) -> T28
1128 (29) -> T29
1129 }
1130 Tuple31 {
1131 (0) -> T0
1132 (1) -> T1
1133 (2) -> T2
1134 (3) -> T3
1135 (4) -> T4
1136 (5) -> T5
1137 (6) -> T6
1138 (7) -> T7
1139 (8) -> T8
1140 (9) -> T9
1141 (10) -> T10
1142 (11) -> T11
1143 (12) -> T12
1144 (13) -> T13
1145 (14) -> T14
1146 (15) -> T15
1147 (16) -> T16
1148 (17) -> T17
1149 (18) -> T18
1150 (19) -> T19
1151 (20) -> T20
1152 (21) -> T21
1153 (22) -> T22
1154 (23) -> T23
1155 (24) -> T24
1156 (25) -> T25
1157 (26) -> T26
1158 (27) -> T27
1159 (28) -> T28
1160 (29) -> T29
1161 (30) -> T30
1162 }
1163 Tuple32 {
1164 (0) -> T0
1165 (1) -> T1
1166 (2) -> T2
1167 (3) -> T3
1168 (4) -> T4
1169 (5) -> T5
1170 (6) -> T6
1171 (7) -> T7
1172 (8) -> T8
1173 (9) -> T9
1174 (10) -> T10
1175 (11) -> T11
1176 (12) -> T12
1177 (13) -> T13
1178 (14) -> T14
1179 (15) -> T15
1180 (16) -> T16
1181 (17) -> T17
1182 (18) -> T18
1183 (19) -> T19
1184 (20) -> T20
1185 (21) -> T21
1186 (22) -> T22
1187 (23) -> T23
1188 (24) -> T24
1189 (25) -> T25
1190 (26) -> T26
1191 (27) -> T27
1192 (28) -> T28
1193 (29) -> T29
1194 (30) -> T30
1195 (31) -> T31
1196 }
1197}
1198
1199#[cfg(test)]
1200mod tests {
1201 use std::ops::Range;
1202
1203 use super::*;
1204 use crate::{Level, SourceLocation};
1205
1206 // We use `get_mock_record` and `test_pattern` in tests/pattern.rs so let's make
1207 // them pub in test builds.
1208
1209 #[must_use]
1210 fn get_mock_record() -> Record<'static> {
1211 Record::new(
1212 Level::Info,
1213 "record_payload",
1214 Some(SourceLocation::__new("module", "file", 10, 20)),
1215 Some("logger_name"),
1216 &[],
1217 )
1218 }
1219
1220 fn test_pattern<P, T>(pattern: P, formatted: T, style_range: Option<Range<usize>>)
1221 where
1222 P: Pattern,
1223 T: AsRef<str>,
1224 {
1225 let record = get_mock_record();
1226 let mut output = StringBuf::new();
1227 let mut fmt_ctx = FormatterContext::new();
1228 fmt_ctx.locked_time_date = Some(TimeDateLazyLocked::new(record.time()));
1229 let mut pat_ctx = PatternContext {
1230 fmt_ctx: &mut fmt_ctx,
1231 };
1232 pattern.format(&record, &mut output, &mut pat_ctx).unwrap();
1233 fmt_ctx.locked_time_date = None;
1234
1235 assert_eq!(output.as_str(), formatted.as_ref());
1236 assert_eq!(fmt_ctx.style_range(), style_range);
1237 }
1238
1239 #[test]
1240 fn test_string_as_pattern() {
1241 test_pattern(String::from("literal"), "literal", None);
1242 }
1243
1244 #[test]
1245 fn test_str_as_pattern() {
1246 test_pattern("literal", "literal", None);
1247 }
1248
1249 #[test]
1250 fn test_pattern_ref_as_pattern() {
1251 #[allow(unknown_lints)]
1252 #[allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args)]
1253 test_pattern(&String::from("literal"), "literal", None);
1254 }
1255
1256 #[test]
1257 fn test_pattern_mut_as_pattern() {
1258 // Since we now require `T: Pattern` to implement `Clone`, there is no way to
1259 // accept an `&mut T` as a `Pattern` anymore, since `&mut T` is not cloneable.
1260 //
1261 // test_pattern(&mut String::from("literal"), "literal", None);
1262 #[allow(clippy::deref_addrof)]
1263 test_pattern(&*&mut String::from("literal"), "literal", None);
1264 }
1265
1266 #[test]
1267 fn test_box_as_pattern() {
1268 test_pattern(Box::new(String::from("literal")), "literal", None);
1269 }
1270
1271 #[test]
1272 fn test_arc_as_pattern() {
1273 test_pattern(Arc::new(String::from("literal")), "literal", None);
1274 }
1275
1276 #[test]
1277 fn test_slice_as_pattern() {
1278 let pat: &[String] = &[String::from("literal1"), String::from("literal2")];
1279 test_pattern(pat, "literal1literal2", None);
1280 }
1281
1282 #[test]
1283 fn test_empty_slice_as_pattern() {
1284 let pat: &[String] = &[];
1285 test_pattern(pat, "", None);
1286 }
1287
1288 #[test]
1289 fn test_array_as_pattern() {
1290 let pat: [String; 3] = [
1291 String::from("literal1"),
1292 String::from("literal2"),
1293 String::from("literal3"),
1294 ];
1295 test_pattern(pat, "literal1literal2literal3", None);
1296 }
1297
1298 #[test]
1299 fn test_empty_array_as_pattern() {
1300 let pat: [String; 0] = [];
1301 test_pattern(pat, "", None);
1302 }
1303
1304 #[test]
1305 fn test_vec_as_pattern() {
1306 let pat = vec![
1307 String::from("literal1"),
1308 String::from("literal2"),
1309 String::from("literal3"),
1310 ];
1311 test_pattern(pat, "literal1literal2literal3", None);
1312 }
1313
1314 #[test]
1315 fn test_empty_vec_as_pattern() {
1316 let pat: Vec<String> = vec![];
1317 test_pattern(pat, "", None);
1318 }
1319
1320 #[test]
1321 fn test_tuple_as_pattern() {
1322 let pat = (
1323 String::from("literal1"),
1324 "literal2",
1325 String::from("literal3"),
1326 );
1327 test_pattern(pat, "literal1literal2literal3", None);
1328 }
1329
1330 #[test]
1331 fn test_unit_as_pattern() {
1332 test_pattern((), "", None);
1333 }
1334}