summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/field/delimited.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-subscriber/src/field/delimited.rs')
-rw-r--r--vendor/tracing-subscriber/src/field/delimited.rs184
1 files changed, 184 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/src/field/delimited.rs b/vendor/tracing-subscriber/src/field/delimited.rs
new file mode 100644
index 000000000..98634cea9
--- /dev/null
+++ b/vendor/tracing-subscriber/src/field/delimited.rs
@@ -0,0 +1,184 @@
+//! 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"
+ );
+ });
+ }
+}