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: &&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 | |