1use std::{
2 pin::Pin,
3 task::{Context, Poll},
4};
5
6use derive_more::{Deref, DerefMut};
7
8#[derive(Debug, Clone, Deref, DerefMut)]
14pub struct WithSpan<T> {
15 #[deref]
16 #[deref_mut]
17 pub inner: T,
18 pub span: tracing::Span,
19}
20
21impl<T> WithSpan<T> {
22 #[inline]
24 pub fn current(inner: T) -> Self {
25 Self { inner, span: tracing::Span::current() }
26 }
27
28 #[inline]
31 pub fn new(inner: T) -> Self {
32 Self { inner, span: tracing::Span::none() }
33 }
34
35 #[inline]
37 pub fn with_span(mut self, span: tracing::Span) -> Self {
38 self.span = span;
39 self
40 }
41
42 #[inline]
44 pub fn into_parts(self) -> (T, tracing::Span) {
45 (self.inner, self.span)
46 }
47
48 #[inline]
49 pub fn into_inner(self) -> T {
50 self.inner
51 }
52}
53
54struct WithSpanProjection<'a, T> {
56 inner: Pin<&'a mut T>,
57 span: &'a tracing::Span,
59}
60
61impl<T: Unpin> Unpin for WithSpan<T> {}
63
64impl<T> WithSpan<T> {
65 #[inline]
67 fn project(self: Pin<&mut Self>) -> WithSpanProjection<'_, T> {
68 unsafe {
69 let this = self.get_unchecked_mut();
71 WithSpanProjection { inner: Pin::new_unchecked(&mut this.inner), span: &mut this.span }
72 }
73 }
74}
75
76impl<T: Future> Future for WithSpan<T> {
77 type Output = WithSpan<T::Output>;
78
79 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
80 let WithSpanProjection { inner, span } = self.project();
81
82 let _g = span.enter();
83
84 if let Poll::Ready(val) = inner.poll(cx) {
85 return Poll::Ready(val.with_span(span));
86 }
87
88 Poll::Pending
89 }
90}
91
92#[derive(Debug, Deref, DerefMut)]
94pub struct WithEntered<T> {
95 #[deref]
96 #[deref_mut]
97 pub inner: T,
98 pub span: tracing::span::EnteredSpan,
99}
100
101pub trait EnterSpan {
108 type Output;
109
110 fn enter(self) -> Self::Output;
111}
112
113impl<T> EnterSpan for WithSpan<T> {
114 type Output = WithEntered<T>;
115
116 #[inline]
117 fn enter(self) -> Self::Output {
118 let WithSpan { inner, span } = self;
119 WithEntered { inner, span: span.entered() }
120 }
121}
122
123impl<T> EnterSpan for WithEntered<T> {
124 type Output = WithEntered<T>;
125
126 #[inline]
127 fn enter(self) -> Self::Output {
128 self
129 }
130}
131
132impl<T: EnterSpan> EnterSpan for Option<T> {
133 type Output = Option<<T as EnterSpan>::Output>;
134
135 #[inline]
136 fn enter(self) -> Self::Output {
137 self.map(|v| v.enter())
138 }
139}
140
141impl<T: EnterSpan, E> EnterSpan for Result<T, E> {
142 type Output = Result<<T as EnterSpan>::Output, E>;
143
144 #[inline]
145 fn enter(self) -> Self::Output {
146 self.map(|v| v.enter())
147 }
148}
149
150impl<T: EnterSpan> EnterSpan for Poll<T> {
151 type Output = Poll<<T as EnterSpan>::Output>;
152
153 #[inline]
154 fn enter(self) -> Self::Output {
155 match self {
156 Poll::Ready(v) => Poll::Ready(v.enter()),
157 Poll::Pending => Poll::Pending,
158 }
159 }
160}
161
162pub trait IntoSpanExt {
163 fn into_span(self) -> tracing::Span;
164}
165
166impl IntoSpanExt for tracing::Span {
167 #[inline]
168 fn into_span(self) -> tracing::Span {
169 self
170 }
171}
172
173impl IntoSpanExt for &tracing::Span {
174 #[inline]
175 fn into_span(self) -> tracing::Span {
176 self.clone()
177 }
178}
179
180impl IntoSpanExt for tracing::span::EnteredSpan {
181 #[inline]
182 fn into_span(self) -> tracing::Span {
183 self.clone()
184 }
185}
186
187pub trait SpanExt<T> {
188 fn with_span(self, span: impl IntoSpanExt) -> WithSpan<T>;
189
190 fn with_current_span(self) -> WithSpan<T>;
191}
192
193impl<T> SpanExt<T> for T {
194 #[inline]
195 fn with_span(self, span: impl IntoSpanExt) -> WithSpan<T> {
196 WithSpan { inner: self, span: span.into_span() }
197 }
198
199 fn with_current_span(self) -> WithSpan<T> {
200 WithSpan::current(self)
201 }
202}