use std::{
fmt::Debug,
future::Future,
io::{self, IoSliceMut},
net::SocketAddr,
pin::Pin,
sync::Arc,
task::{Context, Poll},
time::Instant,
};
use udp::{RecvMeta, Transmit};
pub trait Runtime: Send + Sync + Debug + 'static {
fn new_timer(&self, i: Instant) -> Pin<Box<dyn AsyncTimer>>;
fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>);
fn wrap_udp_socket(&self, t: std::net::UdpSocket) -> io::Result<Arc<dyn AsyncUdpSocket>>;
fn now(&self) -> Instant {
Instant::now()
}
}
pub trait AsyncTimer: Send + Debug + 'static {
fn reset(self: Pin<&mut Self>, i: Instant);
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<()>;
}
pub trait AsyncUdpSocket: Send + Sync + Debug + 'static {
fn create_io_poller(self: Arc<Self>) -> Pin<Box<dyn UdpPoller>>;
fn try_send(&self, transmit: &Transmit) -> io::Result<()>;
fn poll_recv(
&self,
cx: &mut Context,
bufs: &mut [IoSliceMut<'_>],
meta: &mut [RecvMeta],
) -> Poll<io::Result<usize>>;
fn local_addr(&self) -> io::Result<SocketAddr>;
fn max_transmit_segments(&self) -> usize {
1
}
fn max_receive_segments(&self) -> usize {
1
}
fn may_fragment(&self) -> bool {
true
}
}
pub trait UdpPoller: Send + Sync + Debug + 'static {
fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>>;
}
pin_project_lite::pin_project! {
struct UdpPollHelper<MakeFut, Fut> {
make_fut: MakeFut,
#[pin]
fut: Option<Fut>,
}
}
impl<MakeFut, Fut> UdpPollHelper<MakeFut, Fut> {
#[cfg(any(
feature = "runtime-async-std",
feature = "runtime-smol",
feature = "runtime-tokio"
))]
fn new(make_fut: MakeFut) -> Self {
Self {
make_fut,
fut: None,
}
}
}
impl<MakeFut, Fut> UdpPoller for UdpPollHelper<MakeFut, Fut>
where
MakeFut: Fn() -> Fut + Send + Sync + 'static,
Fut: Future<Output = io::Result<()>> + Send + Sync + 'static,
{
fn poll_writable(self: Pin<&mut Self>, cx: &mut Context) -> Poll<io::Result<()>> {
let mut this = self.project();
if this.fut.is_none() {
this.fut.set(Some((this.make_fut)()));
}
let result = this.fut.as_mut().as_pin_mut().unwrap().poll(cx);
if result.is_ready() {
this.fut.set(None);
}
result
}
}
impl<MakeFut, Fut> Debug for UdpPollHelper<MakeFut, Fut> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("UdpPollHelper").finish_non_exhaustive()
}
}
#[allow(clippy::needless_return)] pub fn default_runtime() -> Option<Arc<dyn Runtime>> {
#[cfg(feature = "runtime-tokio")]
{
if ::tokio::runtime::Handle::try_current().is_ok() {
return Some(Arc::new(TokioRuntime));
}
}
#[cfg(feature = "runtime-async-std")]
{
return Some(Arc::new(AsyncStdRuntime));
}
#[cfg(all(feature = "runtime-smol", not(feature = "runtime-async-std")))]
{
return Some(Arc::new(SmolRuntime));
}
#[cfg(not(any(feature = "runtime-async-std", feature = "runtime-smol")))]
None
}
#[cfg(feature = "runtime-tokio")]
mod tokio;
#[cfg(feature = "runtime-tokio")]
pub use self::tokio::TokioRuntime;
#[cfg(feature = "async-io")]
mod async_io;
#[cfg(feature = "async-io")]
pub use self::async_io::*;