• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //! `Span` and `Event` key-value data.
2 //!
3 //! Spans and events may be annotated with key-value data, known as _fields_.
4 //! These fields consist of a mapping from a key (corresponding to a `&str` but
5 //! represented internally as an array index) to a [`Value`].
6 //!
7 //! # `Value`s and `Subscriber`s
8 //!
9 //! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s.
10 //! The set of field keys on a given span or event is defined on its [`Metadata`].
11 //! When a span is created, it provides [`Attributes`] to the `Subscriber`'s
12 //! [`new_span`] method, containing any fields whose values were provided when
13 //! the span was created; and may call the `Subscriber`'s [`record`] method
14 //! with additional [`Record`]s if values are added for more of its fields.
15 //! Similarly, the [`Event`] type passed to the subscriber's [`event`] method
16 //! will contain any fields attached to each event.
17 //!
18 //! `tracing` represents values as either one of a set of Rust primitives
19 //! (`i64`, `u64`, `f64`, `i128`, `u128`, `bool`, and `&str`) or using a
20 //! `fmt::Display` or `fmt::Debug` implementation. `Subscriber`s are provided
21 //! these primitive value types as `dyn Value` trait objects.
22 //!
23 //! These trait objects can be formatted using `fmt::Debug`, but may also be
24 //! recorded as typed data by calling the [`Value::record`] method on these
25 //! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
26 //! represents the behavior used to record values of various types. For example,
27 //! an implementation of `Visit` might record integers by incrementing counters
28 //! for their field names rather than printing them.
29 //!
30 //!
31 //! # Using `valuable`
32 //!
33 //! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
34 //! number of Rust primitives as typed values, and only permits recording
35 //! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
36 //! implementations. However, there are some cases where it may be useful to record
37 //! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
38 //! user-defined `struct` and `enum` types without having to format them as
39 //! unstructured text.
40 //!
41 //! To address `Value`'s limitations, `tracing` offers experimental support for
42 //! the [`valuable`] crate, which provides object-safe inspection of structured
43 //! values. User-defined types can implement the [`valuable::Valuable`] trait,
44 //! and be recorded as a `tracing` field by calling their [`as_value`] method.
45 //! If the [`Subscriber`] also supports the `valuable` crate, it can
46 //! then visit those types fields as structured values using `valuable`.
47 //!
48 //! <pre class="ignore" style="white-space:normal;font:inherit;">
49 //!     <strong>Note</strong>: <code>valuable</code> support is an
50 //!     <a href = "../index.html#unstable-features">unstable feature</a>. See
51 //!     the documentation on unstable features for details on how to enable it.
52 //! </pre>
53 //!
54 //! For example:
55 //! ```ignore
56 //! // Derive `Valuable` for our types:
57 //! use valuable::Valuable;
58 //!
59 //! #[derive(Clone, Debug, Valuable)]
60 //! struct User {
61 //!     name: String,
62 //!     age: u32,
63 //!     address: Address,
64 //! }
65 //!
66 //! #[derive(Clone, Debug, Valuable)]
67 //! struct Address {
68 //!     country: String,
69 //!     city: String,
70 //!     street: String,
71 //! }
72 //!
73 //! let user = User {
74 //!     name: "Arwen Undomiel".to_string(),
75 //!     age: 3000,
76 //!     address: Address {
77 //!         country: "Middle Earth".to_string(),
78 //!         city: "Rivendell".to_string(),
79 //!         street: "leafy lane".to_string(),
80 //!     },
81 //! };
82 //!
83 //! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
84 //! // to traverse its fields as a nested, typed structure:
85 //! tracing::info!(current_user = user.as_value());
86 //! ```
87 //!
88 //! Alternatively, the [`valuable()`] function may be used to convert a type
89 //! implementing [`Valuable`] into a `tracing` field value.
90 //!
91 //! When the `valuable` feature is enabled, the [`Visit`] trait will include an
92 //! optional [`record_value`] method. `Visit` implementations that wish to
93 //! record `valuable` values can implement this method with custom behavior.
94 //! If a visitor does not implement `record_value`, the [`valuable::Value`] will
95 //! be forwarded to the visitor's [`record_debug`] method.
96 //!
97 //! [`valuable`]: https://crates.io/crates/valuable
98 //! [`as_value`]: valuable::Valuable::as_value
99 //! [`Subscriber`]: crate::Subscriber
100 //! [`record_value`]: Visit::record_value
101 //! [`record_debug`]: Visit::record_debug
102 //!
103 //! [span]: super::span
104 //! [`Event`]: super::event::Event
105 //! [`Metadata`]: super::metadata::Metadata
106 //! [`Attributes`]:  super::span::Attributes
107 //! [`Record`]: super::span::Record
108 //! [`new_span`]: super::subscriber::Subscriber::new_span
109 //! [`record`]: super::subscriber::Subscriber::record
110 //! [`event`]:  super::subscriber::Subscriber::event
111 //! [`Value::record`]: Value::record
112 use crate::callsite;
113 use crate::stdlib::{
114     borrow::Borrow,
115     fmt,
116     hash::{Hash, Hasher},
117     num,
118     ops::Range,
119     string::String,
120 };
121 
122 use self::private::ValidLen;
123 
124 /// An opaque key allowing _O_(1) access to a field in a `Span`'s key-value
125 /// data.
126 ///
127 /// As keys are defined by the _metadata_ of a span, rather than by an
128 /// individual instance of a span, a key may be used to access the same field
129 /// across all instances of a given span with the same metadata. Thus, when a
130 /// subscriber observes a new span, it need only access a field by name _once_,
131 /// and use the key for that name for all other accesses.
132 #[derive(Debug)]
133 pub struct Field {
134     i: usize,
135     fields: FieldSet,
136 }
137 
138 /// An empty field.
139 ///
140 /// This can be used to indicate that the value of a field is not currently
141 /// present but will be recorded later.
142 ///
143 /// When a field's value is `Empty`. it will not be recorded.
144 #[derive(Debug, Eq, PartialEq)]
145 pub struct Empty;
146 
147 /// Describes the fields present on a span.
148 ///
149 /// ## Equality
150 ///
151 /// In well-behaved applications, two `FieldSet`s [initialized] with equal
152 /// [callsite identifiers] will have identical fields. Consequently, in release
153 /// builds, [`FieldSet::eq`] *only* checks that its arguments have equal
154 /// callsites. However, the equality of field names is checked in debug builds.
155 ///
156 /// [initialized]: Self::new
157 /// [callsite identifiers]: callsite::Identifier
158 pub struct FieldSet {
159     /// The names of each field on the described span.
160     names: &'static [&'static str],
161     /// The callsite where the described span originates.
162     callsite: callsite::Identifier,
163 }
164 
165 /// A set of fields and values for a span.
166 pub struct ValueSet<'a> {
167     values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)],
168     fields: &'a FieldSet,
169 }
170 
171 /// An iterator over a set of fields.
172 #[derive(Debug)]
173 pub struct Iter {
174     idxs: Range<usize>,
175     fields: FieldSet,
176 }
177 
178 /// Visits typed values.
179 ///
180 /// An instance of `Visit` ("a visitor") represents the logic necessary to
181 /// record field values of various types. When an implementor of [`Value`] is
182 /// [recorded], it calls the appropriate method on the provided visitor to
183 /// indicate the type that value should be recorded as.
184 ///
185 /// When a [`Subscriber`] implementation [records an `Event`] or a
186 /// [set of `Value`s added to a `Span`], it can pass an `&mut Visit` to the
187 /// `record` method on the provided [`ValueSet`] or [`Event`]. This visitor
188 /// will then be used to record all the field-value pairs present on that
189 /// `Event` or `ValueSet`.
190 ///
191 /// # Examples
192 ///
193 /// A simple visitor that writes to a string might be implemented like so:
194 /// ```
195 /// # extern crate tracing_core as tracing;
196 /// use std::fmt::{self, Write};
197 /// use tracing::field::{Value, Visit, Field};
198 /// pub struct StringVisitor<'a> {
199 ///     string: &'a mut String,
200 /// }
201 ///
202 /// impl<'a> Visit for StringVisitor<'a> {
203 ///     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
204 ///         write!(self.string, "{} = {:?}; ", field.name(), value).unwrap();
205 ///     }
206 /// }
207 /// ```
208 /// This visitor will format each recorded value using `fmt::Debug`, and
209 /// append the field name and formatted value to the provided string,
210 /// regardless of the type of the recorded value. When all the values have
211 /// been recorded, the `StringVisitor` may be dropped, allowing the string
212 /// to be printed or stored in some other data structure.
213 ///
214 /// The `Visit` trait provides default implementations for `record_i64`,
215 /// `record_u64`, `record_bool`, `record_str`, and `record_error`, which simply
216 /// forward the recorded value to `record_debug`. Thus, `record_debug` is the
217 /// only method which a `Visit` implementation *must* implement. However,
218 /// visitors may override the default implementations of these functions in
219 /// order to implement type-specific behavior.
220 ///
221 /// Additionally, when a visitor receives a value of a type it does not care
222 /// about, it is free to ignore those values completely. For example, a
223 /// visitor which only records numeric data might look like this:
224 ///
225 /// ```
226 /// # extern crate tracing_core as tracing;
227 /// # use std::fmt::{self, Write};
228 /// # use tracing::field::{Value, Visit, Field};
229 /// pub struct SumVisitor {
230 ///     sum: i64,
231 /// }
232 ///
233 /// impl Visit for SumVisitor {
234 ///     fn record_i64(&mut self, _field: &Field, value: i64) {
235 ///        self.sum += value;
236 ///     }
237 ///
238 ///     fn record_u64(&mut self, _field: &Field, value: u64) {
239 ///         self.sum += value as i64;
240 ///     }
241 ///
242 ///     fn record_debug(&mut self, _field: &Field, _value: &fmt::Debug) {
243 ///         // Do nothing
244 ///     }
245 /// }
246 /// ```
247 ///
248 /// This visitor (which is probably not particularly useful) keeps a running
249 /// sum of all the numeric values it records, and ignores all other values. A
250 /// more practical example of recording typed values is presented in
251 /// `examples/counters.rs`, which demonstrates a very simple metrics system
252 /// implemented using `tracing`.
253 ///
254 /// <div class="example-wrap" style="display:inline-block">
255 /// <pre class="ignore" style="white-space:normal;font:inherit;">
256 /// <strong>Note</strong>: The <code>record_error</code> trait method is only
257 /// available when the Rust standard library is present, as it requires the
258 /// <code>std::error::Error</code> trait.
259 /// </pre></div>
260 ///
261 /// [recorded]: Value::record
262 /// [`Subscriber`]: super::subscriber::Subscriber
263 /// [records an `Event`]: super::subscriber::Subscriber::event
264 /// [set of `Value`s added to a `Span`]: super::subscriber::Subscriber::record
265 /// [`Event`]: super::event::Event
266 pub trait Visit {
267     /// Visits an arbitrary type implementing the [`valuable`] crate's `Valuable` trait.
268     ///
269     /// [`valuable`]: https://docs.rs/valuable
270     #[cfg(all(tracing_unstable, feature = "valuable"))]
271     #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
record_value(&mut self, field: &Field, value: valuable::Value<'_>)272     fn record_value(&mut self, field: &Field, value: valuable::Value<'_>) {
273         self.record_debug(field, &value)
274     }
275 
276     /// Visit a double-precision floating point value.
record_f64(&mut self, field: &Field, value: f64)277     fn record_f64(&mut self, field: &Field, value: f64) {
278         self.record_debug(field, &value)
279     }
280 
281     /// Visit a signed 64-bit integer value.
record_i64(&mut self, field: &Field, value: i64)282     fn record_i64(&mut self, field: &Field, value: i64) {
283         self.record_debug(field, &value)
284     }
285 
286     /// Visit an unsigned 64-bit integer value.
record_u64(&mut self, field: &Field, value: u64)287     fn record_u64(&mut self, field: &Field, value: u64) {
288         self.record_debug(field, &value)
289     }
290 
291     /// Visit a signed 128-bit integer value.
record_i128(&mut self, field: &Field, value: i128)292     fn record_i128(&mut self, field: &Field, value: i128) {
293         self.record_debug(field, &value)
294     }
295 
296     /// Visit an unsigned 128-bit integer value.
record_u128(&mut self, field: &Field, value: u128)297     fn record_u128(&mut self, field: &Field, value: u128) {
298         self.record_debug(field, &value)
299     }
300 
301     /// Visit a boolean value.
record_bool(&mut self, field: &Field, value: bool)302     fn record_bool(&mut self, field: &Field, value: bool) {
303         self.record_debug(field, &value)
304     }
305 
306     /// Visit a string value.
record_str(&mut self, field: &Field, value: &str)307     fn record_str(&mut self, field: &Field, value: &str) {
308         self.record_debug(field, &value)
309     }
310 
311     /// Records a type implementing `Error`.
312     ///
313     /// <div class="example-wrap" style="display:inline-block">
314     /// <pre class="ignore" style="white-space:normal;font:inherit;">
315     /// <strong>Note</strong>: This is only enabled when the Rust standard library is
316     /// present.
317     /// </pre>
318     /// </div>
319     #[cfg(feature = "std")]
320     #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static))321     fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
322         self.record_debug(field, &DisplayValue(value))
323     }
324 
325     /// Visit a value implementing `fmt::Debug`.
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)326     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug);
327 }
328 
329 /// A field value of an erased type.
330 ///
331 /// Implementors of `Value` may call the appropriate typed recording methods on
332 /// the [visitor] passed to their `record` method in order to indicate how
333 /// their data should be recorded.
334 ///
335 /// [visitor]: Visit
336 pub trait Value: crate::sealed::Sealed {
337     /// Visits this value with the given `Visitor`.
record(&self, key: &Field, visitor: &mut dyn Visit)338     fn record(&self, key: &Field, visitor: &mut dyn Visit);
339 }
340 
341 /// A `Value` which serializes using `fmt::Display`.
342 ///
343 /// Uses `record_debug` in the `Value` implementation to
344 /// avoid an unnecessary evaluation.
345 #[derive(Clone)]
346 pub struct DisplayValue<T: fmt::Display>(T);
347 
348 /// A `Value` which serializes as a string using `fmt::Debug`.
349 #[derive(Clone)]
350 pub struct DebugValue<T: fmt::Debug>(T);
351 
352 /// Wraps a type implementing `fmt::Display` as a `Value` that can be
353 /// recorded using its `Display` implementation.
display<T>(t: T) -> DisplayValue<T> where T: fmt::Display,354 pub fn display<T>(t: T) -> DisplayValue<T>
355 where
356     T: fmt::Display,
357 {
358     DisplayValue(t)
359 }
360 
361 /// Wraps a type implementing `fmt::Debug` as a `Value` that can be
362 /// recorded using its `Debug` implementation.
debug<T>(t: T) -> DebugValue<T> where T: fmt::Debug,363 pub fn debug<T>(t: T) -> DebugValue<T>
364 where
365     T: fmt::Debug,
366 {
367     DebugValue(t)
368 }
369 
370 /// Wraps a type implementing [`Valuable`] as a `Value` that
371 /// can be recorded using its `Valuable` implementation.
372 ///
373 /// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
374 #[cfg(all(tracing_unstable, feature = "valuable"))]
375 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
valuable<T>(t: &T) -> valuable::Value<'_> where T: valuable::Valuable,376 pub fn valuable<T>(t: &T) -> valuable::Value<'_>
377 where
378     T: valuable::Valuable,
379 {
380     t.as_value()
381 }
382 
383 // ===== impl Visit =====
384 
385 impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)386     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
387         self.field(field.name(), value);
388     }
389 }
390 
391 impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)392     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
393         self.entry(&format_args!("{}", field), value);
394     }
395 }
396 
397 impl<F> Visit for F
398 where
399     F: FnMut(&Field, &dyn fmt::Debug),
400 {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)401     fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
402         (self)(field, value)
403     }
404 }
405 
406 // ===== impl Value =====
407 
408 macro_rules! impl_values {
409     ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => {
410         $(
411             impl_value!{ $record( $( $whatever )+ ) }
412         )+
413     }
414 }
415 
416 macro_rules! ty_to_nonzero {
417     (u8) => {
418         NonZeroU8
419     };
420     (u16) => {
421         NonZeroU16
422     };
423     (u32) => {
424         NonZeroU32
425     };
426     (u64) => {
427         NonZeroU64
428     };
429     (u128) => {
430         NonZeroU128
431     };
432     (usize) => {
433         NonZeroUsize
434     };
435     (i8) => {
436         NonZeroI8
437     };
438     (i16) => {
439         NonZeroI16
440     };
441     (i32) => {
442         NonZeroI32
443     };
444     (i64) => {
445         NonZeroI64
446     };
447     (i128) => {
448         NonZeroI128
449     };
450     (isize) => {
451         NonZeroIsize
452     };
453 }
454 
455 macro_rules! impl_one_value {
456     (f32, $op:expr, $record:ident) => {
457         impl_one_value!(normal, f32, $op, $record);
458     };
459     (f64, $op:expr, $record:ident) => {
460         impl_one_value!(normal, f64, $op, $record);
461     };
462     (bool, $op:expr, $record:ident) => {
463         impl_one_value!(normal, bool, $op, $record);
464     };
465     ($value_ty:tt, $op:expr, $record:ident) => {
466         impl_one_value!(normal, $value_ty, $op, $record);
467         impl_one_value!(nonzero, $value_ty, $op, $record);
468     };
469     (normal, $value_ty:tt, $op:expr, $record:ident) => {
470         impl $crate::sealed::Sealed for $value_ty {}
471         impl $crate::field::Value for $value_ty {
472             fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
473                 // `op` is always a function; the closure is used because
474                 // sometimes there isn't a real function corresponding to that
475                 // operation. the clippy warning is not that useful here.
476                 #[allow(clippy::redundant_closure_call)]
477                 visitor.$record(key, $op(*self))
478             }
479         }
480     };
481     (nonzero, $value_ty:tt, $op:expr, $record:ident) => {
482         // This `use num::*;` is reported as unused because it gets emitted
483         // for every single invocation of this macro, so there are multiple `use`s.
484         // All but the first are useless indeed.
485         // We need this import because we can't write a path where one part is
486         // the `ty_to_nonzero!($value_ty)` invocation.
487         #[allow(clippy::useless_attribute, unused)]
488         use num::*;
489         impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
490         impl $crate::field::Value for ty_to_nonzero!($value_ty) {
491             fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
492                 // `op` is always a function; the closure is used because
493                 // sometimes there isn't a real function corresponding to that
494                 // operation. the clippy warning is not that useful here.
495                 #[allow(clippy::redundant_closure_call)]
496                 visitor.$record(key, $op(self.get()))
497             }
498         }
499     };
500 }
501 
502 macro_rules! impl_value {
503     ( $record:ident( $( $value_ty:tt ),+ ) ) => {
504         $(
505             impl_one_value!($value_ty, |this: $value_ty| this, $record);
506         )+
507     };
508     ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
509         $(
510             impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
511         )+
512     };
513 }
514 
515 // ===== impl Value =====
516 
517 impl_values! {
518     record_u64(u64),
519     record_u64(usize, u32, u16, u8 as u64),
520     record_i64(i64),
521     record_i64(isize, i32, i16, i8 as i64),
522     record_u128(u128),
523     record_i128(i128),
524     record_bool(bool),
525     record_f64(f64, f32 as f64)
526 }
527 
528 impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
529 impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit)530     fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
531         self.0.record(key, visitor)
532     }
533 }
534 
535 impl crate::sealed::Sealed for str {}
536 
537 impl Value for str {
record(&self, key: &Field, visitor: &mut dyn Visit)538     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
539         visitor.record_str(key, self)
540     }
541 }
542 
543 #[cfg(feature = "std")]
544 impl crate::sealed::Sealed for dyn std::error::Error + 'static {}
545 
546 #[cfg(feature = "std")]
547 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
548 impl Value for dyn std::error::Error + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)549     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
550         visitor.record_error(key, self)
551     }
552 }
553 
554 #[cfg(feature = "std")]
555 impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {}
556 
557 #[cfg(feature = "std")]
558 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
559 impl Value for dyn std::error::Error + Send + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)560     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
561         (self as &dyn std::error::Error).record(key, visitor)
562     }
563 }
564 
565 #[cfg(feature = "std")]
566 impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {}
567 
568 #[cfg(feature = "std")]
569 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
570 impl Value for dyn std::error::Error + Sync + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)571     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
572         (self as &dyn std::error::Error).record(key, visitor)
573     }
574 }
575 
576 #[cfg(feature = "std")]
577 impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {}
578 
579 #[cfg(feature = "std")]
580 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
581 impl Value for dyn std::error::Error + Send + Sync + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)582     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
583         (self as &dyn std::error::Error).record(key, visitor)
584     }
585 }
586 
587 impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {}
588 
589 impl<'a, T: ?Sized> Value for &'a T
590 where
591     T: Value + 'a,
592 {
record(&self, key: &Field, visitor: &mut dyn Visit)593     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
594         (*self).record(key, visitor)
595     }
596 }
597 
598 impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {}
599 
600 impl<'a, T: ?Sized> Value for &'a mut T
601 where
602     T: Value + 'a,
603 {
record(&self, key: &Field, visitor: &mut dyn Visit)604     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
605         // Don't use `(*self).record(key, visitor)`, otherwise would
606         // cause stack overflow due to `unconditional_recursion`.
607         T::record(self, key, visitor)
608     }
609 }
610 
611 impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {}
612 
613 impl<'a> Value for fmt::Arguments<'a> {
record(&self, key: &Field, visitor: &mut dyn Visit)614     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
615         visitor.record_debug(key, self)
616     }
617 }
618 
619 impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {}
620 
621 impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T>
622 where
623     T: Value,
624 {
625     #[inline]
record(&self, key: &Field, visitor: &mut dyn Visit)626     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
627         self.as_ref().record(key, visitor)
628     }
629 }
630 
631 impl crate::sealed::Sealed for String {}
632 impl Value for String {
record(&self, key: &Field, visitor: &mut dyn Visit)633     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
634         visitor.record_str(key, self.as_str())
635     }
636 }
637 
638 impl fmt::Debug for dyn Value {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result639     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
640         // We are only going to be recording the field value, so we don't
641         // actually care about the field name here.
642         struct NullCallsite;
643         static NULL_CALLSITE: NullCallsite = NullCallsite;
644         impl crate::callsite::Callsite for NullCallsite {
645             fn set_interest(&self, _: crate::subscriber::Interest) {
646                 unreachable!("you somehow managed to register the null callsite?")
647             }
648 
649             fn metadata(&self) -> &crate::Metadata<'_> {
650                 unreachable!("you somehow managed to access the null callsite?")
651             }
652         }
653 
654         static FIELD: Field = Field {
655             i: 0,
656             fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)),
657         };
658 
659         let mut res = Ok(());
660         self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| {
661             res = write!(f, "{:?}", val);
662         });
663         res
664     }
665 }
666 
667 impl fmt::Display for dyn Value {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result668     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
669         fmt::Debug::fmt(self, f)
670     }
671 }
672 
673 // ===== impl DisplayValue =====
674 
675 impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {}
676 
677 impl<T> Value for DisplayValue<T>
678 where
679     T: fmt::Display,
680 {
record(&self, key: &Field, visitor: &mut dyn Visit)681     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
682         visitor.record_debug(key, self)
683     }
684 }
685 
686 impl<T: fmt::Display> fmt::Debug for DisplayValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result687     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
688         fmt::Display::fmt(self, f)
689     }
690 }
691 
692 impl<T: fmt::Display> fmt::Display for DisplayValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result693     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
694         self.0.fmt(f)
695     }
696 }
697 
698 // ===== impl DebugValue =====
699 
700 impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {}
701 
702 impl<T> Value for DebugValue<T>
703 where
704     T: fmt::Debug,
705 {
record(&self, key: &Field, visitor: &mut dyn Visit)706     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
707         visitor.record_debug(key, &self.0)
708     }
709 }
710 
711 impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result712     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
713         self.0.fmt(f)
714     }
715 }
716 
717 // ===== impl ValuableValue =====
718 
719 #[cfg(all(tracing_unstable, feature = "valuable"))]
720 impl crate::sealed::Sealed for valuable::Value<'_> {}
721 
722 #[cfg(all(tracing_unstable, feature = "valuable"))]
723 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
724 impl Value for valuable::Value<'_> {
record(&self, key: &Field, visitor: &mut dyn Visit)725     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
726         visitor.record_value(key, *self)
727     }
728 }
729 
730 #[cfg(all(tracing_unstable, feature = "valuable"))]
731 impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {}
732 
733 #[cfg(all(tracing_unstable, feature = "valuable"))]
734 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
735 impl Value for &'_ dyn valuable::Valuable {
record(&self, key: &Field, visitor: &mut dyn Visit)736     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
737         visitor.record_value(key, self.as_value())
738     }
739 }
740 
741 impl crate::sealed::Sealed for Empty {}
742 impl Value for Empty {
743     #[inline]
record(&self, _: &Field, _: &mut dyn Visit)744     fn record(&self, _: &Field, _: &mut dyn Visit) {}
745 }
746 
747 impl<T: Value> crate::sealed::Sealed for Option<T> {}
748 
749 impl<T: Value> Value for Option<T> {
record(&self, key: &Field, visitor: &mut dyn Visit)750     fn record(&self, key: &Field, visitor: &mut dyn Visit) {
751         if let Some(v) = &self {
752             v.record(key, visitor)
753         }
754     }
755 }
756 
757 // ===== impl Field =====
758 
759 impl Field {
760     /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
761     /// which defines this field.
762     ///
763     /// [`Identifier`]: super::callsite::Identifier
764     /// [`Callsite`]: super::callsite::Callsite
765     #[inline]
callsite(&self) -> callsite::Identifier766     pub fn callsite(&self) -> callsite::Identifier {
767         self.fields.callsite()
768     }
769 
770     /// Returns a string representing the name of the field.
name(&self) -> &'static str771     pub fn name(&self) -> &'static str {
772         self.fields.names[self.i]
773     }
774 }
775 
776 impl fmt::Display for Field {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result777     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
778         f.pad(self.name())
779     }
780 }
781 
782 impl AsRef<str> for Field {
as_ref(&self) -> &str783     fn as_ref(&self) -> &str {
784         self.name()
785     }
786 }
787 
788 impl PartialEq for Field {
eq(&self, other: &Self) -> bool789     fn eq(&self, other: &Self) -> bool {
790         self.callsite() == other.callsite() && self.i == other.i
791     }
792 }
793 
794 impl Eq for Field {}
795 
796 impl Hash for Field {
hash<H>(&self, state: &mut H) where H: Hasher,797     fn hash<H>(&self, state: &mut H)
798     where
799         H: Hasher,
800     {
801         self.callsite().hash(state);
802         self.i.hash(state);
803     }
804 }
805 
806 impl Clone for Field {
clone(&self) -> Self807     fn clone(&self) -> Self {
808         Field {
809             i: self.i,
810             fields: FieldSet {
811                 names: self.fields.names,
812                 callsite: self.fields.callsite(),
813             },
814         }
815     }
816 }
817 
818 // ===== impl FieldSet =====
819 
820 impl FieldSet {
821     /// Constructs a new `FieldSet` with the given array of field names and callsite.
new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self822     pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self {
823         Self { names, callsite }
824     }
825 
826     /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
827     /// which defines this set of fields..
828     ///
829     /// [`Identifier`]: super::callsite::Identifier
830     /// [`Callsite`]: super::callsite::Callsite
831     #[inline]
callsite(&self) -> callsite::Identifier832     pub(crate) fn callsite(&self) -> callsite::Identifier {
833         callsite::Identifier(self.callsite.0)
834     }
835 
836     /// Returns the [`Field`] named `name`, or `None` if no such field exists.
837     ///
838     /// [`Field`]: super::Field
field<Q: ?Sized>(&self, name: &Q) -> Option<Field> where Q: Borrow<str>,839     pub fn field<Q: ?Sized>(&self, name: &Q) -> Option<Field>
840     where
841         Q: Borrow<str>,
842     {
843         let name = &name.borrow();
844         self.names.iter().position(|f| f == name).map(|i| Field {
845             i,
846             fields: FieldSet {
847                 names: self.names,
848                 callsite: self.callsite(),
849             },
850         })
851     }
852 
853     /// Returns `true` if `self` contains the given `field`.
854     ///
855     /// <div class="example-wrap" style="display:inline-block">
856     /// <pre class="ignore" style="white-space:normal;font:inherit;">
857     /// <strong>Note</strong>: If <code>field</code> shares a name with a field
858     /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
859     /// with a different callsite, this <code>FieldSet</code> does <em>not</em>
860     /// contain it. This is so that if two separate span callsites define a field
861     /// named "foo", the <code>Field</code> corresponding to "foo" for each
862     /// of those callsites are not equivalent.
863     /// </pre></div>
contains(&self, field: &Field) -> bool864     pub fn contains(&self, field: &Field) -> bool {
865         field.callsite() == self.callsite() && field.i <= self.len()
866     }
867 
868     /// Returns an iterator over the `Field`s in this `FieldSet`.
869     #[inline]
iter(&self) -> Iter870     pub fn iter(&self) -> Iter {
871         let idxs = 0..self.len();
872         Iter {
873             idxs,
874             fields: FieldSet {
875                 names: self.names,
876                 callsite: self.callsite(),
877             },
878         }
879     }
880 
881     /// Returns a new `ValueSet` with entries for this `FieldSet`'s values.
882     #[doc(hidden)]
value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> where V: ValidLen<'v>,883     pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v>
884     where
885         V: ValidLen<'v>,
886     {
887         ValueSet {
888             fields: self,
889             values: values.borrow(),
890         }
891     }
892 
893     /// Returns the number of fields in this `FieldSet`.
894     #[inline]
len(&self) -> usize895     pub fn len(&self) -> usize {
896         self.names.len()
897     }
898 
899     /// Returns whether or not this `FieldSet` has fields.
900     #[inline]
is_empty(&self) -> bool901     pub fn is_empty(&self) -> bool {
902         self.names.is_empty()
903     }
904 }
905 
906 impl<'a> IntoIterator for &'a FieldSet {
907     type IntoIter = Iter;
908     type Item = Field;
909     #[inline]
into_iter(self) -> Self::IntoIter910     fn into_iter(self) -> Self::IntoIter {
911         self.iter()
912     }
913 }
914 
915 impl fmt::Debug for FieldSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result916     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
917         f.debug_struct("FieldSet")
918             .field("names", &self.names)
919             .field("callsite", &self.callsite)
920             .finish()
921     }
922 }
923 
924 impl fmt::Display for FieldSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result925     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
926         f.debug_set()
927             .entries(self.names.iter().map(display))
928             .finish()
929     }
930 }
931 
932 impl Eq for FieldSet {}
933 
934 impl PartialEq for FieldSet {
eq(&self, other: &Self) -> bool935     fn eq(&self, other: &Self) -> bool {
936         if core::ptr::eq(&self, &other) {
937             true
938         } else if cfg!(not(debug_assertions)) {
939             // In a well-behaving application, two `FieldSet`s can be assumed to
940             // be totally equal so long as they share the same callsite.
941             self.callsite == other.callsite
942         } else {
943             // However, when debug-assertions are enabled, do NOT assume that
944             // the application is well-behaving; check every the field names of
945             // each `FieldSet` for equality.
946 
947             // `FieldSet` is destructured here to ensure a compile-error if the
948             // fields of `FieldSet` change.
949             let Self {
950                 names: lhs_names,
951                 callsite: lhs_callsite,
952             } = self;
953 
954             let Self {
955                 names: rhs_names,
956                 callsite: rhs_callsite,
957             } = &other;
958 
959             // Check callsite equality first, as it is probably cheaper to do
960             // than str equality.
961             lhs_callsite == rhs_callsite && lhs_names == rhs_names
962         }
963     }
964 }
965 
966 // ===== impl Iter =====
967 
968 impl Iterator for Iter {
969     type Item = Field;
970     #[inline]
next(&mut self) -> Option<Field>971     fn next(&mut self) -> Option<Field> {
972         let i = self.idxs.next()?;
973         Some(Field {
974             i,
975             fields: FieldSet {
976                 names: self.fields.names,
977                 callsite: self.fields.callsite(),
978             },
979         })
980     }
981 }
982 
983 // ===== impl ValueSet =====
984 
985 impl<'a> ValueSet<'a> {
986     /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
987     /// defining the fields this `ValueSet` refers to.
988     ///
989     /// [`Identifier`]: super::callsite::Identifier
990     /// [`Callsite`]: super::callsite::Callsite
991     #[inline]
callsite(&self) -> callsite::Identifier992     pub fn callsite(&self) -> callsite::Identifier {
993         self.fields.callsite()
994     }
995 
996     /// Visits all the fields in this `ValueSet` with the provided [visitor].
997     ///
998     /// [visitor]: Visit
record(&self, visitor: &mut dyn Visit)999     pub fn record(&self, visitor: &mut dyn Visit) {
1000         let my_callsite = self.callsite();
1001         for (field, value) in self.values {
1002             if field.callsite() != my_callsite {
1003                 continue;
1004             }
1005             if let Some(value) = value {
1006                 value.record(field, visitor);
1007             }
1008         }
1009     }
1010 
1011     /// Returns the number of fields in this `ValueSet` that would be visited
1012     /// by a given [visitor] to the [`ValueSet::record()`] method.
1013     ///
1014     /// [visitor]: Visit
1015     /// [`ValueSet::record()`]: ValueSet::record()
len(&self) -> usize1016     pub fn len(&self) -> usize {
1017         let my_callsite = self.callsite();
1018         self.values
1019             .iter()
1020             .filter(|(field, _)| field.callsite() == my_callsite)
1021             .count()
1022     }
1023 
1024     /// Returns `true` if this `ValueSet` contains a value for the given `Field`.
contains(&self, field: &Field) -> bool1025     pub(crate) fn contains(&self, field: &Field) -> bool {
1026         field.callsite() == self.callsite()
1027             && self
1028                 .values
1029                 .iter()
1030                 .any(|(key, val)| *key == field && val.is_some())
1031     }
1032 
1033     /// Returns true if this `ValueSet` contains _no_ values.
is_empty(&self) -> bool1034     pub fn is_empty(&self) -> bool {
1035         let my_callsite = self.callsite();
1036         self.values
1037             .iter()
1038             .all(|(key, val)| val.is_none() || key.callsite() != my_callsite)
1039     }
1040 
field_set(&self) -> &FieldSet1041     pub(crate) fn field_set(&self) -> &FieldSet {
1042         self.fields
1043     }
1044 }
1045 
1046 impl<'a> fmt::Debug for ValueSet<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1047     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1048         self.values
1049             .iter()
1050             .fold(&mut f.debug_struct("ValueSet"), |dbg, (key, v)| {
1051                 if let Some(val) = v {
1052                     val.record(key, dbg);
1053                 }
1054                 dbg
1055             })
1056             .field("callsite", &self.callsite())
1057             .finish()
1058     }
1059 }
1060 
1061 impl<'a> fmt::Display for ValueSet<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1062     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1063         self.values
1064             .iter()
1065             .fold(&mut f.debug_map(), |dbg, (key, v)| {
1066                 if let Some(val) = v {
1067                     val.record(key, dbg);
1068                 }
1069                 dbg
1070             })
1071             .finish()
1072     }
1073 }
1074 
1075 // ===== impl ValidLen =====
1076 
1077 mod private {
1078     use super::*;
1079 
1080     /// Restrictions on `ValueSet` lengths were removed in #2508 but this type remains for backwards compatibility.
1081     pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {}
1082 
1083     impl<'a, const N: usize> ValidLen<'a> for [(&'a Field, Option<&'a (dyn Value + 'a)>); N] {}
1084 }
1085 
1086 #[cfg(test)]
1087 mod test {
1088     use super::*;
1089     use crate::metadata::{Kind, Level, Metadata};
1090     use crate::stdlib::{borrow::ToOwned, string::String};
1091 
1092     // Make sure TEST_CALLSITE_* have non-zero size, so they can't be located at the same address.
1093     struct TestCallsite1(u8);
1094     static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1(0);
1095     static TEST_META_1: Metadata<'static> = metadata! {
1096         name: "field_test1",
1097         target: module_path!(),
1098         level: Level::INFO,
1099         fields: &["foo", "bar", "baz"],
1100         callsite: &TEST_CALLSITE_1,
1101         kind: Kind::SPAN,
1102     };
1103 
1104     impl crate::callsite::Callsite for TestCallsite1 {
set_interest(&self, _: crate::subscriber::Interest)1105         fn set_interest(&self, _: crate::subscriber::Interest) {
1106             unimplemented!()
1107         }
1108 
metadata(&self) -> &Metadata<'_>1109         fn metadata(&self) -> &Metadata<'_> {
1110             &TEST_META_1
1111         }
1112     }
1113 
1114     struct TestCallsite2(u8);
1115     static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2(0);
1116     static TEST_META_2: Metadata<'static> = metadata! {
1117         name: "field_test2",
1118         target: module_path!(),
1119         level: Level::INFO,
1120         fields: &["foo", "bar", "baz"],
1121         callsite: &TEST_CALLSITE_2,
1122         kind: Kind::SPAN,
1123     };
1124 
1125     impl crate::callsite::Callsite for TestCallsite2 {
set_interest(&self, _: crate::subscriber::Interest)1126         fn set_interest(&self, _: crate::subscriber::Interest) {
1127             unimplemented!()
1128         }
1129 
metadata(&self) -> &Metadata<'_>1130         fn metadata(&self) -> &Metadata<'_> {
1131             &TEST_META_2
1132         }
1133     }
1134 
1135     #[test]
value_set_with_no_values_is_empty()1136     fn value_set_with_no_values_is_empty() {
1137         let fields = TEST_META_1.fields();
1138         let values = &[
1139             (&fields.field("foo").unwrap(), None),
1140             (&fields.field("bar").unwrap(), None),
1141             (&fields.field("baz").unwrap(), None),
1142         ];
1143         let valueset = fields.value_set(values);
1144         assert!(valueset.is_empty());
1145     }
1146 
1147     #[test]
empty_value_set_is_empty()1148     fn empty_value_set_is_empty() {
1149         let fields = TEST_META_1.fields();
1150         let valueset = fields.value_set(&[]);
1151         assert!(valueset.is_empty());
1152     }
1153 
1154     #[test]
value_sets_with_fields_from_other_callsites_are_empty()1155     fn value_sets_with_fields_from_other_callsites_are_empty() {
1156         let fields = TEST_META_1.fields();
1157         let values = &[
1158             (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
1159             (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
1160             (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
1161         ];
1162         let valueset = TEST_META_2.fields().value_set(values);
1163         assert!(valueset.is_empty())
1164     }
1165 
1166     #[test]
sparse_value_sets_are_not_empty()1167     fn sparse_value_sets_are_not_empty() {
1168         let fields = TEST_META_1.fields();
1169         let values = &[
1170             (&fields.field("foo").unwrap(), None),
1171             (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
1172             (&fields.field("baz").unwrap(), None),
1173         ];
1174         let valueset = fields.value_set(values);
1175         assert!(!valueset.is_empty());
1176     }
1177 
1178     #[test]
fields_from_other_callsets_are_skipped()1179     fn fields_from_other_callsets_are_skipped() {
1180         let fields = TEST_META_1.fields();
1181         let values = &[
1182             (&fields.field("foo").unwrap(), None),
1183             (
1184                 &TEST_META_2.fields().field("bar").unwrap(),
1185                 Some(&57 as &dyn Value),
1186             ),
1187             (&fields.field("baz").unwrap(), None),
1188         ];
1189 
1190         struct MyVisitor;
1191         impl Visit for MyVisitor {
1192             fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
1193                 assert_eq!(field.callsite(), TEST_META_1.callsite())
1194             }
1195         }
1196         let valueset = fields.value_set(values);
1197         valueset.record(&mut MyVisitor);
1198     }
1199 
1200     #[test]
empty_fields_are_skipped()1201     fn empty_fields_are_skipped() {
1202         let fields = TEST_META_1.fields();
1203         let values = &[
1204             (&fields.field("foo").unwrap(), Some(&Empty as &dyn Value)),
1205             (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
1206             (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
1207         ];
1208 
1209         struct MyVisitor;
1210         impl Visit for MyVisitor {
1211             fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
1212                 assert_eq!(field.name(), "bar")
1213             }
1214         }
1215         let valueset = fields.value_set(values);
1216         valueset.record(&mut MyVisitor);
1217     }
1218 
1219     #[test]
record_debug_fn()1220     fn record_debug_fn() {
1221         let fields = TEST_META_1.fields();
1222         let values = &[
1223             (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
1224             (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
1225             (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
1226         ];
1227         let valueset = fields.value_set(values);
1228         let mut result = String::new();
1229         valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
1230             use crate::stdlib::fmt::Write;
1231             write!(&mut result, "{:?}", value).unwrap();
1232         });
1233         assert_eq!(result, "123".to_owned());
1234     }
1235 
1236     #[test]
1237     #[cfg(feature = "std")]
record_error()1238     fn record_error() {
1239         let fields = TEST_META_1.fields();
1240         let err: Box<dyn std::error::Error + Send + Sync + 'static> =
1241             std::io::Error::new(std::io::ErrorKind::Other, "lol").into();
1242         let values = &[
1243             (&fields.field("foo").unwrap(), Some(&err as &dyn Value)),
1244             (&fields.field("bar").unwrap(), Some(&Empty as &dyn Value)),
1245             (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
1246         ];
1247         let valueset = fields.value_set(values);
1248         let mut result = String::new();
1249         valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
1250             use core::fmt::Write;
1251             write!(&mut result, "{:?}", value).unwrap();
1252         });
1253         assert_eq!(result, format!("{}", err));
1254     }
1255 }
1256