use std::{ future::Future, io, pin::Pin, sync::Arc, task::{Context, Poll, ready}, time::Instant, }; use tokio::{ io::Interest, time::{Sleep, sleep_until}, }; use super::{AsyncTimer, AsyncUdpSocket, Runtime, UdpPollHelper}; /// A Quinn runtime for Tokio #[derive(Debug)] pub struct TokioRuntime; impl Runtime for TokioRuntime { fn new_timer(&self, t: Instant) -> Pin> { Box::pin(sleep_until(t.into())) } fn spawn(&self, future: Pin + Send>>) { tokio::spawn(future); } fn wrap_udp_socket(&self, sock: std::net::UdpSocket) -> io::Result> { Ok(Arc::new(UdpSocket { inner: udp::UdpSocketState::new((&sock).into())?, io: tokio::net::UdpSocket::from_std(sock)?, })) } fn now(&self) -> Instant { tokio::time::Instant::now().into_std() } } impl AsyncTimer for Sleep { fn reset(self: Pin<&mut Self>, t: Instant) { Self::reset(self, t.into()) } fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()> { Future::poll(self, cx) } } #[derive(Debug)] struct UdpSocket { io: tokio::net::UdpSocket, inner: udp::UdpSocketState, } impl AsyncUdpSocket for UdpSocket { fn create_io_poller(self: Arc) -> Pin> { Box::pin(UdpPollHelper::new(move || { let socket = self.clone(); async move { socket.io.writable().await } })) } fn try_send(&self, transmit: &udp::Transmit) -> io::Result<()> { self.io.try_io(Interest::WRITABLE, || { self.inner.send((&self.io).into(), transmit) }) } fn poll_recv( &self, cx: &mut Context, bufs: &mut [std::io::IoSliceMut<'_>], meta: &mut [udp::RecvMeta], ) -> Poll> { loop { ready!(self.io.poll_recv_ready(cx))?; if let Ok(res) = self.io.try_io(Interest::READABLE, || { self.inner.recv((&self.io).into(), bufs, meta) }) { return Poll::Ready(Ok(res)); } } } fn local_addr(&self) -> io::Result { self.io.local_addr() } fn may_fragment(&self) -> bool { self.inner.may_fragment() } fn max_transmit_segments(&self) -> usize { self.inner.max_gso_segments() } fn max_receive_segments(&self) -> usize { self.inner.gro_segments() } }