Coverage Report

Created: 2025-11-11 06:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/tracing-subscriber-0.3.20/src/field/delimited.rs
Line
Count
Source
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>;
34
0
    fn make_visitor(&self, target: T) -> Self::Visitor {
35
0
        let inner = self.inner.make_visitor(target);
36
0
        VisitDelimited::new(self.delimiter.clone(), inner)
37
0
    }
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
45
0
    pub fn new(delimiter: D, inner: V) -> Self {
46
0
        Self { delimiter, inner }
47
0
    }
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
57
0
    pub fn new(delimiter: D, inner: V) -> Self {
58
0
        Self {
59
0
            delimiter,
60
0
            inner,
61
0
            seen: false,
62
0
            err: Ok(()),
63
0
        }
64
0
    }
65
66
0
    fn delimit(&mut self)
67
0
    where
68
0
        V: VisitFmt,
69
0
        D: AsRef<str>,
70
    {
71
0
        if self.err.is_err() {
72
0
            return;
73
0
        }
74
75
0
        if self.seen {
76
0
            self.err = self.inner.writer().write_str(self.delimiter.as_ref());
77
0
        }
78
79
0
        self.seen = true;
80
0
    }
81
}
82
83
impl<D, V> Visit for VisitDelimited<D, V>
84
where
85
    V: VisitFmt,
86
    D: AsRef<str>,
87
{
88
0
    fn record_i64(&mut self, field: &Field, value: i64) {
89
0
        self.delimit();
90
0
        self.inner.record_i64(field, value);
91
0
    }
92
93
0
    fn record_u64(&mut self, field: &Field, value: u64) {
94
0
        self.delimit();
95
0
        self.inner.record_u64(field, value);
96
0
    }
97
98
0
    fn record_bool(&mut self, field: &Field, value: bool) {
99
0
        self.delimit();
100
0
        self.inner.record_bool(field, value);
101
0
    }
102
103
0
    fn record_str(&mut self, field: &Field, value: &str) {
104
0
        self.delimit();
105
0
        self.inner.record_str(field, value);
106
0
    }
107
108
0
    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
109
0
        self.delimit();
110
0
        self.inner.record_debug(field, value);
111
0
    }
112
}
113
114
impl<D, V> VisitOutput<fmt::Result> for VisitDelimited<D, V>
115
where
116
    V: VisitFmt,
117
    D: AsRef<str>,
118
{
119
0
    fn finish(self) -> fmt::Result {
120
0
        self.err?;
121
0
        self.inner.finish()
122
0
    }
123
}
124
125
impl<D, V> VisitFmt for VisitDelimited<D, V>
126
where
127
    V: VisitFmt,
128
    D: AsRef<str>,
129
{
130
0
    fn writer(&mut self) -> &mut dyn fmt::Write {
131
0
        self.inner.writer()
132
0
    }
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]
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]
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
}