summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-subscriber/src/field
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/tracing-subscriber/src/field')
-rw-r--r--vendor/tracing-subscriber/src/field/debug.rs111
-rw-r--r--vendor/tracing-subscriber/src/field/delimited.rs184
-rw-r--r--vendor/tracing-subscriber/src/field/display.rs117
-rw-r--r--vendor/tracing-subscriber/src/field/mod.rs366
4 files changed, 778 insertions, 0 deletions
diff --git a/vendor/tracing-subscriber/src/field/debug.rs b/vendor/tracing-subscriber/src/field/debug.rs
new file mode 100644
index 000000000..cc67d29fe
--- /dev/null
+++ b/vendor/tracing-subscriber/src/field/debug.rs
@@ -0,0 +1,111 @@
+//! `MakeVisitor` wrappers for working with `fmt::Debug` fields.
+use super::{MakeVisitor, VisitFmt, VisitOutput};
+use tracing_core::field::{Field, Visit};
+
+use core::fmt;
+
+/// A visitor wrapper that ensures any `fmt::Debug` fields are formatted using
+/// the alternate (`:#`) formatter.
+#[derive(Debug, Clone)]
+pub struct Alt<V>(V);
+
+// TODO(eliza): When `error` as a primitive type is stable, add a
+// `DisplayErrors` wrapper...
+
+// === impl Alt ===
+//
+impl<V> Alt<V> {
+ /// Wraps the provided visitor so that any `fmt::Debug` fields are formatted
+ /// using the alternative (`:#`) formatter.
+ pub fn new(inner: V) -> Self {
+ Alt(inner)
+ }
+}
+
+impl<T, V> MakeVisitor<T> for Alt<V>
+where
+ V: MakeVisitor<T>,
+{
+ type Visitor = Alt<V::Visitor>;
+
+ #[inline]
+ fn make_visitor(&self, target: T) -> Self::Visitor {
+ Alt(self.0.make_visitor(target))
+ }
+}
+
+impl<V> Visit for Alt<V>
+where
+ V: Visit,
+{
+ #[inline]
+ fn record_f64(&mut self, field: &Field, value: f64) {
+ self.0.record_f64(field, value)
+ }
+
+ #[inline]
+ fn record_i64(&mut self, field: &Field, value: i64) {
+ self.0.record_i64(field, value)
+ }
+
+ #[inline]
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ self.0.record_u64(field, value)
+ }
+
+ #[inline]
+ fn record_bool(&mut self, field: &Field, value: bool) {
+ self.0.record_bool(field, value)
+ }
+
+ /// Visit a string value.
+ fn record_str(&mut self, field: &Field, value: &str) {
+ self.0.record_str(field, value)
+ }
+
+ // TODO(eliza): add RecordError when stable
+ // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
+ // self.record_debug(field, &format_args!("{}", value))
+ // }
+
+ #[inline]
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.0.record_debug(field, &format_args!("{:#?}", value))
+ }
+}
+
+impl<V, O> VisitOutput<O> for Alt<V>
+where
+ V: VisitOutput<O>,
+{
+ #[inline]
+ fn finish(self) -> O {
+ self.0.finish()
+ }
+}
+
+feature! {
+ #![feature = "std"]
+ use super::VisitWrite;
+ use std::io;
+
+ impl<V> VisitWrite for Alt<V>
+ where
+ V: VisitWrite,
+ {
+ #[inline]
+ fn writer(&mut self) -> &mut dyn io::Write {
+ self.0.writer()
+ }
+ }
+}
+
+impl<V> VisitFmt for Alt<V>
+where
+ V: VisitFmt,
+{
+ #[inline]
+ fn writer(&mut self) -> &mut dyn fmt::Write {
+ self.0.writer()
+ }
+}
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"
+ );
+ });
+ }
+}
diff --git a/vendor/tracing-subscriber/src/field/display.rs b/vendor/tracing-subscriber/src/field/display.rs
new file mode 100644
index 000000000..78a039ce1
--- /dev/null
+++ b/vendor/tracing-subscriber/src/field/display.rs
@@ -0,0 +1,117 @@
+//! `MakeVisitor` wrappers for working with `fmt::Display` fields.
+use super::{MakeVisitor, VisitFmt, VisitOutput};
+use tracing_core::field::{Field, Visit};
+
+use core::fmt;
+
+/// A visitor wrapper that ensures any strings named "message" are formatted
+/// using `fmt::Display`
+#[derive(Debug, Clone)]
+pub struct Messages<V>(V);
+
+// TODO(eliza): When `error` as a primitive type is stable, add a
+// `DisplayErrors` wrapper...
+
+// === impl Messages ===
+//
+impl<V> Messages<V> {
+ /// Returns a new [`MakeVisitor`] implementation that will wrap `inner` so
+ /// that any strings named `message` are formatted using `fmt::Display`.
+ ///
+ /// [`MakeVisitor`]: super::MakeVisitor
+ pub fn new(inner: V) -> Self {
+ Messages(inner)
+ }
+}
+
+impl<T, V> MakeVisitor<T> for Messages<V>
+where
+ V: MakeVisitor<T>,
+{
+ type Visitor = Messages<V::Visitor>;
+
+ #[inline]
+ fn make_visitor(&self, target: T) -> Self::Visitor {
+ Messages(self.0.make_visitor(target))
+ }
+}
+
+impl<V> Visit for Messages<V>
+where
+ V: Visit,
+{
+ #[inline]
+ fn record_f64(&mut self, field: &Field, value: f64) {
+ self.0.record_f64(field, value)
+ }
+
+ #[inline]
+ fn record_i64(&mut self, field: &Field, value: i64) {
+ self.0.record_i64(field, value)
+ }
+
+ #[inline]
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ self.0.record_u64(field, value)
+ }
+
+ #[inline]
+ fn record_bool(&mut self, field: &Field, value: bool) {
+ self.0.record_bool(field, value)
+ }
+
+ /// Visit a string value.
+ fn record_str(&mut self, field: &Field, value: &str) {
+ if field.name() == "message" {
+ self.0.record_debug(field, &format_args!("{}", value))
+ } else {
+ self.0.record_str(field, value)
+ }
+ }
+
+ // TODO(eliza): add RecordError when stable
+ // fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
+ // self.record_debug(field, &format_args!("{}", value))
+ // }
+
+ #[inline]
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.0.record_debug(field, value)
+ }
+}
+
+impl<V, O> VisitOutput<O> for Messages<V>
+where
+ V: VisitOutput<O>,
+{
+ #[inline]
+ fn finish(self) -> O {
+ self.0.finish()
+ }
+}
+
+feature! {
+ #![feature = "std"]
+ use super::VisitWrite;
+ use std::io;
+
+ impl<V> VisitWrite for Messages<V>
+ where
+ V: VisitWrite,
+ {
+ #[inline]
+ fn writer(&mut self) -> &mut dyn io::Write {
+ self.0.writer()
+ }
+ }
+}
+
+impl<V> VisitFmt for Messages<V>
+where
+ V: VisitFmt,
+{
+ #[inline]
+ fn writer(&mut self) -> &mut dyn fmt::Write {
+ self.0.writer()
+ }
+}
diff --git a/vendor/tracing-subscriber/src/field/mod.rs b/vendor/tracing-subscriber/src/field/mod.rs
new file mode 100644
index 000000000..5dfddb362
--- /dev/null
+++ b/vendor/tracing-subscriber/src/field/mod.rs
@@ -0,0 +1,366 @@
+//! Utilities for working with [fields] and [field visitors].
+//!
+//! [fields]: tracing_core::field
+//! [field visitors]: tracing_core::field::Visit
+use core::{fmt, marker::PhantomData};
+pub use tracing_core::field::Visit;
+use tracing_core::{
+ span::{Attributes, Record},
+ Event,
+};
+pub mod debug;
+pub mod delimited;
+pub mod display;
+
+/// Creates new [visitors].
+///
+/// A type implementing `MakeVisitor` represents a composable factory for types
+/// implementing the [`Visit` trait][visitors]. The `MakeVisitor` trait defines
+/// a single function, `make_visitor`, which takes in a `T`-typed `target` and
+/// returns a type implementing `Visit` configured for that target. A target may
+/// be a string, output stream, or data structure that the visitor will record
+/// data to, configuration variables that determine the visitor's behavior, or
+/// `()` when no input is required to produce a visitor.
+///
+/// [visitors]: tracing_core::field::Visit
+pub trait MakeVisitor<T> {
+ /// The visitor type produced by this `MakeVisitor`.
+ type Visitor: Visit;
+
+ /// Make a new visitor for the provided `target`.
+ fn make_visitor(&self, target: T) -> Self::Visitor;
+}
+
+/// A [visitor] that produces output once it has visited a set of fields.
+///
+/// [visitor]: tracing_core::field::Visit
+pub trait VisitOutput<Out>: Visit {
+ /// Completes the visitor, returning any output.
+ ///
+ /// This is called once a full set of fields has been visited.
+ fn finish(self) -> Out;
+
+ /// Visit a set of fields, and return the output of finishing the visitor
+ /// once the fields have been visited.
+ fn visit<R>(mut self, fields: &R) -> Out
+ where
+ R: RecordFields,
+ Self: Sized,
+ {
+ fields.record(&mut self);
+ self.finish()
+ }
+}
+
+/// Extension trait implemented by types which can be recorded by a [visitor].
+///
+/// This allows writing code that is generic over `tracing_core`'s
+/// [`span::Attributes`][attr], [`span::Record`][rec], and [`Event`][event]
+/// types. These types all provide inherent `record` methods that allow a
+/// visitor to record their fields, but there is no common trait representing this.
+///
+/// With `RecordFields`, we can write code like this:
+/// ```
+/// use tracing_core::field::Visit;
+/// # use tracing_core::field::Field;
+/// use tracing_subscriber::field::RecordFields;
+///
+/// struct MyVisitor {
+/// // ...
+/// }
+/// # impl MyVisitor { fn new() -> Self { Self{} } }
+/// impl Visit for MyVisitor {
+/// // ...
+/// # fn record_debug(&mut self, _: &Field, _: &dyn std::fmt::Debug) {}
+/// }
+///
+/// fn record_with_my_visitor<R>(r: R)
+/// where
+/// R: RecordFields,
+/// {
+/// let mut visitor = MyVisitor::new();
+/// r.record(&mut visitor);
+/// }
+/// ```
+/// [visitor]: tracing_core::field::Visit
+/// [attr]: tracing_core::span::Attributes
+/// [rec]: tracing_core::span::Record
+/// [event]: tracing_core::event::Event
+pub trait RecordFields: crate::sealed::Sealed<RecordFieldsMarker> {
+ /// Record all the fields in `self` with the provided `visitor`.
+ fn record(&self, visitor: &mut dyn Visit);
+}
+
+/// Extension trait implemented for all `MakeVisitor` implementations that
+/// produce a visitor implementing `VisitOutput`.
+pub trait MakeOutput<T, Out>
+where
+ Self: MakeVisitor<T> + crate::sealed::Sealed<(T, Out)>,
+ Self::Visitor: VisitOutput<Out>,
+{
+ /// Visits all fields in `fields` with a new visitor constructed from
+ /// `target`.
+ fn visit_with<F>(&self, target: T, fields: &F) -> Out
+ where
+ F: RecordFields,
+ {
+ self.make_visitor(target).visit(fields)
+ }
+}
+
+feature! {
+ #![feature = "std"]
+ use std::io;
+
+ /// Extension trait implemented by visitors to indicate that they write to an
+ /// `io::Write` instance, and allow access to that writer.
+ pub trait VisitWrite: VisitOutput<Result<(), io::Error>> {
+ /// Returns the writer that this visitor writes to.
+ fn writer(&mut self) -> &mut dyn io::Write;
+ }
+}
+
+/// Extension trait implemented by visitors to indicate that they write to a
+/// `fmt::Write` instance, and allow access to that writer.
+pub trait VisitFmt: VisitOutput<fmt::Result> {
+ /// Returns the formatter that this visitor writes to.
+ fn writer(&mut self) -> &mut dyn fmt::Write;
+}
+
+/// Extension trait providing `MakeVisitor` combinators.
+pub trait MakeExt<T>
+where
+ Self: MakeVisitor<T> + Sized,
+ Self: crate::sealed::Sealed<MakeExtMarker<T>>,
+{
+ /// Wraps `self` so that any `fmt::Debug` fields are recorded using the
+ /// alternate formatter (`{:#?}`).
+ fn debug_alt(self) -> debug::Alt<Self> {
+ debug::Alt::new(self)
+ }
+
+ /// Wraps `self` so that any string fields named "message" are recorded
+ /// using `fmt::Display`.
+ fn display_messages(self) -> display::Messages<Self> {
+ display::Messages::new(self)
+ }
+
+ /// Wraps `self` so that when fields are formatted to a writer, they are
+ /// separated by the provided `delimiter`.
+ fn delimited<D>(self, delimiter: D) -> delimited::Delimited<D, Self>
+ where
+ D: AsRef<str> + Clone,
+ Self::Visitor: VisitFmt,
+ {
+ delimited::Delimited::new(delimiter, self)
+ }
+}
+
+// === impl RecordFields ===
+
+impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Event<'a> {}
+impl<'a> RecordFields for Event<'a> {
+ fn record(&self, visitor: &mut dyn Visit) {
+ Event::record(self, visitor)
+ }
+}
+
+impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Attributes<'a> {}
+impl<'a> RecordFields for Attributes<'a> {
+ fn record(&self, visitor: &mut dyn Visit) {
+ Attributes::record(self, visitor)
+ }
+}
+
+impl<'a> crate::sealed::Sealed<RecordFieldsMarker> for Record<'a> {}
+impl<'a> RecordFields for Record<'a> {
+ fn record(&self, visitor: &mut dyn Visit) {
+ Record::record(self, visitor)
+ }
+}
+
+impl<'a, F> crate::sealed::Sealed<RecordFieldsMarker> for &'a F where F: RecordFields {}
+impl<'a, F> RecordFields for &'a F
+where
+ F: RecordFields,
+{
+ fn record(&self, visitor: &mut dyn Visit) {
+ F::record(*self, visitor)
+ }
+}
+
+// === blanket impls ===
+
+impl<T, V, F> MakeVisitor<T> for F
+where
+ F: Fn(T) -> V,
+ V: Visit,
+{
+ type Visitor = V;
+ fn make_visitor(&self, target: T) -> Self::Visitor {
+ (self)(target)
+ }
+}
+
+impl<T, Out, M> crate::sealed::Sealed<(T, Out)> for M
+where
+ M: MakeVisitor<T>,
+ M::Visitor: VisitOutput<Out>,
+{
+}
+
+impl<T, Out, M> MakeOutput<T, Out> for M
+where
+ M: MakeVisitor<T>,
+ M::Visitor: VisitOutput<Out>,
+{
+}
+
+impl<T, M> crate::sealed::Sealed<MakeExtMarker<T>> for M where M: MakeVisitor<T> + Sized {}
+
+impl<T, M> MakeExt<T> for M
+where
+ M: MakeVisitor<T> + Sized,
+ M: crate::sealed::Sealed<MakeExtMarker<T>>,
+{
+}
+
+#[derive(Debug)]
+#[doc(hidden)]
+pub struct MakeExtMarker<T> {
+ _p: PhantomData<T>,
+}
+
+#[derive(Debug)]
+#[doc(hidden)]
+pub struct RecordFieldsMarker {
+ _p: (),
+}
+
+#[cfg(all(test, feature = "alloc"))]
+#[macro_use]
+pub(in crate::field) mod test_util {
+ use super::*;
+ pub(in crate::field) use alloc::string::String;
+ use tracing_core::{
+ callsite::Callsite,
+ field::{Field, Value},
+ metadata::{Kind, Level, Metadata},
+ };
+
+ pub(crate) struct TestAttrs1;
+ pub(crate) struct TestAttrs2;
+
+ impl TestAttrs1 {
+ pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
+ let fieldset = TEST_META_1.fields();
+ let values = &[
+ (
+ &fieldset.field("question").unwrap(),
+ Some(&"life, the universe, and everything" as &dyn Value),
+ ),
+ (&fieldset.field("question.answer").unwrap(), None),
+ (
+ &fieldset.field("tricky").unwrap(),
+ Some(&true as &dyn Value),
+ ),
+ (
+ &fieldset.field("can_you_do_it").unwrap(),
+ Some(&true as &dyn Value),
+ ),
+ ];
+ let valueset = fieldset.value_set(values);
+ let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
+ f(attrs)
+ }
+ }
+
+ impl TestAttrs2 {
+ pub(crate) fn with<T>(f: impl FnOnce(Attributes<'_>) -> T) -> T {
+ let fieldset = TEST_META_1.fields();
+ let none = tracing_core::field::debug(&Option::<&str>::None);
+ let values = &[
+ (
+ &fieldset.field("question").unwrap(),
+ Some(&none as &dyn Value),
+ ),
+ (
+ &fieldset.field("question.answer").unwrap(),
+ Some(&42 as &dyn Value),
+ ),
+ (
+ &fieldset.field("tricky").unwrap(),
+ Some(&true as &dyn Value),
+ ),
+ (
+ &fieldset.field("can_you_do_it").unwrap(),
+ Some(&false as &dyn Value),
+ ),
+ ];
+ let valueset = fieldset.value_set(values);
+ let attrs = tracing_core::span::Attributes::new(&TEST_META_1, &valueset);
+ f(attrs)
+ }
+ }
+
+ struct TestCallsite1;
+ static TEST_CALLSITE_1: &'static dyn Callsite = &TestCallsite1;
+ static TEST_META_1: Metadata<'static> = tracing_core::metadata! {
+ name: "field_test1",
+ target: module_path!(),
+ level: Level::INFO,
+ fields: &["question", "question.answer", "tricky", "can_you_do_it"],
+ callsite: TEST_CALLSITE_1,
+ kind: Kind::SPAN,
+ };
+
+ impl Callsite for TestCallsite1 {
+ fn set_interest(&self, _: tracing_core::subscriber::Interest) {
+ unimplemented!()
+ }
+
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META_1
+ }
+ }
+
+ pub(crate) struct MakeDebug;
+ pub(crate) struct DebugVisitor<'a> {
+ writer: &'a mut dyn fmt::Write,
+ err: fmt::Result,
+ }
+
+ impl<'a> DebugVisitor<'a> {
+ pub(crate) fn new(writer: &'a mut dyn fmt::Write) -> Self {
+ Self {
+ writer,
+ err: Ok(()),
+ }
+ }
+ }
+
+ impl<'a> Visit for DebugVisitor<'a> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ write!(self.writer, "{}={:?}", field, value).unwrap();
+ }
+ }
+
+ impl<'a> VisitOutput<fmt::Result> for DebugVisitor<'a> {
+ fn finish(self) -> fmt::Result {
+ self.err
+ }
+ }
+
+ impl<'a> VisitFmt for DebugVisitor<'a> {
+ fn writer(&mut self) -> &mut dyn fmt::Write {
+ self.writer
+ }
+ }
+
+ impl<'a> MakeVisitor<&'a mut dyn fmt::Write> for MakeDebug {
+ type Visitor = DebugVisitor<'a>;
+ fn make_visitor(&self, w: &'a mut dyn fmt::Write) -> DebugVisitor<'a> {
+ DebugVisitor::new(w)
+ }
+ }
+}