summaryrefslogtreecommitdiffstats
path: root/vendor/tracing-core/src/field.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 12:02:58 +0000
commit698f8c2f01ea549d77d7dc3338a12e04c11057b9 (patch)
tree173a775858bd501c378080a10dca74132f05bc50 /vendor/tracing-core/src/field.rs
parentInitial commit. (diff)
downloadrustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.tar.xz
rustc-698f8c2f01ea549d77d7dc3338a12e04c11057b9.zip
Adding upstream version 1.64.0+dfsg1.upstream/1.64.0+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--vendor/tracing-core/src/field.rs1219
1 files changed, 1219 insertions, 0 deletions
diff --git a/vendor/tracing-core/src/field.rs b/vendor/tracing-core/src/field.rs
new file mode 100644
index 000000000..c9869ce2c
--- /dev/null
+++ b/vendor/tracing-core/src/field.rs
@@ -0,0 +1,1219 @@
+//! `Span` and `Event` key-value data.
+//!
+//! Spans and events may be annotated with key-value data, referred to as known
+//! as _fields_. These fields consist of a mapping from a key (corresponding to
+//! a `&str` but represented internally as an array index) to a [`Value`].
+//!
+//! # `Value`s and `Subscriber`s
+//!
+//! `Subscriber`s consume `Value`s as fields attached to [span]s or [`Event`]s.
+//! The set of field keys on a given span or is defined on its [`Metadata`].
+//! When a span is created, it provides [`Attributes`] to the `Subscriber`'s
+//! [`new_span`] method, containing any fields whose values were provided when
+//! the span was created; and may call the `Subscriber`'s [`record`] method
+//! with additional [`Record`]s if values are added for more of its fields.
+//! Similarly, the [`Event`] type passed to the subscriber's [`event`] method
+//! will contain any fields attached to each event.
+//!
+//! `tracing` represents values as either one of a set of Rust primitives
+//! (`i64`, `u64`, `f64`, `i128`, `u128`, `bool`, and `&str`) or using a
+//! `fmt::Display` or `fmt::Debug` implementation. `Subscriber`s are provided
+//! these primitive value types as `dyn Value` trait objects.
+//!
+//! These trait objects can be formatted using `fmt::Debug`, but may also be
+//! recorded as typed data by calling the [`Value::record`] method on these
+//! trait objects with a _visitor_ implementing the [`Visit`] trait. This trait
+//! represents the behavior used to record values of various types. For example,
+//! an implementation of `Visit` might record integers by incrementing counters
+//! for their field names rather than printing them.
+//!
+//!
+//! # Using `valuable`
+//!
+//! `tracing`'s [`Value`] trait is intentionally minimalist: it supports only a small
+//! number of Rust primitives as typed values, and only permits recording
+//! user-defined types with their [`fmt::Debug`] or [`fmt::Display`]
+//! implementations. However, there are some cases where it may be useful to record
+//! nested values (such as arrays, `Vec`s, or `HashMap`s containing values), or
+//! user-defined `struct` and `enum` types without having to format them as
+//! unstructured text.
+//!
+//! To address `Value`'s limitations, `tracing` offers experimental support for
+//! the [`valuable`] crate, which provides object-safe inspection of structured
+//! values. User-defined types can implement the [`valuable::Valuable`] trait,
+//! and be recorded as a `tracing` field by calling their [`as_value`] method.
+//! If the [`Subscriber`] also supports the `valuable` crate, it can
+//! then visit those types fields as structured values using `valuable`.
+//!
+//! <pre class="ignore" style="white-space:normal;font:inherit;">
+//! <strong>Note</strong>: <code>valuable</code> support is an
+//! <a href = "../index.html#unstable-features">unstable feature</a>. See
+//! the documentation on unstable features for details on how to enable it.
+//! </pre>
+//!
+//! For example:
+//! ```ignore
+//! // Derive `Valuable` for our types:
+//! use valuable::Valuable;
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct User {
+//! name: String,
+//! age: u32,
+//! address: Address,
+//! }
+//!
+//! #[derive(Clone, Debug, Valuable)]
+//! struct Address {
+//! country: String,
+//! city: String,
+//! street: String,
+//! }
+//!
+//! let user = User {
+//! name: "Arwen Undomiel".to_string(),
+//! age: 3000,
+//! address: Address {
+//! country: "Middle Earth".to_string(),
+//! city: "Rivendell".to_string(),
+//! street: "leafy lane".to_string(),
+//! },
+//! };
+//!
+//! // Recording `user` as a `valuable::Value` will allow the `tracing` subscriber
+//! // to traverse its fields as a nested, typed structure:
+//! tracing::info!(current_user = user.as_value());
+//! ```
+//!
+//! Alternatively, the [`valuable()`] function may be used to convert a type
+//! implementing [`Valuable`] into a `tracing` field value.
+//!
+//! When the `valuable` feature is enabled, the [`Visit`] trait will include an
+//! optional [`record_value`] method. `Visit` implementations that wish to
+//! record `valuable` values can implement this method with custom behavior.
+//! If a visitor does not implement `record_value`, the [`valuable::Value`] will
+//! be forwarded to the visitor's [`record_debug`] method.
+//!
+//! [`valuable`]: https://crates.io/crates/valuable
+//! [`as_value`]: valuable::Valuable::as_value
+//! [`Subscriber`]: crate::Subscriber
+//! [`record_value`]: Visit::record_value
+//! [`record_debug`]: Visit::record_debug
+//!
+//! [span]: super::span
+//! [`Event`]: super::event::Event
+//! [`Metadata`]: super::metadata::Metadata
+//! [`Attributes`]: super::span::Attributes
+//! [`Record`]: super::span::Record
+//! [`new_span`]: super::subscriber::Subscriber::new_span
+//! [`record`]: super::subscriber::Subscriber::record
+//! [`event`]: super::subscriber::Subscriber::event
+//! [`Value::record`]: Value::record
+use crate::callsite;
+use crate::stdlib::{
+ borrow::Borrow,
+ fmt,
+ hash::{Hash, Hasher},
+ num,
+ ops::Range,
+ string::String,
+};
+
+use self::private::ValidLen;
+
+/// An opaque key allowing _O_(1) access to a field in a `Span`'s key-value
+/// data.
+///
+/// As keys are defined by the _metadata_ of a span, rather than by an
+/// individual instance of a span, a key may be used to access the same field
+/// across all instances of a given span with the same metadata. Thus, when a
+/// subscriber observes a new span, it need only access a field by name _once_,
+/// and use the key for that name for all other accesses.
+#[derive(Debug)]
+pub struct Field {
+ i: usize,
+ fields: FieldSet,
+}
+
+/// An empty field.
+///
+/// This can be used to indicate that the value of a field is not currently
+/// present but will be recorded later.
+///
+/// When a field's value is `Empty`. it will not be recorded.
+#[derive(Debug, Eq, PartialEq)]
+pub struct Empty;
+
+/// Describes the fields present on a span.
+pub struct FieldSet {
+ /// The names of each field on the described span.
+ names: &'static [&'static str],
+ /// The callsite where the described span originates.
+ callsite: callsite::Identifier,
+}
+
+/// A set of fields and values for a span.
+pub struct ValueSet<'a> {
+ values: &'a [(&'a Field, Option<&'a (dyn Value + 'a)>)],
+ fields: &'a FieldSet,
+}
+
+/// An iterator over a set of fields.
+#[derive(Debug)]
+pub struct Iter {
+ idxs: Range<usize>,
+ fields: FieldSet,
+}
+
+/// Visits typed values.
+///
+/// An instance of `Visit` ("a visitor") represents the logic necessary to
+/// record field values of various types. When an implementor of [`Value`] is
+/// [recorded], it calls the appropriate method on the provided visitor to
+/// indicate the type that value should be recorded as.
+///
+/// When a [`Subscriber`] implementation [records an `Event`] or a
+/// [set of `Value`s added to a `Span`], it can pass an `&mut Visit` to the
+/// `record` method on the provided [`ValueSet`] or [`Event`]. This visitor
+/// will then be used to record all the field-value pairs present on that
+/// `Event` or `ValueSet`.
+///
+/// # Examples
+///
+/// A simple visitor that writes to a string might be implemented like so:
+/// ```
+/// # extern crate tracing_core as tracing;
+/// use std::fmt::{self, Write};
+/// use tracing::field::{Value, Visit, Field};
+/// pub struct StringVisitor<'a> {
+/// string: &'a mut String,
+/// }
+///
+/// impl<'a> Visit for StringVisitor<'a> {
+/// fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+/// write!(self.string, "{} = {:?}; ", field.name(), value).unwrap();
+/// }
+/// }
+/// ```
+/// This visitor will format each recorded value using `fmt::Debug`, and
+/// append the field name and formatted value to the provided string,
+/// regardless of the type of the recorded value. When all the values have
+/// been recorded, the `StringVisitor` may be dropped, allowing the string
+/// to be printed or stored in some other data structure.
+///
+/// The `Visit` trait provides default implementations for `record_i64`,
+/// `record_u64`, `record_bool`, `record_str`, and `record_error`, which simply
+/// forward the recorded value to `record_debug`. Thus, `record_debug` is the
+/// only method which a `Visit` implementation *must* implement. However,
+/// visitors may override the default implementations of these functions in
+/// order to implement type-specific behavior.
+///
+/// Additionally, when a visitor receives a value of a type it does not care
+/// about, it is free to ignore those values completely. For example, a
+/// visitor which only records numeric data might look like this:
+///
+/// ```
+/// # extern crate tracing_core as tracing;
+/// # use std::fmt::{self, Write};
+/// # use tracing::field::{Value, Visit, Field};
+/// pub struct SumVisitor {
+/// sum: i64,
+/// }
+///
+/// impl Visit for SumVisitor {
+/// fn record_i64(&mut self, _field: &Field, value: i64) {
+/// self.sum += value;
+/// }
+///
+/// fn record_u64(&mut self, _field: &Field, value: u64) {
+/// self.sum += value as i64;
+/// }
+///
+/// fn record_debug(&mut self, _field: &Field, _value: &fmt::Debug) {
+/// // Do nothing
+/// }
+/// }
+/// ```
+///
+/// This visitor (which is probably not particularly useful) keeps a running
+/// sum of all the numeric values it records, and ignores all other values. A
+/// more practical example of recording typed values is presented in
+/// `examples/counters.rs`, which demonstrates a very simple metrics system
+/// implemented using `tracing`.
+///
+/// <div class="example-wrap" style="display:inline-block">
+/// <pre class="ignore" style="white-space:normal;font:inherit;">
+/// <strong>Note</strong>: The <code>record_error</code> trait method is only
+/// available when the Rust standard library is present, as it requires the
+/// <code>std::error::Error</code> trait.
+/// </pre></div>
+///
+/// [recorded]: Value::record
+/// [`Subscriber`]: super::subscriber::Subscriber
+/// [records an `Event`]: super::subscriber::Subscriber::event
+/// [set of `Value`s added to a `Span`]: super::subscriber::Subscriber::record
+/// [`Event`]: super::event::Event
+pub trait Visit {
+ /// Visits an arbitrary type implementing the [`valuable`] crate's `Valuable` trait.
+ ///
+ /// [`valuable`]: https://docs.rs/valuable
+ #[cfg(all(tracing_unstable, feature = "valuable"))]
+ #[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+ fn record_value(&mut self, field: &Field, value: valuable::Value<'_>) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a double-precision floating point value.
+ fn record_f64(&mut self, field: &Field, value: f64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a signed 64-bit integer value.
+ fn record_i64(&mut self, field: &Field, value: i64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit an unsigned 64-bit integer value.
+ fn record_u64(&mut self, field: &Field, value: u64) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a signed 128-bit integer value.
+ fn record_i128(&mut self, field: &Field, value: i128) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit an unsigned 128-bit integer value.
+ fn record_u128(&mut self, field: &Field, value: u128) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a boolean value.
+ fn record_bool(&mut self, field: &Field, value: bool) {
+ self.record_debug(field, &value)
+ }
+
+ /// Visit a string value.
+ fn record_str(&mut self, field: &Field, value: &str) {
+ self.record_debug(field, &value)
+ }
+
+ /// Records a type implementing `Error`.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: This is only enabled when the Rust standard library is
+ /// present.
+ /// </pre>
+ #[cfg(feature = "std")]
+ #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+ fn record_error(&mut self, field: &Field, value: &(dyn std::error::Error + 'static)) {
+ self.record_debug(field, &DisplayValue(value))
+ }
+
+ /// Visit a value implementing `fmt::Debug`.
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug);
+}
+
+/// A field value of an erased type.
+///
+/// Implementors of `Value` may call the appropriate typed recording methods on
+/// the [visitor] passed to their `record` method in order to indicate how
+/// their data should be recorded.
+///
+/// [visitor]: Visit
+pub trait Value: crate::sealed::Sealed {
+ /// Visits this value with the given `Visitor`.
+ fn record(&self, key: &Field, visitor: &mut dyn Visit);
+}
+
+/// A `Value` which serializes using `fmt::Display`.
+///
+/// Uses `record_debug` in the `Value` implementation to
+/// avoid an unnecessary evaluation.
+#[derive(Clone)]
+pub struct DisplayValue<T: fmt::Display>(T);
+
+/// A `Value` which serializes as a string using `fmt::Debug`.
+#[derive(Clone)]
+pub struct DebugValue<T: fmt::Debug>(T);
+
+/// Wraps a type implementing `fmt::Display` as a `Value` that can be
+/// recorded using its `Display` implementation.
+pub fn display<T>(t: T) -> DisplayValue<T>
+where
+ T: fmt::Display,
+{
+ DisplayValue(t)
+}
+
+/// Wraps a type implementing `fmt::Debug` as a `Value` that can be
+/// recorded using its `Debug` implementation.
+pub fn debug<T>(t: T) -> DebugValue<T>
+where
+ T: fmt::Debug,
+{
+ DebugValue(t)
+}
+
+/// Wraps a type implementing [`Valuable`] as a `Value` that
+/// can be recorded using its `Valuable` implementation.
+///
+/// [`Valuable`]: https://docs.rs/valuable/latest/valuable/trait.Valuable.html
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+pub fn valuable<T>(t: &T) -> valuable::Value<'_>
+where
+ T: valuable::Valuable,
+{
+ t.as_value()
+}
+
+// ===== impl Visit =====
+
+impl<'a, 'b> Visit for fmt::DebugStruct<'a, 'b> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.field(field.name(), value);
+ }
+}
+
+impl<'a, 'b> Visit for fmt::DebugMap<'a, 'b> {
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ self.entry(&format_args!("{}", field), value);
+ }
+}
+
+impl<F> Visit for F
+where
+ F: FnMut(&Field, &dyn fmt::Debug),
+{
+ fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
+ (self)(field, value)
+ }
+}
+
+// ===== impl Value =====
+
+macro_rules! impl_values {
+ ( $( $record:ident( $( $whatever:tt)+ ) ),+ ) => {
+ $(
+ impl_value!{ $record( $( $whatever )+ ) }
+ )+
+ }
+}
+
+macro_rules! ty_to_nonzero {
+ (u8) => {
+ NonZeroU8
+ };
+ (u16) => {
+ NonZeroU16
+ };
+ (u32) => {
+ NonZeroU32
+ };
+ (u64) => {
+ NonZeroU64
+ };
+ (u128) => {
+ NonZeroU128
+ };
+ (usize) => {
+ NonZeroUsize
+ };
+ (i8) => {
+ NonZeroI8
+ };
+ (i16) => {
+ NonZeroI16
+ };
+ (i32) => {
+ NonZeroI32
+ };
+ (i64) => {
+ NonZeroI64
+ };
+ (i128) => {
+ NonZeroI128
+ };
+ (isize) => {
+ NonZeroIsize
+ };
+}
+
+macro_rules! impl_one_value {
+ (f32, $op:expr, $record:ident) => {
+ impl_one_value!(normal, f32, $op, $record);
+ };
+ (f64, $op:expr, $record:ident) => {
+ impl_one_value!(normal, f64, $op, $record);
+ };
+ (bool, $op:expr, $record:ident) => {
+ impl_one_value!(normal, bool, $op, $record);
+ };
+ ($value_ty:tt, $op:expr, $record:ident) => {
+ impl_one_value!(normal, $value_ty, $op, $record);
+ impl_one_value!(nonzero, $value_ty, $op, $record);
+ };
+ (normal, $value_ty:tt, $op:expr, $record:ident) => {
+ impl $crate::sealed::Sealed for $value_ty {}
+ impl $crate::field::Value for $value_ty {
+ fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
+ visitor.$record(key, $op(*self))
+ }
+ }
+ };
+ (nonzero, $value_ty:tt, $op:expr, $record:ident) => {
+ // This `use num::*;` is reported as unused because it gets emitted
+ // for every single invocation of this macro, so there are multiple `use`s.
+ // All but the first are useless indeed.
+ // We need this import because we can't write a path where one part is
+ // the `ty_to_nonzero!($value_ty)` invocation.
+ #[allow(clippy::useless_attribute, unused)]
+ use num::*;
+ impl $crate::sealed::Sealed for ty_to_nonzero!($value_ty) {}
+ impl $crate::field::Value for ty_to_nonzero!($value_ty) {
+ fn record(&self, key: &$crate::field::Field, visitor: &mut dyn $crate::field::Visit) {
+ visitor.$record(key, $op(self.get()))
+ }
+ }
+ };
+}
+
+macro_rules! impl_value {
+ ( $record:ident( $( $value_ty:tt ),+ ) ) => {
+ $(
+ impl_one_value!($value_ty, |this: $value_ty| this, $record);
+ )+
+ };
+ ( $record:ident( $( $value_ty:tt ),+ as $as_ty:ty) ) => {
+ $(
+ impl_one_value!($value_ty, |this: $value_ty| this as $as_ty, $record);
+ )+
+ };
+}
+
+// ===== impl Value =====
+
+impl_values! {
+ record_u64(u64),
+ record_u64(usize, u32, u16, u8 as u64),
+ record_i64(i64),
+ record_i64(isize, i32, i16, i8 as i64),
+ record_u128(u128),
+ record_i128(i128),
+ record_bool(bool),
+ record_f64(f64, f32 as f64)
+}
+
+impl<T: crate::sealed::Sealed> crate::sealed::Sealed for Wrapping<T> {}
+impl<T: crate::field::Value> crate::field::Value for Wrapping<T> {
+ fn record(&self, key: &crate::field::Field, visitor: &mut dyn crate::field::Visit) {
+ self.0.record(key, visitor)
+ }
+}
+
+impl crate::sealed::Sealed for str {}
+
+impl Value for str {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_str(key, self)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_error(key, self)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Send + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Send + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Sync + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Sync + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+#[cfg(feature = "std")]
+impl crate::sealed::Sealed for dyn std::error::Error + Send + Sync + 'static {}
+
+#[cfg(feature = "std")]
+#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
+impl Value for dyn std::error::Error + Send + Sync + 'static {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (self as &dyn std::error::Error).record(key, visitor)
+ }
+}
+
+impl<'a, T: ?Sized> crate::sealed::Sealed for &'a T where T: Value + crate::sealed::Sealed + 'a {}
+
+impl<'a, T: ?Sized> Value for &'a T
+where
+ T: Value + 'a,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ (*self).record(key, visitor)
+ }
+}
+
+impl<'a, T: ?Sized> crate::sealed::Sealed for &'a mut T where T: Value + crate::sealed::Sealed + 'a {}
+
+impl<'a, T: ?Sized> Value for &'a mut T
+where
+ T: Value + 'a,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ // Don't use `(*self).record(key, visitor)`, otherwise would
+ // cause stack overflow due to `unconditional_recursion`.
+ T::record(self, key, visitor)
+ }
+}
+
+impl<'a> crate::sealed::Sealed for fmt::Arguments<'a> {}
+
+impl<'a> Value for fmt::Arguments<'a> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, self)
+ }
+}
+
+impl<T: ?Sized> crate::sealed::Sealed for crate::stdlib::boxed::Box<T> where T: Value {}
+
+impl<T: ?Sized> Value for crate::stdlib::boxed::Box<T>
+where
+ T: Value,
+{
+ #[inline]
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ self.as_ref().record(key, visitor)
+ }
+}
+
+impl crate::sealed::Sealed for String {}
+impl Value for String {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_str(key, self.as_str())
+ }
+}
+
+impl fmt::Debug for dyn Value {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // We are only going to be recording the field value, so we don't
+ // actually care about the field name here.
+ struct NullCallsite;
+ static NULL_CALLSITE: NullCallsite = NullCallsite;
+ impl crate::callsite::Callsite for NullCallsite {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unreachable!("you somehow managed to register the null callsite?")
+ }
+
+ fn metadata(&self) -> &crate::Metadata<'_> {
+ unreachable!("you somehow managed to access the null callsite?")
+ }
+ }
+
+ static FIELD: Field = Field {
+ i: 0,
+ fields: FieldSet::new(&[], crate::identify_callsite!(&NULL_CALLSITE)),
+ };
+
+ let mut res = Ok(());
+ self.record(&FIELD, &mut |_: &Field, val: &dyn fmt::Debug| {
+ res = write!(f, "{:?}", val);
+ });
+ res
+ }
+}
+
+impl fmt::Display for dyn Value {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(self, f)
+ }
+}
+
+// ===== impl DisplayValue =====
+
+impl<T: fmt::Display> crate::sealed::Sealed for DisplayValue<T> {}
+
+impl<T> Value for DisplayValue<T>
+where
+ T: fmt::Display,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, self)
+ }
+}
+
+impl<T: fmt::Display> fmt::Debug for DisplayValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(self, f)
+ }
+}
+
+impl<T: fmt::Display> fmt::Display for DisplayValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+// ===== impl DebugValue =====
+
+impl<T: fmt::Debug> crate::sealed::Sealed for DebugValue<T> {}
+
+impl<T> Value for DebugValue<T>
+where
+ T: fmt::Debug,
+{
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_debug(key, &self.0)
+ }
+}
+
+impl<T: fmt::Debug> fmt::Debug for DebugValue<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+// ===== impl ValuableValue =====
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+impl crate::sealed::Sealed for valuable::Value<'_> {}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+impl Value for valuable::Value<'_> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_value(key, *self)
+ }
+}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+impl crate::sealed::Sealed for &'_ dyn valuable::Valuable {}
+
+#[cfg(all(tracing_unstable, feature = "valuable"))]
+#[cfg_attr(docsrs, doc(cfg(all(tracing_unstable, feature = "valuable"))))]
+impl Value for &'_ dyn valuable::Valuable {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ visitor.record_value(key, self.as_value())
+ }
+}
+
+impl crate::sealed::Sealed for Empty {}
+impl Value for Empty {
+ #[inline]
+ fn record(&self, _: &Field, _: &mut dyn Visit) {}
+}
+
+impl<T: Value> crate::sealed::Sealed for Option<T> {}
+
+impl<T: Value> Value for Option<T> {
+ fn record(&self, key: &Field, visitor: &mut dyn Visit) {
+ if let Some(v) = &self {
+ v.record(key, visitor)
+ }
+ }
+}
+
+// ===== impl Field =====
+
+impl Field {
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// which defines this field.
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ #[inline]
+ pub fn callsite(&self) -> callsite::Identifier {
+ self.fields.callsite()
+ }
+
+ /// Returns a string representing the name of the field.
+ pub fn name(&self) -> &'static str {
+ self.fields.names[self.i]
+ }
+}
+
+impl fmt::Display for Field {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.pad(self.name())
+ }
+}
+
+impl AsRef<str> for Field {
+ fn as_ref(&self) -> &str {
+ self.name()
+ }
+}
+
+impl PartialEq for Field {
+ fn eq(&self, other: &Self) -> bool {
+ self.callsite() == other.callsite() && self.i == other.i
+ }
+}
+
+impl Eq for Field {}
+
+impl Hash for Field {
+ fn hash<H>(&self, state: &mut H)
+ where
+ H: Hasher,
+ {
+ self.callsite().hash(state);
+ self.i.hash(state);
+ }
+}
+
+impl Clone for Field {
+ fn clone(&self) -> Self {
+ Field {
+ i: self.i,
+ fields: FieldSet {
+ names: self.fields.names,
+ callsite: self.fields.callsite(),
+ },
+ }
+ }
+}
+
+// ===== impl FieldSet =====
+
+impl FieldSet {
+ /// Constructs a new `FieldSet` with the given array of field names and callsite.
+ pub const fn new(names: &'static [&'static str], callsite: callsite::Identifier) -> Self {
+ Self { names, callsite }
+ }
+
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// which defines this set of fields..
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ pub(crate) fn callsite(&self) -> callsite::Identifier {
+ callsite::Identifier(self.callsite.0)
+ }
+
+ /// Returns the [`Field`] named `name`, or `None` if no such field exists.
+ ///
+ /// [`Field`]: super::Field
+ pub fn field<Q: ?Sized>(&self, name: &Q) -> Option<Field>
+ where
+ Q: Borrow<str>,
+ {
+ let name = &name.borrow();
+ self.names.iter().position(|f| f == name).map(|i| Field {
+ i,
+ fields: FieldSet {
+ names: self.names,
+ callsite: self.callsite(),
+ },
+ })
+ }
+
+ /// Returns `true` if `self` contains the given `field`.
+ ///
+ /// <div class="example-wrap" style="display:inline-block">
+ /// <pre class="ignore" style="white-space:normal;font:inherit;">
+ /// <strong>Note</strong>: If <code>field</code> shares a name with a field
+ /// in this <code>FieldSet</code>, but was created by a <code>FieldSet</code>
+ /// with a different callsite, this <code>FieldSet</code> does <em>not</em>
+ /// contain it. This is so that if two separate span callsites define a field
+ /// named "foo", the <code>Field</code> corresponding to "foo" for each
+ /// of those callsites are not equivalent.
+ /// </pre></div>
+ pub fn contains(&self, field: &Field) -> bool {
+ field.callsite() == self.callsite() && field.i <= self.len()
+ }
+
+ /// Returns an iterator over the `Field`s in this `FieldSet`.
+ pub fn iter(&self) -> Iter {
+ let idxs = 0..self.len();
+ Iter {
+ idxs,
+ fields: FieldSet {
+ names: self.names,
+ callsite: self.callsite(),
+ },
+ }
+ }
+
+ /// Returns a new `ValueSet` with entries for this `FieldSet`'s values.
+ ///
+ /// Note that a `ValueSet` may not be constructed with arrays of over 32
+ /// elements.
+ #[doc(hidden)]
+ pub fn value_set<'v, V>(&'v self, values: &'v V) -> ValueSet<'v>
+ where
+ V: ValidLen<'v>,
+ {
+ ValueSet {
+ fields: self,
+ values: values.borrow(),
+ }
+ }
+
+ /// Returns the number of fields in this `FieldSet`.
+ #[inline]
+ pub fn len(&self) -> usize {
+ self.names.len()
+ }
+
+ /// Returns whether or not this `FieldSet` has fields.
+ #[inline]
+ pub fn is_empty(&self) -> bool {
+ self.names.is_empty()
+ }
+}
+
+impl<'a> IntoIterator for &'a FieldSet {
+ type IntoIter = Iter;
+ type Item = Field;
+ #[inline]
+ fn into_iter(self) -> Self::IntoIter {
+ self.iter()
+ }
+}
+
+impl fmt::Debug for FieldSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("FieldSet")
+ .field("names", &self.names)
+ .field("callsite", &self.callsite)
+ .finish()
+ }
+}
+
+impl fmt::Display for FieldSet {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_set()
+ .entries(self.names.iter().map(display))
+ .finish()
+ }
+}
+
+// ===== impl Iter =====
+
+impl Iterator for Iter {
+ type Item = Field;
+ fn next(&mut self) -> Option<Field> {
+ let i = self.idxs.next()?;
+ Some(Field {
+ i,
+ fields: FieldSet {
+ names: self.fields.names,
+ callsite: self.fields.callsite(),
+ },
+ })
+ }
+}
+
+// ===== impl ValueSet =====
+
+impl<'a> ValueSet<'a> {
+ /// Returns an [`Identifier`] that uniquely identifies the [`Callsite`]
+ /// defining the fields this `ValueSet` refers to.
+ ///
+ /// [`Identifier`]: super::callsite::Identifier
+ /// [`Callsite`]: super::callsite::Callsite
+ #[inline]
+ pub fn callsite(&self) -> callsite::Identifier {
+ self.fields.callsite()
+ }
+
+ /// Visits all the fields in this `ValueSet` with the provided [visitor].
+ ///
+ /// [visitor]: Visit
+ pub fn record(&self, visitor: &mut dyn Visit) {
+ let my_callsite = self.callsite();
+ for (field, value) in self.values {
+ if field.callsite() != my_callsite {
+ continue;
+ }
+ if let Some(value) = value {
+ value.record(field, visitor);
+ }
+ }
+ }
+
+ /// Returns the number of fields in this `ValueSet` that would be visited
+ /// by a given [visitor] to the [`ValueSet::record()`] method.
+ ///
+ /// [visitor]: Visit
+ /// [`ValueSet::record()`]: ValueSet::record()
+ pub fn len(&self) -> usize {
+ let my_callsite = self.callsite();
+ self.values
+ .iter()
+ .filter(|(field, _)| field.callsite() == my_callsite)
+ .count()
+ }
+
+ /// Returns `true` if this `ValueSet` contains a value for the given `Field`.
+ pub(crate) fn contains(&self, field: &Field) -> bool {
+ field.callsite() == self.callsite()
+ && self
+ .values
+ .iter()
+ .any(|(key, val)| *key == field && val.is_some())
+ }
+
+ /// Returns true if this `ValueSet` contains _no_ values.
+ pub fn is_empty(&self) -> bool {
+ let my_callsite = self.callsite();
+ self.values
+ .iter()
+ .all(|(key, val)| val.is_none() || key.callsite() != my_callsite)
+ }
+
+ pub(crate) fn field_set(&self) -> &FieldSet {
+ self.fields
+ }
+}
+
+impl<'a> fmt::Debug for ValueSet<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.values
+ .iter()
+ .fold(&mut f.debug_struct("ValueSet"), |dbg, (key, v)| {
+ if let Some(val) = v {
+ val.record(key, dbg);
+ }
+ dbg
+ })
+ .field("callsite", &self.callsite())
+ .finish()
+ }
+}
+
+impl<'a> fmt::Display for ValueSet<'a> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.values
+ .iter()
+ .fold(&mut f.debug_map(), |dbg, (key, v)| {
+ if let Some(val) = v {
+ val.record(key, dbg);
+ }
+ dbg
+ })
+ .finish()
+ }
+}
+
+// ===== impl ValidLen =====
+
+mod private {
+ use super::*;
+
+ /// Marker trait implemented by arrays which are of valid length to
+ /// construct a `ValueSet`.
+ ///
+ /// `ValueSet`s may only be constructed from arrays containing 32 or fewer
+ /// elements, to ensure the array is small enough to always be allocated on the
+ /// stack. This trait is only implemented by arrays of an appropriate length,
+ /// ensuring that the correct size arrays are used at compile-time.
+ pub trait ValidLen<'a>: Borrow<[(&'a Field, Option<&'a (dyn Value + 'a)>)]> {}
+}
+
+macro_rules! impl_valid_len {
+ ( $( $len:tt ),+ ) => {
+ $(
+ impl<'a> private::ValidLen<'a> for
+ [(&'a Field, Option<&'a (dyn Value + 'a)>); $len] {}
+ )+
+ }
+}
+
+impl_valid_len! {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+ 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+ use crate::metadata::{Kind, Level, Metadata};
+ use crate::stdlib::{borrow::ToOwned, string::String};
+
+ struct TestCallsite1;
+ static TEST_CALLSITE_1: TestCallsite1 = TestCallsite1;
+ static TEST_META_1: Metadata<'static> = metadata! {
+ name: "field_test1",
+ target: module_path!(),
+ level: Level::INFO,
+ fields: &["foo", "bar", "baz"],
+ callsite: &TEST_CALLSITE_1,
+ kind: Kind::SPAN,
+ };
+
+ impl crate::callsite::Callsite for TestCallsite1 {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unimplemented!()
+ }
+
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META_1
+ }
+ }
+
+ struct TestCallsite2;
+ static TEST_CALLSITE_2: TestCallsite2 = TestCallsite2;
+ static TEST_META_2: Metadata<'static> = metadata! {
+ name: "field_test2",
+ target: module_path!(),
+ level: Level::INFO,
+ fields: &["foo", "bar", "baz"],
+ callsite: &TEST_CALLSITE_2,
+ kind: Kind::SPAN,
+ };
+
+ impl crate::callsite::Callsite for TestCallsite2 {
+ fn set_interest(&self, _: crate::subscriber::Interest) {
+ unimplemented!()
+ }
+
+ fn metadata(&self) -> &Metadata<'_> {
+ &TEST_META_2
+ }
+ }
+
+ #[test]
+ fn value_set_with_no_values_is_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (&fields.field("bar").unwrap(), None),
+ (&fields.field("baz").unwrap(), None),
+ ];
+ let valueset = fields.value_set(values);
+ assert!(valueset.is_empty());
+ }
+
+ #[test]
+ fn empty_value_set_is_empty() {
+ let fields = TEST_META_1.fields();
+ let valueset = fields.value_set(&[]);
+ assert!(valueset.is_empty());
+ }
+
+ #[test]
+ fn value_sets_with_fields_from_other_callsites_are_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
+ ];
+ let valueset = TEST_META_2.fields().value_set(values);
+ assert!(valueset.is_empty())
+ }
+
+ #[test]
+ fn sparse_value_sets_are_not_empty() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
+ (&fields.field("baz").unwrap(), None),
+ ];
+ let valueset = fields.value_set(values);
+ assert!(!valueset.is_empty());
+ }
+
+ #[test]
+ fn fields_from_other_callsets_are_skipped() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), None),
+ (
+ &TEST_META_2.fields().field("bar").unwrap(),
+ Some(&57 as &dyn Value),
+ ),
+ (&fields.field("baz").unwrap(), None),
+ ];
+
+ struct MyVisitor;
+ impl Visit for MyVisitor {
+ fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
+ assert_eq!(field.callsite(), TEST_META_1.callsite())
+ }
+ }
+ let valueset = fields.value_set(values);
+ valueset.record(&mut MyVisitor);
+ }
+
+ #[test]
+ fn empty_fields_are_skipped() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&Empty as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&57 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
+ ];
+
+ struct MyVisitor;
+ impl Visit for MyVisitor {
+ fn record_debug(&mut self, field: &Field, _: &dyn (crate::stdlib::fmt::Debug)) {
+ assert_eq!(field.name(), "bar")
+ }
+ }
+ let valueset = fields.value_set(values);
+ valueset.record(&mut MyVisitor);
+ }
+
+ #[test]
+ fn record_debug_fn() {
+ let fields = TEST_META_1.fields();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&1 as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&2 as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&3 as &dyn Value)),
+ ];
+ let valueset = fields.value_set(values);
+ let mut result = String::new();
+ valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
+ use crate::stdlib::fmt::Write;
+ write!(&mut result, "{:?}", value).unwrap();
+ });
+ assert_eq!(result, "123".to_owned());
+ }
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn record_error() {
+ let fields = TEST_META_1.fields();
+ let err: Box<dyn std::error::Error + Send + Sync + 'static> =
+ std::io::Error::new(std::io::ErrorKind::Other, "lol").into();
+ let values = &[
+ (&fields.field("foo").unwrap(), Some(&err as &dyn Value)),
+ (&fields.field("bar").unwrap(), Some(&Empty as &dyn Value)),
+ (&fields.field("baz").unwrap(), Some(&Empty as &dyn Value)),
+ ];
+ let valueset = fields.value_set(values);
+ let mut result = String::new();
+ valueset.record(&mut |_: &Field, value: &dyn fmt::Debug| {
+ use core::fmt::Write;
+ write!(&mut result, "{:?}", value).unwrap();
+ });
+ assert_eq!(result, format!("{}", err));
+ }
+}