Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

tracing-core: implement PartialEq, Eq for Metadata, FieldSet #2229

Merged
merged 2 commits into from Jul 19, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 9 additions & 0 deletions tracing-core/src/callsite.rs
Expand Up @@ -113,6 +113,15 @@ pub trait Callsite: Sync {

/// Returns the [metadata] associated with the callsite.
///
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
///
/// **Note:** Implementations of this method should not produce [`Metadata`]
/// that share the same callsite [`Identifier`] but otherwise differ in any
/// way (e.g., have different `name`s).
///
/// </pre></div>
///
/// [metadata]: super::metadata::Metadata
fn metadata(&self) -> &Metadata<'_>;
}
Expand Down
44 changes: 44 additions & 0 deletions tracing-core/src/field.rs
Expand Up @@ -70,6 +70,16 @@ pub struct Field {
pub struct Empty;

/// Describes the fields present on a span.
jswrenn marked this conversation as resolved.
Show resolved Hide resolved
///
/// ## Equality
///
/// In well-behaved applications, two `FieldSet`s [initialized] with equal
/// [callsite identifiers] will have identical fields. Consequently, in release
/// builds, [`FieldSet::eq`] *only* checks that its arguments have equal
/// callsites. However, the equality of field names is checked in debug builds.
///
/// [initialized]: Self::new
/// [callsite identifiers]: callsite::Identifier
pub struct FieldSet {
/// The names of each field on the described span.
names: &'static [&'static str],
Expand Down Expand Up @@ -788,6 +798,40 @@ impl fmt::Display for FieldSet {
}
}

impl Eq for FieldSet {}

impl PartialEq for FieldSet {
fn eq(&self, other: &Self) -> bool {
if core::ptr::eq(&self, &other) {
true
} else if cfg!(not(debug_assertions)) {
// In a well-behaving application, two `FieldSet`s can be assumed to
// be totally equal so long as they share the same callsite.
self.callsite == other.callsite
} else {
// However, when debug-assertions are enabled, do NOT assume that
// the application is well-behaving; check every the field names of
// each `FieldSet` for equality.

// `FieldSet` is destructured here to ensure a compile-error if the
// fields of `FieldSet` change.
let Self {
names: lhs_names,
callsite: lhs_callsite,
} = self;

let Self {
names: rhs_names,
callsite: rhs_callsite,
} = &other;

// Check callsite equality first, as it is probably cheaper to do
// than str equality.
lhs_callsite == rhs_callsite && lhs_names == rhs_names
}
}
}

// ===== impl Iter =====

impl Iterator for Iter {
Expand Down
73 changes: 63 additions & 10 deletions tracing-core/src/metadata.rs
Expand Up @@ -35,16 +35,13 @@ use core::{
/// _significantly_ lower than that of creating the actual span. Therefore,
/// filtering is based on metadata, rather than on the constructed span.
///
/// <div class="example-wrap" style="display:inline-block">
/// <pre class="ignore" style="white-space:normal;font:inherit;">
/// ## Equality
///
/// **Note**: Although instances of `Metadata` cannot
/// be compared directly, they provide a method [`callsite`][Metadata::callsite],
/// returning an opaque [callsite identifier] which uniquely identifies the
/// callsite where the metadata originated. This can be used to determine if two
/// `Metadata` correspond to the same callsite.
jswrenn marked this conversation as resolved.
Show resolved Hide resolved
///
/// </pre></div>
/// In well-behaved applications, two `Metadata` with equal
/// [callsite identifiers] will be equal in all other ways (i.e., have the same
/// `name`, `target`, etc.). Consequently, in release builds, [`Metadata::eq`]
/// *only* checks that its arguments have equal callsites. However, the equality
/// of `Metadata`'s other fields is checked in debug builds.
///
/// [span]: super::span
/// [event]: super::event
Expand All @@ -56,7 +53,7 @@ use core::{
/// [line number]: Self::line
/// [module path]: Self::module_path
/// [collector]: super::collect::Collect
/// [callsite identifier]: super::callsite::Identifier
/// [callsite identifiers]: Self::callsite
pub struct Metadata<'a> {
/// The name of the span described by this metadata.
name: &'static str,
Expand Down Expand Up @@ -444,6 +441,62 @@ impl fmt::Debug for Kind {
}
}

impl<'a> Eq for Metadata<'a> {}

impl<'a> PartialEq for Metadata<'a> {
#[inline]
fn eq(&self, other: &Self) -> bool {
if core::ptr::eq(&self, &other) {
true
} else if cfg!(not(debug_assertions)) {
// In a well-behaving application, two `Metadata` can be assumed to
// be totally equal so long as they share the same callsite.
self.callsite() == other.callsite()
} else {
// However, when debug-assertions are enabled, do not assume that
// the application is well-behaving; check every field of `Metadata`
// for equality.

// `Metadata` is destructured here to ensure a compile-error if the
// fields of `Metadata` change.
let Metadata {
name: lhs_name,
target: lhs_target,
level: lhs_level,
module_path: lhs_module_path,
file: lhs_file,
line: lhs_line,
fields: lhs_fields,
kind: lhs_kind,
} = self;

let Metadata {
name: rhs_name,
target: rhs_target,
level: rhs_level,
module_path: rhs_module_path,
file: rhs_file,
line: rhs_line,
fields: rhs_fields,
kind: rhs_kind,
} = &other;

// The initial comparison of callsites is purely an optimization;
// it can be removed without affecting the overall semantics of the
// expression.
self.callsite() == other.callsite()
&& lhs_name == rhs_name
&& lhs_target == rhs_target
&& lhs_level == rhs_level
&& lhs_module_path == rhs_module_path
&& lhs_file == rhs_file
&& lhs_line == rhs_line
&& lhs_fields == rhs_fields
&& lhs_kind == rhs_kind
}
}
}

// ===== impl Level =====

impl Level {
Expand Down