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::{self, Write},
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 /// Visit a byte slice.
record_bytes(&mut self, field: &Field, value: &[u8])312 fn record_bytes(&mut self, field: &Field, value: &[u8]) {
313 self.record_debug(field, &HexBytes(value))
314 }
315
316 /// Records a type implementing `Error`.
317 ///
318 /// <div class="example-wrap" style="display:inline-block">
319 /// <pre class="ignore" style="white-space:normal;font:inherit;">
320 /// <strong>Note</strong>: This is only enabled when the Rust standard library is
321 /// present.
322 /// </pre>
323 /// </div>
324 #[cfg(feature = "std")]
325 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static))326 fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
327 self.record_debug(field, &DisplayValue(value))
328 }
329
330 /// Visit a value implementing `fmt::Debug`.
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)331 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug);
332 }
333
334 /// A field value of an erased type.
335 ///
336 /// Implementors of `Value` may call the appropriate typed recording methods on
337 /// the [visitor] passed to their `record` method in order to indicate how
338 /// their data should be recorded.
339 ///
340 /// [visitor]: Visit
341 pub trait Value: crate::sealed::Sealed {
342 /// Visits this value with the given `Visitor`.
record(&self, key: &Field, visitor: &mut dyn Visit)343 fn record(&self, key: &Field, visitor: &mut dyn Visit);
344 }
345
346 /// A `Value` which serializes using `fmt::Display`.
347 ///
348 /// Uses `record_debug` in the `Value` implementation to
349 /// avoid an unnecessary evaluation.
350 #[derive(Clone)]
351 pub struct DisplayValue<T: fmt::Display>(T);
352
353 /// A `Value` which serializes as a string using `fmt::Debug`.
354 #[derive(Clone)]
355 pub struct DebugValue<T: fmt::Debug>(T);
356
357 /// Wraps a type implementing `fmt::Display` as a `Value` that can be
358 /// recorded using its `Display` implementation.
display<T>(t: T) -> DisplayValue<T> where T: fmt::Display,359 pub fn display<T>(t: T) -> DisplayValue<T>
360 where
361 T: fmt::Display,
362 {
363 DisplayValue(t)
364 }
365
366 /// Wraps a type implementing `fmt::Debug` as a `Value` that can be
367 /// recorded using its `Debug` implementation.
debug<T>(t: T) -> DebugValue<T> where T: fmt::Debug,368 pub fn debug<T>(t: T) -> DebugValue<T>
369 where
370 T: fmt::Debug,
371 {
372 DebugValue(t)
373 }
374
375 /// Wraps a type implementing [`Valuable`] as a `Value` that
376 /// can be recorded using its `Valuable` implementation.
377 ///
378 /// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
379 #[cfg(all(tracing_unstable, feature = "valuable"))]
380 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
valuable<T>(t: &T) -> valuable::Value<'_> where T: valuable::Valuable,381 pub fn valuable<T>(t: &T) -> valuable::Value<'_>
382 where
383 T: valuable::Valuable,
384 {
385 t.as_value()
386 }
387
388 struct HexBytes<'a>(&'a [u8]);
389
390 impl<'a> fmt::Debug for HexBytes<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result391 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
392 f.write_char('[')?;
393
394 let mut bytes = self.0.iter();
395
396 if let Some(byte) = bytes.next() {
397 f.write_fmt(format_args!("{byte:02x}"))?;
398 }
399
400 for byte in bytes {
401 f.write_fmt(format_args!(" {byte:02x}"))?;
402 }
403
404 f.write_char(']')
405 }
406 }
407
408 // ===== impl Visit =====
409
410 impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)411 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
412 self.field(field.name(), value);
413 }
414 }
415
416 impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)417 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
418 self.entry(&format_args!("{}", field), value);
419 }
420 }
421
422 impl<F> Visit for F
423 where
424 F: FnMut(&Field, &dyn fmt::Debug),
425 {
record_debug(&mut self, field: &Field, value: &dyn fmt::Debug)426 fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
427 (self)(field, value)
428 }
429 }
430
431 // ===== impl Value =====
432
433 macro_rules! impl_values {
434 ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => {
435 $(
436 impl_value!{ $record( $( $whatever )+ ) }
437 )+
438 }
439 }
440
441 macro_rules! ty_to_nonzero {
442 (u8) => {
443 NonZeroU8
444 };
445 (u16) => {
446 NonZeroU16
447 };
448 (u32) => {
449 NonZeroU32
450 };
451 (u64) => {
452 NonZeroU64
453 };
454 (u128) => {
455 NonZeroU128
456 };
457 (usize) => {
458 NonZeroUsize
459 };
460 (i8) => {
461 NonZeroI8
462 };
463 (i16) => {
464 NonZeroI16
465 };
466 (i32) => {
467 NonZeroI32
468 };
469 (i64) => {
470 NonZeroI64
471 };
472 (i128) => {
473 NonZeroI128
474 };
475 (isize) => {
476 NonZeroIsize
477 };
478 }
479
480 macro_rules! impl_one_value {
481 (f32, $op:expr, $record:ident) => {
482 impl_one_value!(normal, f32, $op, $record);
483 };
484 (f64, $op:expr, $record:ident) => {
485 impl_one_value!(normal, f64, $op, $record);
486 };
487 (bool, $op:expr, $record:ident) => {
488 impl_one_value!(normal, bool, $op, $record);
489 };
490 ($value_ty:tt, $op:expr, $record:ident) => {
491 impl_one_value!(normal, $value_ty, $op, $record);
492 impl_one_value!(nonzero, $value_ty, $op, $record);
493 };
494 (normal, $value_ty:tt, $op:expr, $record:ident) => {
495 impl $crate::sealed::Sealed for $value_ty {}
496 impl $crate::field::Value for $value_ty {
497 fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
498 // `op` is always a function; the closure is used because
499 // sometimes there isn't a real function corresponding to that
500 // operation. the clippy warning is not that useful here.
501 #[allow(clippy::redundant_closure_call)]
502 visitor.$record(key, $op(*self))
503 }
504 }
505 };
506 (nonzero, $value_ty:tt, $op:expr, $record:ident) => {
507 // This `use num::*;` is reported as unused because it gets emitted
508 // for every single invocation of this macro, so there are multiple `use`s.
509 // All but the first are useless indeed.
510 // We need this import because we can't write a path where one part is
511 // the `ty_to_nonzero!($value_ty)` invocation.
512 #[allow(clippy::useless_attribute, unused)]
513 use num::*;
514 impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
515 impl $crate::field::Value for ty_to_nonzero!($value_ty) {
516 fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
517 // `op` is always a function; the closure is used because
518 // sometimes there isn't a real function corresponding to that
519 // operation. the clippy warning is not that useful here.
520 #[allow(clippy::redundant_closure_call)]
521 visitor.$record(key, $op(self.get()))
522 }
523 }
524 };
525 }
526
527 macro_rules! impl_value {
528 ( $record:ident( $( $value_ty:tt ),+ ) ) => {
529 $(
530 impl_one_value!($value_ty, |this: $value_ty| this, $record);
531 )+
532 };
533 ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
534 $(
535 impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
536 )+
537 };
538 }
539
540 // ===== impl Value =====
541
542 impl_values! {
543 record_u64(u64),
544 record_u64(usize, u32, u16, u8 as u64),
545 record_i64(i64),
546 record_i64(isize, i32, i16, i8 as i64),
547 record_u128(u128),
548 record_i128(i128),
549 record_bool(bool),
550 record_f64(f64, f32 as f64)
551 }
552
553 impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
554 impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit)555 fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
556 self.0.record(key, visitor)
557 }
558 }
559
560 impl crate::sealed::Sealed for str {}
561
562 impl Value for str {
record(&self, key: &Field, visitor: &mut dyn Visit)563 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
564 visitor.record_str(key, self)
565 }
566 }
567
568 impl crate::sealed::Sealed for [u8] {}
569
570 impl Value for [u8] {
record(&self, key: &Field, visitor: &mut dyn Visit)571 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
572 visitor.record_bytes(key, self)
573 }
574 }
575
576 #[cfg(feature = "std")]
577 impl crate::sealed::Sealed for dyn std::error::Error + 'static {}
578
579 #[cfg(feature = "std")]
580 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
581 impl Value for dyn std::error::Error + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)582 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
583 visitor.record_error(key, self)
584 }
585 }
586
587 #[cfg(feature = "std")]
588 impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {}
589
590 #[cfg(feature = "std")]
591 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
592 impl Value for dyn std::error::Error + Send + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)593 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
594 (self as &dyn std::error::Error).record(key, visitor)
595 }
596 }
597
598 #[cfg(feature = "std")]
599 impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {}
600
601 #[cfg(feature = "std")]
602 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
603 impl Value for dyn std::error::Error + Sync + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)604 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
605 (self as &dyn std::error::Error).record(key, visitor)
606 }
607 }
608
609 #[cfg(feature = "std")]
610 impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {}
611
612 #[cfg(feature = "std")]
613 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
614 impl Value for dyn std::error::Error + Send + Sync + 'static {
record(&self, key: &Field, visitor: &mut dyn Visit)615 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
616 (self as &dyn std::error::Error).record(key, visitor)
617 }
618 }
619
620 impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {}
621
622 impl<'a, T: ?Sized> Value for &'a T
623 where
624 T: Value + 'a,
625 {
record(&self, key: &Field, visitor: &mut dyn Visit)626 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
627 (*self).record(key, visitor)
628 }
629 }
630
631 impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {}
632
633 impl<'a, T: ?Sized> Value for &'a mut T
634 where
635 T: Value + 'a,
636 {
record(&self, key: &Field, visitor: &mut dyn Visit)637 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
638 // Don't use `(*self).record(key, visitor)`, otherwise would
639 // cause stack overflow due to `unconditional_recursion`.
640 T::record(self, key, visitor)
641 }
642 }
643
644 impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {}
645
646 impl<'a> Value for fmt::Arguments<'a> {
record(&self, key: &Field, visitor: &mut dyn Visit)647 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
648 visitor.record_debug(key, self)
649 }
650 }
651
652 impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {}
653
654 impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T>
655 where
656 T: Value,
657 {
658 #[inline]
record(&self, key: &Field, visitor: &mut dyn Visit)659 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
660 self.as_ref().record(key, visitor)
661 }
662 }
663
664 impl crate::sealed::Sealed for String {}
665 impl Value for String {
record(&self, key: &Field, visitor: &mut dyn Visit)666 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
667 visitor.record_str(key, self.as_str())
668 }
669 }
670
671 impl fmt::Debug for dyn Value {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result672 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
673 // We are only going to be recording the field value, so we don't
674 // actually care about the field name here.
675 struct NullCallsite;
676 static NULL_CALLSITE: NullCallsite = NullCallsite;
677 impl crate::callsite::Callsite for NullCallsite {
678 fn set_interest(&self, _: crate::subscriber::Interest) {
679 unreachable!("you somehow managed to register the null callsite?")
680 }
681
682 fn metadata(&self) -> &crate::Metadata<'_> {
683 unreachable!("you somehow managed to access the null callsite?")
684 }
685 }
686
687 static FIELD: Field = Field {
688 i: 0,
689 fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)),
690 };
691
692 let mut res = Ok(());
693 self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| {
694 res = write!(f, "{:?}", val);
695 });
696 res
697 }
698 }
699
700 impl fmt::Display for dyn Value {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result701 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
702 fmt::Debug::fmt(self, f)
703 }
704 }
705
706 // ===== impl DisplayValue =====
707
708 impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {}
709
710 impl<T> Value for DisplayValue<T>
711 where
712 T: fmt::Display,
713 {
record(&self, key: &Field, visitor: &mut dyn Visit)714 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
715 visitor.record_debug(key, self)
716 }
717 }
718
719 impl<T: fmt::Display> fmt::Debug for DisplayValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result720 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
721 fmt::Display::fmt(self, f)
722 }
723 }
724
725 impl<T: fmt::Display> fmt::Display for DisplayValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result726 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
727 self.0.fmt(f)
728 }
729 }
730
731 // ===== impl DebugValue =====
732
733 impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {}
734
735 impl<T> Value for DebugValue<T>
736 where
737 T: fmt::Debug,
738 {
record(&self, key: &Field, visitor: &mut dyn Visit)739 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
740 visitor.record_debug(key, &self.0)
741 }
742 }
743
744 impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result745 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
746 self.0.fmt(f)
747 }
748 }
749
750 // ===== impl ValuableValue =====
751
752 #[cfg(all(tracing_unstable, feature = "valuable"))]
753 impl crate::sealed::Sealed for valuable::Value<'_> {}
754
755 #[cfg(all(tracing_unstable, feature = "valuable"))]
756 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
757 impl Value for valuable::Value<'_> {
record(&self, key: &Field, visitor: &mut dyn Visit)758 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
759 visitor.record_value(key, *self)
760 }
761 }
762
763 #[cfg(all(tracing_unstable, feature = "valuable"))]
764 impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {}
765
766 #[cfg(all(tracing_unstable, feature = "valuable"))]
767 #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
768 impl Value for &'_ dyn valuable::Valuable {
record(&self, key: &Field, visitor: &mut dyn Visit)769 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
770 visitor.record_value(key, self.as_value())
771 }
772 }
773
774 impl crate::sealed::Sealed for Empty {}
775 impl Value for Empty {
776 #[inline]
record(&self, _: &Field, _: &mut dyn Visit)777 fn record(&self, _: &Field, _: &mut dyn Visit) {}
778 }
779
780 impl<T: Value> crate::sealed::Sealed for Option<T> {}
781
782 impl<T: Value> Value for Option<T> {
record(&self, key: &Field, visitor: &mut dyn Visit)783 fn record(&self, key: &Field, visitor: &mut dyn Visit) {
784 if let Some(v) = &self {
785 v.record(key, visitor)
786 }
787 }
788 }
789
790 // ===== impl Field =====
791
792 impl Field {
793 /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
794 /// which defines this field.
795 ///
796 /// [`Identifier`]: super::callsite::Identifier
797 /// [`Callsite`]: super::callsite::Callsite
798 #[inline]
callsite(&self) -> callsite::Identifier799 pub fn callsite(&self) -> callsite::Identifier {
800 self.fields.callsite()
801 }
802
803 /// Returns a string representing the name of the field.
name(&self) -> &'static str804 pub fn name(&self) -> &'static str {
805 self.fields.names[self.i]
806 }
807
808 /// Returns the index of this field in its [`FieldSet`].
index(&self) -> usize809 pub fn index(&self) -> usize {
810 self.i
811 }
812 }
813
814 impl fmt::Display for Field {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result815 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
816 f.pad(self.name())
817 }
818 }
819
820 impl AsRef<str> for Field {
as_ref(&self) -> &str821 fn as_ref(&self) -> &str {
822 self.name()
823 }
824 }
825
826 impl PartialEq for Field {
eq(&self, other: &Self) -> bool827 fn eq(&self, other: &Self) -> bool {
828 self.callsite() == other.callsite() && self.i == other.i
829 }
830 }
831
832 impl Eq for Field {}
833
834 impl Hash for Field {
hash<H>(&self, state: &mut H) where H: Hasher,835 fn hash<H>(&self, state: &mut H)
836 where
837 H: Hasher,
838 {
839 self.callsite().hash(state);
840 self.i.hash(state);
841 }
842 }
843
844 impl Clone for Field {
clone(&self) -> Self845 fn clone(&self) -> Self {
846 Field {
847 i: self.i,
848 fields: FieldSet {
849 names: self.fields.names,
850 callsite: self.fields.callsite(),
851 },
852 }
853 }
854 }
855
856 // ===== impl FieldSet =====
857
858 impl FieldSet {
859 /// Constructs a new `FieldSet` with the given array of field names and callsite.
new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self860 pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self {
861 Self { names, callsite }
862 }
863
864 /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
865 /// which defines this set of fields..
866 ///
867 /// [`Identifier`]: super::callsite::Identifier
868 /// [`Callsite`]: super::callsite::Callsite
869 #[inline]
callsite(&self) -> callsite::Identifier870 pub(crate) fn callsite(&self) -> callsite::Identifier {
871 callsite::Identifier(self.callsite.0)
872 }
873
874 /// Returns the [`Field`] named `name`, or `None` if no such field exists.
875 ///
876 /// [`Field`]: super::Field
field<Q: Borrow<str> + ?Sized>(&self, name: &Q) -> Option<Field>877 pub fn field<Q: Borrow<str> + ?Sized>(&self, name: &Q) -> Option<Field> {
878 let name = &name.borrow();
879 self.names.iter().position(|f| f == name).map(|i| Field {
880 i,
881 fields: FieldSet {
882 names: self.names,
883 callsite: self.callsite(),
884 },
885 })
886 }
887
888 /// Returns `true` if `self` contains the given `field`.
889 ///
890 /// <div class="example-wrap" style="display:inline-block">
891 /// <pre class="ignore" style="white-space:normal;font:inherit;">
892 /// <strong>Note</strong>: If <code>field</code> shares a name with a field
893 /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
894 /// with a different callsite, this <code>FieldSet</code> does <em>not</em>
895 /// contain it. This is so that if two separate span callsites define a field
896 /// named "foo", the <code>Field</code> corresponding to "foo" for each
897 /// of those callsites are not equivalent.
898 /// </pre></div>
contains(&self, field: &Field) -> bool899 pub fn contains(&self, field: &Field) -> bool {
900 field.callsite() == self.callsite() && field.i <= self.len()
901 }
902
903 /// Returns an iterator over the `Field`s in this `FieldSet`.
904 #[inline]
iter(&self) -> Iter905 pub fn iter(&self) -> Iter {
906 let idxs = 0..self.len();
907 Iter {
908 idxs,
909 fields: FieldSet {
910 names: self.names,
911 callsite: self.callsite(),
912 },
913 }
914 }
915
916 /// Returns a new `ValueSet` with entries for this `FieldSet`'s values.
917 #[doc(hidden)]
value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v> where V: ValidLen<'v>,918 pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v>
919 where
920 V: ValidLen<'v>,
921 {
922 ValueSet {
923 fields: self,
924 values: values.borrow(),
925 }
926 }
927
928 /// Returns the number of fields in this `FieldSet`.
929 #[inline]
len(&self) -> usize930 pub fn len(&self) -> usize {
931 self.names.len()
932 }
933
934 /// Returns whether or not this `FieldSet` has fields.
935 #[inline]
is_empty(&self) -> bool936 pub fn is_empty(&self) -> bool {
937 self.names.is_empty()
938 }
939 }
940
941 impl<'a> IntoIterator for &'a FieldSet {
942 type IntoIter = Iter;
943 type Item = Field;
944 #[inline]
into_iter(self) -> Self::IntoIter945 fn into_iter(self) -> Self::IntoIter {
946 self.iter()
947 }
948 }
949
950 impl fmt::Debug for FieldSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result951 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
952 f.debug_struct("FieldSet")
953 .field("names", &self.names)
954 .field("callsite", &self.callsite)
955 .finish()
956 }
957 }
958
959 impl fmt::Display for FieldSet {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result960 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
961 f.debug_set()
962 .entries(self.names.iter().map(display))
963 .finish()
964 }
965 }
966
967 impl Eq for FieldSet {}
968
969 impl PartialEq for FieldSet {
eq(&self, other: &Self) -> bool970 fn eq(&self, other: &Self) -> bool {
971 if core::ptr::eq(&self, &other) {
972 true
973 } else if cfg!(not(debug_assertions)) {
974 // In a well-behaving application, two `FieldSet`s can be assumed to
975 // be totally equal so long as they share the same callsite.
976 self.callsite == other.callsite
977 } else {
978 // However, when debug-assertions are enabled, do NOT assume that
979 // the application is well-behaving; check every the field names of
980 // each `FieldSet` for equality.
981
982 // `FieldSet` is destructured here to ensure a compile-error if the
983 // fields of `FieldSet` change.
984 let Self {
985 names: lhs_names,
986 callsite: lhs_callsite,
987 } = self;
988
989 let Self {
990 names: rhs_names,
991 callsite: rhs_callsite,
992 } = &other;
993
994 // Check callsite equality first, as it is probably cheaper to do
995 // than str equality.
996 lhs_callsite == rhs_callsite && lhs_names == rhs_names
997 }
998 }
999 }
1000
1001 // ===== impl Iter =====
1002
1003 impl Iterator for Iter {
1004 type Item = Field;
1005 #[inline]
next(&mut self) -> Option<Field>1006 fn next(&mut self) -> Option<Field> {
1007 let i = self.idxs.next()?;
1008 Some(Field {
1009 i,
1010 fields: FieldSet {
1011 names: self.fields.names,
1012 callsite: self.fields.callsite(),
1013 },
1014 })
1015 }
1016 }
1017
1018 // ===== impl ValueSet =====
1019
1020 impl<'a> ValueSet<'a> {
1021 /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
1022 /// defining the fields this `ValueSet` refers to.
1023 ///
1024 /// [`Identifier`]: super::callsite::Identifier
1025 /// [`Callsite`]: super::callsite::Callsite
1026 #[inline]
callsite(&self) -> callsite::Identifier1027 pub fn callsite(&self) -> callsite::Identifier {
1028 self.fields.callsite()
1029 }
1030
1031 /// Visits all the fields in this `ValueSet` with the provided [visitor].
1032 ///
1033 /// [visitor]: Visit
record(&self, visitor: &mut dyn Visit)1034 pub fn record(&self, visitor: &mut dyn Visit) {
1035 let my_callsite = self.callsite();
1036 for (field, value) in self.values {
1037 if field.callsite() != my_callsite {
1038 continue;
1039 }
1040 if let Some(value) = value {
1041 value.record(field, visitor);
1042 }
1043 }
1044 }
1045
1046 /// Returns the number of fields in this `ValueSet` that would be visited
1047 /// by a given [visitor] to the [`ValueSet::record()`] method.
1048 ///
1049 /// [visitor]: Visit
1050 /// [`ValueSet::record()`]: ValueSet::record()
len(&self) -> usize1051 pub fn len(&self) -> usize {
1052 let my_callsite = self.callsite();
1053 self.values
1054 .iter()
1055 .filter(|(field, _)| field.callsite() == my_callsite)
1056 .count()
1057 }
1058
1059 /// Returns `true` if this `ValueSet` contains a value for the given `Field`.
contains(&self, field: &Field) -> bool1060 pub(crate) fn contains(&self, field: &Field) -> bool {
1061 field.callsite() == self.callsite()
1062 && self
1063 .values
1064 .iter()
1065 .any(|(key, val)| *key == field && val.is_some())
1066 }
1067
1068 /// Returns true if this `ValueSet` contains _no_ values.
is_empty(&self) -> bool1069 pub fn is_empty(&self) -> bool {
1070 let my_callsite = self.callsite();
1071 self.values
1072 .iter()
1073 .all(|(key, val)| val.is_none() || key.callsite() != my_callsite)
1074 }
1075
field_set(&self) -> &FieldSet1076 pub(crate) fn field_set(&self) -> &FieldSet {
1077 self.fields
1078 }
1079 }
1080
1081 impl<'a> fmt::Debug for ValueSet<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1082 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1083 self.values
1084 .iter()
1085 .fold(&mut f.debug_struct("ValueSet"), |dbg, (key, v)| {
1086 if let Some(val) = v {
1087 val.record(key, dbg);
1088 }
1089 dbg
1090 })
1091 .field("callsite", &self.callsite())
1092 .finish()
1093 }
1094 }
1095
1096 impl<'a> fmt::Display for ValueSet<'a> {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result1097 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1098 self.values
1099 .iter()
1100 .fold(&mut f.debug_map(), |dbg, (key, v)| {
1101 if let Some(val) = v {
1102 val.record(key, dbg);
1103 }
1104 dbg
1105 })
1106 .finish()
1107 }
1108 }
1109
1110 // ===== impl ValidLen =====
1111
1112 mod private {
1113 use super::*;
1114
1115 /// Restrictions on `ValueSet` lengths were removed in #2508 but this type remains for backwards compatibility.
1116 pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {}
1117
1118 impl<'a, const N: usize> ValidLen<'a> for [(&'a Field, Option<&'a (dyn Value + 'a)>); N] {}
1119 }
1120
1121 #[cfg(test)]
1122 mod test {
1123 use super::*;
1124 use crate::metadata::{Kind, Level, Metadata};
1125 use crate::stdlib::{borrow::ToOwned, string::String};
1126
1127 // Make sure TEST_CALLSITE_* have non-zero size, so they can't be located at the same address.
1128 struct TestCallsite1();
1129 static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1();
1130 static TEST_META_1: Metadata<'static> = metadata! {
1131 name: "field_test1",
1132 target: module_path!(),
1133 level: Level::INFO,
1134 fields: &["foo", "bar", "baz"],
1135 callsite: &TEST_CALLSITE_1,
1136 kind: Kind::SPAN,
1137 };
1138
1139 impl crate::callsite::Callsite for TestCallsite1 {
set_interest(&self, _: crate::subscriber::Interest)1140 fn set_interest(&self, _: crate::subscriber::Interest) {
1141 unimplemented!()
1142 }
1143
metadata(&self) -> &Metadata<'_>1144 fn metadata(&self) -> &Metadata<'_> {
1145 &TEST_META_1
1146 }
1147 }
1148
1149 struct TestCallsite2();
1150 static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2();
1151 static TEST_META_2: Metadata<'static> = metadata! {
1152 name: "field_test2",
1153 target: module_path!(),
1154 level: Level::INFO,
1155 fields: &["foo", "bar", "baz"],
1156 callsite: &TEST_CALLSITE_2,
1157 kind: Kind::SPAN,
1158 };
1159
1160 impl crate::callsite::Callsite for TestCallsite2 {
set_interest(&self, _: crate::subscriber::Interest)1161 fn set_interest(&self, _: crate::subscriber::Interest) {
1162 unimplemented!()
1163 }
1164
metadata(&self) -> &Metadata<'_>1165 fn metadata(&self) -> &Metadata<'_> {
1166 &TEST_META_2
1167 }
1168 }
1169
1170 #[test]
value_set_with_no_values_is_empty()1171 fn value_set_with_no_values_is_empty() {
1172 let fields = TEST_META_1.fields();
1173 let values = &[
1174 (&fields.field("foo").unwrap(), None),
1175 (&fields.field("bar").unwrap(), None),
1176 (&fields.field("baz").unwrap(), None),
1177 ];
1178 let valueset = fields.value_set(values);
1179 assert!(valueset.is_empty());
1180 }
1181
1182 #[test]
index_of_field_in_fieldset_is_correct()1183 fn index_of_field_in_fieldset_is_correct() {
1184 let fields = TEST_META_1.fields();
1185 let foo = fields.field("foo").unwrap();
1186 assert_eq!(foo.index(), 0);
1187 let bar = fields.field("bar").unwrap();
1188 assert_eq!(bar.index(), 1);
1189 let baz = fields.field("baz").unwrap();
1190 assert_eq!(baz.index(), 2);
1191 }
1192
1193 #[test]
empty_value_set_is_empty()1194 fn empty_value_set_is_empty() {
1195 let fields = TEST_META_1.fields();
1196 let valueset = fields.value_set(&[]);
1197 assert!(valueset.is_empty());
1198 }
1199
1200 #[test]
value_sets_with_fields_from_other_callsites_are_empty()1201 fn value_sets_with_fields_from_other_callsites_are_empty() {
1202 let fields = TEST_META_1.fields();
1203 let values = &[
1204 (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
1205 (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
1206 (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
1207 ];
1208 let valueset = TEST_META_2.fields().value_set(values);
1209 assert!(valueset.is_empty())
1210 }
1211
1212 #[test]
sparse_value_sets_are_not_empty()1213 fn sparse_value_sets_are_not_empty() {
1214 let fields = TEST_META_1.fields();
1215 let values = &[
1216 (&fields.field("foo").unwrap(), None),
1217 (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
1218 (&fields.field("baz").unwrap(), None),
1219 ];
1220 let valueset = fields.value_set(values);
1221 assert!(!valueset.is_empty());
1222 }
1223
1224 #[test]
fields_from_other_callsets_are_skipped()1225 fn fields_from_other_callsets_are_skipped() {
1226 let fields = TEST_META_1.fields();
1227 let values = &[
1228 (&fields.field("foo").unwrap(), None),
1229 (
1230 &TEST_META_2.fields().field("bar").unwrap(),
1231 Some(&57 as &dyn Value),
1232 ),
1233 (&fields.field("baz").unwrap(), None),
1234 ];
1235
1236 struct MyVisitor;
1237 impl Visit for MyVisitor {
1238 fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
1239 assert_eq!(field.callsite(), TEST_META_1.callsite())
1240 }
1241 }
1242 let valueset = fields.value_set(values);
1243 valueset.record(&mut MyVisitor);
1244 }
1245
1246 #[test]
empty_fields_are_skipped()1247 fn empty_fields_are_skipped() {
1248 let fields = TEST_META_1.fields();
1249 let values = &[
1250 (&fields.field("foo").unwrap(), Some(&Empty as &dyn Value)),
1251 (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
1252 (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
1253 ];
1254
1255 struct MyVisitor;
1256 impl Visit for MyVisitor {
1257 fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
1258 assert_eq!(field.name(), "bar")
1259 }
1260 }
1261 let valueset = fields.value_set(values);
1262 valueset.record(&mut MyVisitor);
1263 }
1264
1265 #[test]
record_debug_fn()1266 fn record_debug_fn() {
1267 let fields = TEST_META_1.fields();
1268 let values = &[
1269 (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
1270 (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
1271 (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
1272 ];
1273 let valueset = fields.value_set(values);
1274 let mut result = String::new();
1275 valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
1276 use crate::stdlib::fmt::Write;
1277 write!(&mut result, "{:?}", value).unwrap();
1278 });
1279 assert_eq!(result, "123".to_owned());
1280 }
1281
1282 #[test]
1283 #[cfg(feature = "std")]
record_error()1284 fn record_error() {
1285 let fields = TEST_META_1.fields();
1286 let err: Box<dyn std::error::Error + Send + Sync + 'static> =
1287 std::io::Error::new(std::io::ErrorKind::Other, "lol").into();
1288 let values = &[
1289 (&fields.field("foo").unwrap(), Some(&err as &dyn Value)),
1290 (&fields.field("bar").unwrap(), Some(&Empty as &dyn Value)),
1291 (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
1292 ];
1293 let valueset = fields.value_set(values);
1294 let mut result = String::new();
1295 valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
1296 use core::fmt::Write;
1297 write!(&mut result, "{:?}", value).unwrap();
1298 });
1299 assert_eq!(result, format!("{}", err));
1300 }
1301
1302 #[test]
record_bytes()1303 fn record_bytes() {
1304 let fields = TEST_META_1.fields();
1305 let first = &b"abc"[..];
1306 let second: &[u8] = &[192, 255, 238];
1307 let values = &[
1308 (&fields.field("foo").unwrap(), Some(&first as &dyn Value)),
1309 (&fields.field("bar").unwrap(), Some(&" " as &dyn Value)),
1310 (&fields.field("baz").unwrap(), Some(&second as &dyn Value)),
1311 ];
1312 let valueset = fields.value_set(values);
1313 let mut result = String::new();
1314 valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
1315 use core::fmt::Write;
1316 write!(&mut result, "{:?}", value).unwrap();
1317 });
1318 assert_eq!(result, format!("{}", r#"[61 62 63]" "[c0 ff ee]"#));
1319 }
1320 }
1321