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