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