Skip to content

Commit

Permalink
core: add Collect impl for Box<dyn Collect + ...> (#1358)
Browse files Browse the repository at this point in the history
In some cases, users may wish to erase the type of a `Colelct`
implementation, such as when it is dynamically constructed from a
complex parameterized type. When doing so, it's important to ensure that
all trait methods with default implementations are properly forwarded to
the inner erased type. For example, if the type does not implement
`try_close`, but the inner erased collector does, then the the
collector will not be notified when spans close — which could result in
a memory leak.

To avoid potential footguns resulting from users implementing
type-erased collectors incorrectly, this branch adds a new `impl Collect
for Box<dyn Collect + Send + Sync + 'static>` in `tracing-core`, when
the `alloc` feature flag is enabled. This is also somewhat more
ergonomic than any solution in another crate, since the implementation
is for `Box<dyn Collect + ...>` directly, rather than some
`BoxedCollector` newtype.
  • Loading branch information
hawkw authored Apr 27, 2021
1 parent 1de85c5 commit d59a2ca
Showing 1 changed file with 67 additions and 0 deletions.
67 changes: 67 additions & 0 deletions tracing-core/src/collect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -555,3 +555,70 @@ impl Interest {
}
}
}

#[cfg(feature = "alloc")]
impl Collect for alloc::boxed::Box<dyn Collect + Send + Sync + 'static> {
#[inline]
fn register_callsite(&self, metadata: &'static Metadata<'static>) -> Interest {
self.as_ref().register_callsite(metadata)
}

#[inline]
fn enabled(&self, metadata: &Metadata<'_>) -> bool {
self.as_ref().enabled(metadata)
}

#[inline]
fn max_level_hint(&self) -> Option<LevelFilter> {
self.as_ref().max_level_hint()
}

#[inline]
fn new_span(&self, span: &span::Attributes<'_>) -> span::Id {
self.as_ref().new_span(span)
}

#[inline]
fn record(&self, span: &span::Id, values: &span::Record<'_>) {
self.as_ref().record(span, values)
}

#[inline]
fn record_follows_from(&self, span: &span::Id, follows: &span::Id) {
self.as_ref().record_follows_from(span, follows)
}

#[inline]
fn event(&self, event: &Event<'_>) {
self.as_ref().event(event)
}

#[inline]
fn enter(&self, span: &span::Id) {
self.as_ref().enter(span)
}

#[inline]
fn exit(&self, span: &span::Id) {
self.as_ref().exit(span)
}

#[inline]
fn clone_span(&self, id: &span::Id) -> span::Id {
self.as_ref().clone_span(id)
}

#[inline]
fn try_close(&self, id: span::Id) -> bool {
self.as_ref().try_close(id)
}

#[inline]
unsafe fn downcast_raw(&self, id: TypeId) -> Option<NonNull<()>> {
if id == TypeId::of::<Self>() {
return Some(NonNull::from(self).cast());
}

self.as_ref().downcast_raw(id)
}
}

0 comments on commit d59a2ca

Please sign in to comment.