1use std::{
55 pin::Pin,
56 task::{Context, Poll},
57 time::{Duration, Instant},
58};
59
60use hyper::rt::{Executor, Sleep, Timer};
61use pin_project_lite::pin_project;
62
63#[cfg(feature = "rt-tracing-exec-force")]
64use tracing::instrument::Instrument;
65
66pub use self::{with_hyper_io::WithHyperIo, with_tokio_io::WithTokioIo};
67
68mod with_hyper_io;
69mod with_tokio_io;
70
71#[non_exhaustive]
86#[derive(Default, Debug, Clone)]
87pub struct TokioExecutor {}
88
89pin_project! {
90 #[derive(Debug)]
94 pub struct TokioIo<T> {
95 #[pin]
96 inner: T,
97 }
98}
99
100#[non_exhaustive]
102#[derive(Default, Clone, Debug)]
103pub struct TokioTimer;
104
105pin_project! {
108 #[derive(Debug)]
109 struct TokioSleep {
110 #[pin]
111 inner: tokio::time::Sleep,
112 }
113}
114
115impl<Fut> Executor<Fut> for TokioExecutor
118where
119 Fut: Future + Send + 'static,
120 Fut::Output: Send + 'static,
121{
122 fn execute(&self, fut: Fut) {
123 #[cfg(feature = "rt-tracing-exec-force")]
124 tokio::spawn(fut.in_current_span());
125
126 #[cfg(not(feature = "rt-tracing-exec-force"))]
127 tokio::spawn(fut);
128 }
129}
130
131impl TokioExecutor {
132 pub fn new() -> Self {
134 Self {}
135 }
136}
137
138impl<T> TokioIo<T> {
141 pub fn new(inner: T) -> Self {
143 Self { inner }
144 }
145
146 pub fn inner(&self) -> &T {
148 &self.inner
149 }
150
151 pub fn inner_mut(&mut self) -> &mut T {
153 &mut self.inner
154 }
155
156 pub fn into_inner(self) -> T {
158 self.inner
159 }
160}
161
162impl<T> hyper::rt::Read for TokioIo<T>
163where
164 T: tokio::io::AsyncRead,
165{
166 fn poll_read(
167 self: Pin<&mut Self>,
168 cx: &mut Context<'_>,
169 mut buf: hyper::rt::ReadBufCursor<'_>,
170 ) -> Poll<Result<(), std::io::Error>> {
171 let n = unsafe {
172 let mut tbuf = tokio::io::ReadBuf::uninit(buf.as_mut());
173 match tokio::io::AsyncRead::poll_read(self.project().inner, cx, &mut tbuf) {
174 Poll::Ready(Ok(())) => tbuf.filled().len(),
175 other => return other,
176 }
177 };
178
179 unsafe {
180 buf.advance(n);
181 }
182 Poll::Ready(Ok(()))
183 }
184}
185
186impl<T> hyper::rt::Write for TokioIo<T>
187where
188 T: tokio::io::AsyncWrite,
189{
190 fn poll_write(
191 self: Pin<&mut Self>,
192 cx: &mut Context<'_>,
193 buf: &[u8],
194 ) -> Poll<Result<usize, std::io::Error>> {
195 tokio::io::AsyncWrite::poll_write(self.project().inner, cx, buf)
196 }
197
198 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
199 tokio::io::AsyncWrite::poll_flush(self.project().inner, cx)
200 }
201
202 fn poll_shutdown(
203 self: Pin<&mut Self>,
204 cx: &mut Context<'_>,
205 ) -> Poll<Result<(), std::io::Error>> {
206 tokio::io::AsyncWrite::poll_shutdown(self.project().inner, cx)
207 }
208
209 fn is_write_vectored(&self) -> bool {
210 tokio::io::AsyncWrite::is_write_vectored(&self.inner)
211 }
212
213 fn poll_write_vectored(
214 self: Pin<&mut Self>,
215 cx: &mut Context<'_>,
216 bufs: &[std::io::IoSlice<'_>],
217 ) -> Poll<Result<usize, std::io::Error>> {
218 tokio::io::AsyncWrite::poll_write_vectored(self.project().inner, cx, bufs)
219 }
220}
221
222impl<T> tokio::io::AsyncRead for TokioIo<T>
223where
224 T: hyper::rt::Read,
225{
226 fn poll_read(
227 self: Pin<&mut Self>,
228 cx: &mut Context<'_>,
229 tbuf: &mut tokio::io::ReadBuf<'_>,
230 ) -> Poll<Result<(), std::io::Error>> {
231 let filled = tbuf.filled().len();
233 let sub_filled = unsafe {
234 let mut buf = hyper::rt::ReadBuf::uninit(tbuf.unfilled_mut());
235
236 match hyper::rt::Read::poll_read(self.project().inner, cx, buf.unfilled()) {
237 Poll::Ready(Ok(())) => buf.filled().len(),
238 other => return other,
239 }
240 };
241
242 let n_filled = filled + sub_filled;
243 let n_init = sub_filled;
245 unsafe {
246 tbuf.assume_init(n_init);
247 tbuf.set_filled(n_filled);
248 }
249
250 Poll::Ready(Ok(()))
251 }
252}
253
254impl<T> tokio::io::AsyncWrite for TokioIo<T>
255where
256 T: hyper::rt::Write,
257{
258 fn poll_write(
259 self: Pin<&mut Self>,
260 cx: &mut Context<'_>,
261 buf: &[u8],
262 ) -> Poll<Result<usize, std::io::Error>> {
263 hyper::rt::Write::poll_write(self.project().inner, cx, buf)
264 }
265
266 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>> {
267 hyper::rt::Write::poll_flush(self.project().inner, cx)
268 }
269
270 fn poll_shutdown(
271 self: Pin<&mut Self>,
272 cx: &mut Context<'_>,
273 ) -> Poll<Result<(), std::io::Error>> {
274 hyper::rt::Write::poll_shutdown(self.project().inner, cx)
275 }
276
277 fn is_write_vectored(&self) -> bool {
278 hyper::rt::Write::is_write_vectored(&self.inner)
279 }
280
281 fn poll_write_vectored(
282 self: Pin<&mut Self>,
283 cx: &mut Context<'_>,
284 bufs: &[std::io::IoSlice<'_>],
285 ) -> Poll<Result<usize, std::io::Error>> {
286 hyper::rt::Write::poll_write_vectored(self.project().inner, cx, bufs)
287 }
288}
289
290impl Timer for TokioTimer {
293 fn sleep(&self, duration: Duration) -> Pin<Box<dyn Sleep>> {
294 Box::pin(TokioSleep {
295 inner: tokio::time::sleep(duration),
296 })
297 }
298
299 fn sleep_until(&self, deadline: Instant) -> Pin<Box<dyn Sleep>> {
300 Box::pin(TokioSleep {
301 inner: tokio::time::sleep_until(deadline.into()),
302 })
303 }
304
305 fn reset(&self, sleep: &mut Pin<Box<dyn Sleep>>, new_deadline: Instant) {
306 if let Some(sleep) = sleep.as_mut().downcast_mut_pin::<TokioSleep>() {
307 sleep.reset(new_deadline)
308 }
309 }
310
311 fn now(&self) -> Instant {
312 tokio::time::Instant::now().into()
313 }
314}
315
316impl TokioTimer {
317 pub fn new() -> Self {
319 Self {}
320 }
321}
322
323impl Future for TokioSleep {
324 type Output = ();
325
326 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
327 self.project().inner.poll(cx)
328 }
329}
330
331impl Sleep for TokioSleep {}
332
333impl TokioSleep {
334 fn reset(self: Pin<&mut Self>, deadline: Instant) {
335 self.project().inner.as_mut().reset(deadline.into());
336 }
337}
338
339#[cfg(test)]
340mod tests {
341 use crate::rt::TokioExecutor;
342 use hyper::rt::Executor;
343 use tokio::sync::oneshot;
344
345 #[tokio::test]
346 async fn simple_execute() -> Result<(), Box<dyn std::error::Error>> {
347 let (tx, rx) = oneshot::channel();
348 let executor = TokioExecutor::new();
349 executor.execute(async move {
350 tx.send(()).unwrap();
351 });
352 rx.await.map_err(Into::into)
353 }
354
355 #[cfg(feature = "tracing")]
356 #[tokio::test]
357 async fn execute_tracing_span() {
358 let _subscriber = tracing::subscriber::set_default(tracing_subscriber::registry());
361 let span = tracing::info_span!("caller");
362 assert!(span.id().is_some());
363 let (tx, rx) = oneshot::channel();
364
365 {
366 let _entered = span.enter();
367 TokioExecutor::new().execute(async move {
368 tx.send(tracing::Span::current().id()).unwrap();
369 });
370 }
371
372 let spawned_span = rx.await.unwrap();
373 if cfg!(feature = "rt-tracing-exec-force") {
374 assert_eq!(spawned_span, span.id());
375 } else {
376 assert_eq!(spawned_span, None);
377 }
378 }
379}