184 lines
4.5 KiB
Rust
184 lines
4.5 KiB
Rust
//! A `MakeVisitor` wrapper that separates formatted fields with a delimiter.
|
|
use super::{MakeVisitor, VisitFmt, VisitOutput};
|
|
|
|
use core::fmt;
|
|
use tracing_core::field::{Field, Visit};
|
|
|
|
/// A `MakeVisitor` wrapper that wraps a visitor that writes formatted output so
|
|
/// that a delimiter is inserted between writing formatted field values.
|
|
#[derive(Debug, Clone)]
|
|
pub struct Delimited<D, V> {
|
|
delimiter: D,
|
|
inner: V,
|
|
}
|
|
|
|
/// A visitor wrapper that inserts a delimiter after the wrapped visitor formats
|
|
/// a field value.
|
|
#[derive(Debug)]
|
|
pub struct VisitDelimited<D, V> {
|
|
delimiter: D,
|
|
seen: bool,
|
|
inner: V,
|
|
err: fmt::Result,
|
|
}
|
|
|
|
// === impl Delimited ===
|
|
|
|
impl<D, V, T> MakeVisitor<T> for Delimited<D, V>
|
|
where
|
|
D: AsRef<str> + Clone,
|
|
V: MakeVisitor<T>,
|
|
V::Visitor: VisitFmt,
|
|
{
|
|
type Visitor = VisitDelimited<D, V::Visitor>;
|
|
fn make_visitor(&self, target: T) -> Self::Visitor {
|
|
let inner = self.inner.make_visitor(target);
|
|
VisitDelimited::new(self.delimiter.clone(), inner)
|
|
}
|
|
}
|
|
|
|
impl<D, V> Delimited<D, V> {
|
|
/// Returns a new [`MakeVisitor`] implementation that wraps `inner` so that
|
|
/// it will format each visited field separated by the provided `delimiter`.
|
|
///
|
|
/// [`MakeVisitor`]: super::MakeVisitor
|
|
pub fn new(delimiter: D, inner: V) -> Self {
|
|
Self { delimiter, inner }
|
|
}
|
|
}
|
|
|
|
// === impl VisitDelimited ===
|
|
|
|
impl<D, V> VisitDelimited<D, V> {
|
|
/// Returns a new [`Visit`] implementation that wraps `inner` so that
|
|
/// each formatted field is separated by the provided `delimiter`.
|
|
///
|
|
/// [`Visit`]: tracing_core::field::Visit
|
|
pub fn new(delimiter: D, inner: V) -> Self {
|
|
Self {
|
|
delimiter,
|
|
inner,
|
|
seen: false,
|
|
err: Ok(()),
|
|
}
|
|
}
|
|
|
|
fn delimit(&mut self)
|
|
where
|
|
V: VisitFmt,
|
|
D: AsRef<str>,
|
|
{
|
|
if self.err.is_err() {
|
|
return;
|
|
}
|
|
|
|
if self.seen {
|
|
self.err = self.inner.writer().write_str(self.delimiter.as_ref());
|
|
}
|
|
|
|
self.seen = true;
|
|
}
|
|
}
|
|
|
|
impl<D, V> Visit for VisitDelimited<D, V>
|
|
where
|
|
V: VisitFmt,
|
|
D: AsRef<str>,
|
|
{
|
|
fn record_i64(&mut self, field: &Field, value: i64) {
|
|
self.delimit();
|
|
self.inner.record_i64(field, value);
|
|
}
|
|
|
|
fn record_u64(&mut self, field: &Field, value: u64) {
|
|
self.delimit();
|
|
self.inner.record_u64(field, value);
|
|
}
|
|
|
|
fn record_bool(&mut self, field: &Field, value: bool) {
|
|
self.delimit();
|
|
self.inner.record_bool(field, value);
|
|
}
|
|
|
|
fn record_str(&mut self, field: &Field, value: &str) {
|
|
self.delimit();
|
|
self.inner.record_str(field, value);
|
|
}
|
|
|
|
fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
|
|
self.delimit();
|
|
self.inner.record_debug(field, value);
|
|
}
|
|
}
|
|
|
|
impl<D, V> VisitOutput<fmt::Result> for VisitDelimited<D, V>
|
|
where
|
|
V: VisitFmt,
|
|
D: AsRef<str>,
|
|
{
|
|
fn finish(self) -> fmt::Result {
|
|
self.err?;
|
|
self.inner.finish()
|
|
}
|
|
}
|
|
|
|
impl<D, V> VisitFmt for VisitDelimited<D, V>
|
|
where
|
|
V: VisitFmt,
|
|
D: AsRef<str>,
|
|
{
|
|
fn writer(&mut self) -> &mut dyn fmt::Write {
|
|
self.inner.writer()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[cfg(all(test, feature = "alloc"))]
|
|
mod test {
|
|
use super::*;
|
|
use crate::field::test_util::*;
|
|
|
|
#[test]
|
|
fn delimited_visitor() {
|
|
let mut s = String::new();
|
|
let visitor = DebugVisitor::new(&mut s);
|
|
let mut visitor = VisitDelimited::new(", ", visitor);
|
|
|
|
TestAttrs1::with(|attrs| attrs.record(&mut visitor));
|
|
visitor.finish().unwrap();
|
|
|
|
assert_eq!(
|
|
s.as_str(),
|
|
"question=\"life, the universe, and everything\", tricky=true, can_you_do_it=true"
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn delimited_new_visitor() {
|
|
let make = Delimited::new("; ", MakeDebug);
|
|
|
|
TestAttrs1::with(|attrs| {
|
|
let mut s = String::new();
|
|
{
|
|
let mut v = make.make_visitor(&mut s);
|
|
attrs.record(&mut v);
|
|
}
|
|
assert_eq!(
|
|
s.as_str(),
|
|
"question=\"life, the universe, and everything\"; tricky=true; can_you_do_it=true"
|
|
);
|
|
});
|
|
|
|
TestAttrs2::with(|attrs| {
|
|
let mut s = String::new();
|
|
{
|
|
let mut v = make.make_visitor(&mut s);
|
|
attrs.record(&mut v);
|
|
}
|
|
assert_eq!(
|
|
s.as_str(),
|
|
"question=None; question.answer=42; tricky=true; can_you_do_it=false"
|
|
);
|
|
});
|
|
}
|
|
}
|