From ce02eb54e8b71e1667fcb31a703933f1f85d7419 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Thu, 15 Apr 2021 13:51:26 -0700 Subject: [PATCH] core: add `Collect` impl for `Box` MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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` 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` directly, rather than some `BoxedCollector` newtype. --- tracing-core/src/collect.rs | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/tracing-core/src/collect.rs b/tracing-core/src/collect.rs index e673b4570e..54129cc757 100644 --- a/tracing-core/src/collect.rs +++ b/tracing-core/src/collect.rs @@ -555,3 +555,70 @@ impl Interest { } } } + +#[cfg(feature = "alloc")] +impl Collect for alloc::boxed::Box { + #[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 { + 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> { + if id == TypeId::of::() { + return Some(NonNull::from(self).cast()); + } + + self.as_ref().downcast_raw(id) + } +}