use core::future::Future;
use std::fmt::Debug;
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Instant;
pub trait Runtime: Send + Sync + core::fmt::Debug + 'static {
#[track_caller]
fn spawn(&self, future: Pin<Box<dyn Future<Output = ()> + Send>>);
fn new_timer(&self, i: Instant) -> Pin<Box<dyn AsyncTimer>>;
fn wrap_udp_socket(
&self,
socket: std::net::UdpSocket,
) -> std::io::Result<Arc<dyn AsyncUdpSocket>>;
#[allow(clippy::type_complexity)]
fn new_tcp_listener(
&self,
addr: SocketAddr,
) -> Pin<Box<dyn Future<Output = std::io::Result<Arc<dyn AsyncTcpListener>>> + Send>>;
#[allow(clippy::type_complexity)]
fn tcp_connect(
&self,
peer: SocketAddr,
) -> Pin<Box<dyn Future<Output = std::io::Result<Box<dyn AsyncTcpStream>>> + Send>>;
}
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 local_addr(&self) -> std::io::Result<SocketAddr>;
fn poll_recv(
&self,
cx: &mut Context,
dest: &mut [u8],
) -> Poll<std::io::Result<(usize, SocketAddr)>>;
fn poll_send(
&self,
cx: &mut Context,
src: &[u8],
to: SocketAddr,
) -> Poll<std::io::Result<usize>>;
}
pub trait AsyncUdpSocketExt: AsyncUdpSocket {
fn send_to(
&self,
data: &[u8],
to: SocketAddr,
) -> impl Future<Output = std::io::Result<usize>> + Send;
fn recv_from(
&self,
buf: &mut [u8],
) -> impl Future<Output = std::io::Result<(usize, SocketAddr)>> + Send;
}
impl<T: AsyncUdpSocket + ?Sized> AsyncUdpSocketExt for T {
async fn send_to(&self, data: &[u8], to: SocketAddr) -> std::io::Result<usize> {
core::future::poll_fn(|cx| self.poll_send(cx, data, to)).await
}
async fn recv_from(&self, buf: &mut [u8]) -> std::io::Result<(usize, SocketAddr)> {
core::future::poll_fn(|cx| self.poll_recv(cx, buf)).await
}
}
pub trait AsyncTcpListener: Send + Sync + Debug + 'static {
fn local_addr(&self) -> std::io::Result<SocketAddr>;
fn poll_next(&self, cx: &mut Context) -> Poll<std::io::Result<Box<dyn AsyncTcpStream>>>;
}
pub trait AsyncTcpListenerExt {
fn accept(&self) -> impl Future<Output = std::io::Result<Box<dyn AsyncTcpStream>>> + Send;
}
impl<T: AsyncTcpListener + ?Sized> AsyncTcpListenerExt for T {
async fn accept(&self) -> std::io::Result<Box<dyn AsyncTcpStream>> {
core::future::poll_fn(|cx| self.poll_next(cx)).await
}
}
pub trait AsyncTcpStream: Send + Sync + Debug {
fn local_addr(&self) -> std::io::Result<SocketAddr>;
fn remote_addr(&self) -> std::io::Result<SocketAddr>;
fn split(self: Box<Self>) -> (Box<dyn AsyncTcpStreamRead>, Box<dyn AsyncTcpStreamWrite>);
}
pub trait AsyncTcpStreamRead: Send + Sync + Debug {
fn local_addr(&self) -> std::io::Result<SocketAddr>;
fn remote_addr(&self) -> std::io::Result<SocketAddr>;
fn poll_read(&mut self, cx: &mut Context, buf: &mut [u8]) -> Poll<std::io::Result<usize>>;
}
pub trait AsyncTcpStreamReadExt: AsyncTcpStreamRead {
fn read(&mut self, dest: &mut [u8]) -> impl Future<Output = std::io::Result<usize>> + Send;
}
impl<T: AsyncTcpStreamRead + ?Sized> AsyncTcpStreamReadExt for T {
async fn read(&mut self, dest: &mut [u8]) -> std::io::Result<usize> {
core::future::poll_fn(|cx| self.poll_read(cx, dest)).await
}
}
pub trait AsyncTcpStreamWrite: Send + Sync + Debug {
fn local_addr(&self) -> std::io::Result<SocketAddr>;
fn remote_addr(&self) -> std::io::Result<SocketAddr>;
fn poll_write(&mut self, cx: &mut Context, buf: &[u8]) -> Poll<std::io::Result<usize>>;
fn poll_flush(&mut self, cx: &mut Context) -> Poll<std::io::Result<()>>;
fn poll_shutdown(
&mut self,
cx: &mut Context,
how: std::net::Shutdown,
) -> Poll<std::io::Result<()>>;
}
pub trait AsyncTcpStreamWriteExt: AsyncTcpStreamWrite {
fn write(&mut self, buf: &[u8]) -> impl Future<Output = std::io::Result<usize>> + Send;
fn write_all(&mut self, buf: &[u8]) -> impl Future<Output = std::io::Result<()>> {
async move {
let mut idx = 0;
loop {
if idx >= buf.len() {
return Ok(());
}
match self.write(&buf[idx..]).await {
Ok(len) => idx += len,
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => (),
Err(e) => return Err(e),
}
}
}
}
fn flush(&mut self) -> impl Future<Output = std::io::Result<()>>;
fn shutdown(&mut self, how: std::net::Shutdown) -> impl Future<Output = std::io::Result<()>>;
}
impl<T: AsyncTcpStreamWrite + ?Sized> AsyncTcpStreamWriteExt for T {
async fn flush(&mut self) -> std::io::Result<()> {
core::future::poll_fn(|cx| self.poll_flush(cx)).await
}
async fn shutdown(&mut self, how: std::net::Shutdown) -> std::io::Result<()> {
core::future::poll_fn(|cx| self.poll_shutdown(cx, how)).await
}
async fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
core::future::poll_fn(|cx| self.poll_write(cx, buf)).await
}
}
#[allow(clippy::needless_return)]
pub fn default_runtime() -> Option<Arc<dyn Runtime>> {
#[cfg(feature = "runtime-tokio")]
if let Ok(handle) = ::tokio::runtime::Handle::try_current() {
return Some(Arc::new(TokioRuntime::new(handle)));
}
#[cfg(feature = "runtime-smol")]
{
return Some(Arc::new(SmolRuntime));
}
#[cfg(not(feature = "runtime-smol"))]
None
}
#[cfg(feature = "runtime-smol")]
mod smol;
#[cfg(feature = "runtime-smol")]
pub use smol::SmolRuntime;
#[cfg(feature = "runtime-tokio")]
mod tokio;
#[cfg(feature = "runtime-tokio")]
pub use tokio::TokioRuntime;