use std::{
pin::Pin,
task::{Context, Poll},
};
use derive_more::{Deref, DerefMut};
#[derive(Debug, Clone, Deref, DerefMut)]
pub struct WithSpan<T> {
#[deref]
#[deref_mut]
pub inner: T,
pub span: tracing::Span,
}
impl<T> WithSpan<T> {
#[inline]
pub fn current(inner: T) -> Self {
Self { inner, span: tracing::Span::current() }
}
#[inline]
pub fn new(inner: T) -> Self {
Self { inner, span: tracing::Span::none() }
}
#[inline]
pub fn with_span(mut self, span: tracing::Span) -> Self {
self.span = span;
self
}
#[inline]
pub fn into_parts(self) -> (T, tracing::Span) {
(self.inner, self.span)
}
#[inline]
pub fn into_inner(self) -> T {
self.inner
}
}
struct WithSpanProjection<'a, T> {
inner: Pin<&'a mut T>,
span: &'a tracing::Span,
}
impl<T: Unpin> Unpin for WithSpan<T> {}
impl<T> WithSpan<T> {
#[inline]
fn project(self: Pin<&mut Self>) -> WithSpanProjection<'_, T> {
unsafe {
let this = self.get_unchecked_mut();
WithSpanProjection { inner: Pin::new_unchecked(&mut this.inner), span: &mut this.span }
}
}
}
impl<T: Future> Future for WithSpan<T> {
type Output = WithSpan<T::Output>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let WithSpanProjection { inner, span } = self.project();
let _g = span.enter();
if let Poll::Ready(val) = inner.poll(cx) {
return Poll::Ready(val.with_span(span));
}
Poll::Pending
}
}
#[derive(Debug, Deref, DerefMut)]
pub struct WithEntered<T> {
#[deref]
#[deref_mut]
pub inner: T,
pub span: tracing::span::EnteredSpan,
}
pub trait EnterSpan {
type Output;
fn enter(self) -> Self::Output;
}
impl<T> EnterSpan for WithSpan<T> {
type Output = WithEntered<T>;
#[inline]
fn enter(self) -> Self::Output {
let WithSpan { inner, span } = self;
WithEntered { inner, span: span.entered() }
}
}
impl<T> EnterSpan for WithEntered<T> {
type Output = WithEntered<T>;
#[inline]
fn enter(self) -> Self::Output {
self
}
}
impl<T: EnterSpan> EnterSpan for Option<T> {
type Output = Option<<T as EnterSpan>::Output>;
#[inline]
fn enter(self) -> Self::Output {
self.map(|v| v.enter())
}
}
impl<T: EnterSpan, E> EnterSpan for Result<T, E> {
type Output = Result<<T as EnterSpan>::Output, E>;
#[inline]
fn enter(self) -> Self::Output {
self.map(|v| v.enter())
}
}
impl<T: EnterSpan> EnterSpan for Poll<T> {
type Output = Poll<<T as EnterSpan>::Output>;
#[inline]
fn enter(self) -> Self::Output {
match self {
Poll::Ready(v) => Poll::Ready(v.enter()),
Poll::Pending => Poll::Pending,
}
}
}
pub trait IntoSpanExt {
fn into_span(self) -> tracing::Span;
}
impl IntoSpanExt for tracing::Span {
#[inline]
fn into_span(self) -> tracing::Span {
self
}
}
impl IntoSpanExt for &tracing::Span {
#[inline]
fn into_span(self) -> tracing::Span {
self.clone()
}
}
impl IntoSpanExt for tracing::span::EnteredSpan {
#[inline]
fn into_span(self) -> tracing::Span {
self.clone()
}
}
pub trait SpanExt<T> {
fn with_span(self, span: impl IntoSpanExt) -> WithSpan<T>;
fn with_current_span(self) -> WithSpan<T>;
}
impl<T> SpanExt<T> for T {
#[inline]
fn with_span(self, span: impl IntoSpanExt) -> WithSpan<T> {
WithSpan { inner: self, span: span.into_span() }
}
fn with_current_span(self) -> WithSpan<T> {
WithSpan::current(self)
}
}