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