1 //! A `MakeVisitor` wrapper that separates formatted fields with a delimiter. 2 use super::{MakeVisitor, VisitFmt, VisitOutput}; 3 4 use core::fmt; 5 use tracing_core::field::{Field, Visit}; 6 7 /// A `MakeVisitor` wrapper that wraps a visitor that writes formatted output so 8 /// that a delimiter is inserted between writing formatted field values. 9 #[derive(Debug, Clone)] 10 pub struct Delimited<D, V> { 11 delimiter: D, 12 inner: V, 13 } 14 15 /// A visitor wrapper that inserts a delimiter after the wrapped visitor formats 16 /// a field value. 17 #[derive(Debug)] 18 pub struct VisitDelimited<D, V> { 19 delimiter: D, 20 seen: bool, 21 inner: V, 22 err: fmt::Result, 23 } 24 25 // === impl Delimited === 26 27 impl<D, V, T> MakeVisitor<T> for Delimited<D, V> 28 where 29 D: AsRef<str> + Clone, 30 V: MakeVisitor<T>, 31 V::Visitor: VisitFmt, 32 { 33 type Visitor = VisitDelimited<D, V::Visitor>; make_visitor(&self, target: T) -> Self::Visitor34 fn make_visitor(&self, target: T) -> Self::Visitor { 35 let inner = self.inner.make_visitor(target); 36 VisitDelimited::new(self.delimiter.clone(), inner) 37 } 38 } 39 40 impl<D, V> Delimited<D, V> { 41 /// Returns a new [`MakeVisitor`] implementation that wraps `inner` so that 42 /// it will format each visited field separated by the provided `delimiter`. 43 /// 44 /// [`MakeVisitor`]: super::MakeVisitor new(delimiter: D, inner: V) -> Self45 pub fn new(delimiter: D, inner: V) -> Self { 46 Self { delimiter, inner } 47 } 48 } 49 50 // === impl VisitDelimited === 51 52 impl<D, V> VisitDelimited<D, V> { 53 /// Returns a new [`Visit`] implementation that wraps `inner` so that 54 /// each formatted field is separated by the provided `delimiter`. 55 /// 56 /// [`Visit`]: tracing_core::field::Visit new(delimiter: D, inner: V) -> Self57 pub fn new(delimiter: D, inner: V) -> Self { 58 Self { 59 delimiter, 60 inner, 61 seen: false, 62 err: Ok(()), 63 } 64 } 65 delimit(&mut self) where V: VisitFmt, D: AsRef<str>,66 fn delimit(&mut self) 67 where 68 V: VisitFmt, 69 D: AsRef<str>, 70 { 71 if self.err.is_err() { 72 return; 73 } 74 75 if self.seen { 76 self.err = self.inner.writer().write_str(self.delimiter.as_ref()); 77 } 78 79 self.seen = true; 80 } 81 } 82 83 impl<D, V> Visit for VisitDelimited<D, V> 84 where 85 V: VisitFmt, 86 D: AsRef<str>, 87 { record_i64(&mut self, field: &Field, value: i64)88 fn record_i64(&mut self, field: &Field, value: i64) { 89 self.delimit(); 90 self.inner.record_i64(field, value); 91 } 92 record_u64(&mut self, field: &Field, value: u64)93 fn record_u64(&mut self, field: &Field, value: u64) { 94 self.delimit(); 95 self.inner.record_u64(field, value); 96 } 97 record_bool(&mut self, field: &Field, value: bool)98 fn record_bool(&mut self, field: &Field, value: bool) { 99 self.delimit(); 100 self.inner.record_bool(field, value); 101 } 102 record_str(&mut self, field: &Field, value: &str)103 fn record_str(&mut self, field: &Field, value: &str) { 104 self.delimit(); 105 self.inner.record_str(field, value); 106 } 107 record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)108 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) { 109 self.delimit(); 110 self.inner.record_debug(field, value); 111 } 112 } 113 114 impl<D, V> VisitOutput<fmt::Result> for VisitDelimited<D, V> 115 where 116 V: VisitFmt, 117 D: AsRef<str>, 118 { finish(self) -> fmt::Result119 fn finish(self) -> fmt::Result { 120 self.err?; 121 self.inner.finish() 122 } 123 } 124 125 impl<D, V> VisitFmt for VisitDelimited<D, V> 126 where 127 V: VisitFmt, 128 D: AsRef<str>, 129 { writer(&mut self) -> &mut dyn fmt::Write130 fn writer(&mut self) -> &mut dyn fmt::Write { 131 self.inner.writer() 132 } 133 } 134 135 #[cfg(test)] 136 #[cfg(all(test, feature = "alloc"))] 137 mod test { 138 use super::*; 139 use crate::field::test_util::*; 140 141 #[test] delimited_visitor()142 fn delimited_visitor() { 143 let mut s = String::new(); 144 let visitor = DebugVisitor::new(&mut s); 145 let mut visitor = VisitDelimited::new(", ", visitor); 146 147 TestAttrs1::with(|attrs| attrs.record(&mut visitor)); 148 visitor.finish().unwrap(); 149 150 assert_eq!( 151 s.as_str(), 152 "question=\"life, the universe, and everything\", tricky=true, can_you_do_it=true" 153 ); 154 } 155 156 #[test] delimited_new_visitor()157 fn delimited_new_visitor() { 158 let make = Delimited::new("; ", MakeDebug); 159 160 TestAttrs1::with(|attrs| { 161 let mut s = String::new(); 162 { 163 let mut v = make.make_visitor(&mut s); 164 attrs.record(&mut v); 165 } 166 assert_eq!( 167 s.as_str(), 168 "question=\"life, the universe, and everything\"; tricky=true; can_you_do_it=true" 169 ); 170 }); 171 172 TestAttrs2::with(|attrs| { 173 let mut s = String::new(); 174 { 175 let mut v = make.make_visitor(&mut s); 176 attrs.record(&mut v); 177 } 178 assert_eq!( 179 s.as_str(), 180 "question=None; question.answer=42; tricky=true; can_you_do_it=false" 181 ); 182 }); 183 } 184 } 185