1 //! `MakeVisitor` wrappers for working with `fmt::Display` fields.
2 use super::{MakeVisitor, VisitFmt, VisitOutput};
3 use tracing_core::field::{Field, Visit};
4 
5 use core::fmt;
6 
7 /// A visitor wrapper that ensures any strings named "message" are formatted
8 /// using `fmt::Display`
9 #[derive(Debug, Clone)]
10 pub struct Messages<V>(V);
11 
12 // TODO(eliza): When `error` as a primitive type is stable, add a
13 // `DisplayErrors` wrapper...
14 
15 // === impl Messages ===
16 //
17 impl<V> Messages<V> {
18     /// Returns a new [`MakeVisitor`] implementation that will wrap `inner` so
19     /// that any strings named `message` are formatted using `fmt::Display`.
20     ///
21     /// [`MakeVisitor`]: super::MakeVisitor
new(inner: V) -> Self22     pub fn new(inner: V) -> Self {
23         Messages(inner)
24     }
25 }
26 
27 impl<T, V> MakeVisitor<T> for Messages<V>
28 where
29     V: MakeVisitor<T>,
30 {
31     type Visitor = Messages<V::Visitor>;
32 
33     #[inline]
make_visitor(&self, target: T) -> Self::Visitor34     fn make_visitor(&self, target: T) -> Self::Visitor {
35         Messages(self.0.make_visitor(target))
36     }
37 }
38 
39 impl<V> Visit for Messages<V>
40 where
41     V: Visit,
42 {
43     #[inline]
record_f64(&mut self, field: &Field, value: f64)44     fn record_f64(&mut self, field: &Field, value: f64) {
45         self.0.record_f64(field, value)
46     }
47 
48     #[inline]
record_i64(&mut self, field: &Field, value: i64)49     fn record_i64(&mut self, field: &Field, value: i64) {
50         self.0.record_i64(field, value)
51     }
52 
53     #[inline]
record_u64(&mut self, field: &Field, value: u64)54     fn record_u64(&mut self, field: &Field, value: u64) {
55         self.0.record_u64(field, value)
56     }
57 
58     #[inline]
record_bool(&mut self, field: &Field, value: bool)59     fn record_bool(&mut self, field: &Field, value: bool) {
60         self.0.record_bool(field, value)
61     }
62 
63     /// Visit a string value.
record_str(&mut self, field: &Field, value: &str)64     fn record_str(&mut self, field: &Field, value: &str) {
65         if field.name() == "message" {
66             self.0.record_debug(field, &format_args!("{}", value))
67         } else {
68             self.0.record_str(field, value)
69         }
70     }
71 
72     // TODO(eliza): add RecordError when stable
73     // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
74     //     self.record_debug(field, &format_args!("{}", value))
75     // }
76 
77     #[inline]
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)78     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
79         self.0.record_debug(field, value)
80     }
81 }
82 
83 impl<V, O> VisitOutput<O> for Messages<V>
84 where
85     V: VisitOutput<O>,
86 {
87     #[inline]
finish(self) -> O88     fn finish(self) -> O {
89         self.0.finish()
90     }
91 }
92 
93 feature! {
94     #![feature = "std"]
95     use super::VisitWrite;
96     use std::io;
97 
98     impl<V> VisitWrite for Messages<V>
99     where
100         V: VisitWrite,
101     {
102         #[inline]
103         fn writer(&mut self) -> &mut dyn io::Write {
104             self.0.writer()
105         }
106     }
107 }
108 
109 impl<V> VisitFmt for Messages<V>
110 where
111     V: VisitFmt,
112 {
113     #[inline]
writer(&mut self) -> &mut dyn fmt::Write114     fn writer(&mut self) -> &mut dyn fmt::Write {
115         self.0.writer()
116     }
117 }
118