use compio_buf::{BufResult, IoBuf, IoBufMut, IoVectoredBuf};
#[allow(unused_imports)]
use compio_io::{AsyncRead, AsyncWrite};
use smol::Async;
use socket2::SockRef;
use std::future::Future;
use std::io;
use std::net::SocketAddr;
use std::sync::Arc;
use std::time::Duration;
pub use std::net::ToSocketAddrs;
fn resolve<A: ToSocketAddrs>(addr: A) -> io::Result<SocketAddr> {
addr.to_socket_addrs()?
.next()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "no socket address resolved"))
}
async fn read_into<T, B>(stream: &Async<T>, buf: B) -> BufResult<usize, B>
where
B: IoBufMut,
for<'a> SockRef<'a>: From<&'a T>,
{
crate::io::fill_read(buf, async move |spare| {
stream
.read_with(|inner| SockRef::from(inner).recv(spare))
.await
})
.await
}
async fn write_from<T, B>(stream: &Async<T>, buf: B) -> BufResult<usize, B>
where
B: IoBuf,
for<'a> SockRef<'a>: From<&'a T>,
{
let result = stream
.write_with(|inner| SockRef::from(inner).send(buf.as_init()))
.await;
match result {
Ok(n) => BufResult(Ok(n), buf),
Err(e) => BufResult(Err(e), buf),
}
}
async fn write_vectored_from<T, B>(stream: &Async<T>, buf: B) -> BufResult<usize, B>
where
B: IoVectoredBuf,
for<'a> SockRef<'a>: From<&'a T>,
{
let result = stream
.write_with(|inner| {
crate::io::with_vectored_slices(&buf, |slices| {
SockRef::from(inner).send_vectored(slices)
})
})
.await;
match result {
Ok(n) => BufResult(Ok(n), buf),
Err(e) => BufResult(Err(e), buf),
}
}
thread_local! {
static EXECUTOR: smol::LocalExecutor<'static> = const { smol::LocalExecutor::new() };
}
pub type JoinHandle<T> = smol::Task<T>;
#[inline]
pub fn spawn<F>(fut: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
EXECUTOR.with(|ex| ex.spawn(fut))
}
#[inline]
pub fn spawn_detached<F>(fut: F)
where
F: Future + 'static,
F::Output: 'static,
{
EXECUTOR.with(|ex| ex.spawn(fut).detach());
}
#[inline]
pub async fn spawn_blocking<F, T>(f: F) -> T
where
F: FnOnce() -> T + Send + Sync + 'static,
T: Send + 'static,
{
smol::unblock(f).await
}
#[inline]
pub async fn join<T>(handle: JoinHandle<T>) -> T {
handle.await
}
pub struct LocalRuntime;
impl LocalRuntime {
#[allow(clippy::unnecessary_wraps)] pub fn new() -> io::Result<Self> {
Ok(Self)
}
pub fn block_on<F: Future>(&self, fut: F) -> F::Output {
EXECUTOR.with(|ex| smol::block_on(ex.run(fut)))
}
}
pub async fn sleep(dur: Duration) {
smol::Timer::after(dur).await;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Elapsed;
impl std::fmt::Display for Elapsed {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str("deadline has elapsed")
}
}
impl std::error::Error for Elapsed {}
pub async fn timeout<F, T>(dur: Duration, fut: F) -> Result<T, Elapsed>
where
F: Future<Output = T>,
{
use futures::future::{Either, select};
use std::pin::pin;
match select(pin!(fut), pin!(smol::Timer::after(dur))).await {
Either::Left((val, _)) => Ok(val),
Either::Right(_) => Err(Elapsed),
}
}
#[derive(Clone, Debug)]
pub struct TcpStream {
inner: Arc<Async<std::net::TcpStream>>,
}
#[derive(Debug)]
pub struct OwnedReadHalf {
inner: Arc<Async<std::net::TcpStream>>,
}
#[derive(Debug)]
pub struct OwnedWriteHalf {
inner: Arc<Async<std::net::TcpStream>>,
}
impl TcpStream {
pub async fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
let target = resolve(addr)?;
let inner = Async::<std::net::TcpStream>::connect(target).await?;
Ok(Self {
inner: Arc::new(inner),
})
}
pub fn from_std(stream: std::net::TcpStream) -> io::Result<Self> {
Ok(Self {
inner: Arc::new(Async::new(stream)?),
})
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().local_addr()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().peer_addr()
}
#[must_use]
pub fn into_split(self) -> (OwnedReadHalf, OwnedWriteHalf) {
(
OwnedReadHalf {
inner: self.inner.clone(),
},
OwnedWriteHalf { inner: self.inner },
)
}
}
#[derive(Debug)]
pub struct TcpListener {
inner: Async<std::net::TcpListener>,
}
impl TcpListener {
#[allow(clippy::unused_async)] pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
let target = resolve(addr)?;
let inner = Async::<std::net::TcpListener>::bind(target)?;
Ok(Self { inner })
}
pub fn from_std(listener: std::net::TcpListener) -> io::Result<Self> {
Ok(Self {
inner: Async::new(listener)?,
})
}
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (stream, addr) = self.inner.accept().await?;
Ok((
TcpStream {
inner: Arc::new(stream),
},
addr,
))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().local_addr()
}
}
pub fn bind_reuseport(addr: SocketAddr) -> io::Result<TcpListener> {
TcpListener::from_std(crate::tcp::reuseport_listener(addr)?)
}
impl AsyncRead for TcpStream {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
read_into(&self.inner, buf).await
}
}
impl AsyncWrite for TcpStream {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_from(&self.inner, buf).await
}
async fn write_vectored<B: IoVectoredBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_vectored_from(&self.inner, buf).await
}
async fn flush(&mut self) -> io::Result<()> {
Ok(())
}
async fn shutdown(&mut self) -> io::Result<()> {
SockRef::from(self.inner.get_ref()).shutdown(std::net::Shutdown::Write)
}
}
impl AsyncRead for OwnedReadHalf {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
read_into(&self.inner, buf).await
}
}
impl AsyncWrite for OwnedWriteHalf {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_from(&self.inner, buf).await
}
async fn write_vectored<B: IoVectoredBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_vectored_from(&self.inner, buf).await
}
async fn flush(&mut self) -> io::Result<()> {
Ok(())
}
async fn shutdown(&mut self) -> io::Result<()> {
SockRef::from(self.inner.get_ref()).shutdown(std::net::Shutdown::Write)
}
}
#[cfg(unix)]
impl std::os::unix::io::AsRawFd for TcpStream {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
std::os::unix::io::AsRawFd::as_raw_fd(self.inner.get_ref())
}
}
#[cfg(unix)]
pub use unix::{UnixListener, UnixStream};
#[cfg(unix)]
mod unix {
use super::{
Arc, AsyncRead, AsyncWrite, BufResult, IoBuf, IoBufMut, IoVectoredBuf, SockRef, io,
read_into, write_from, write_vectored_from,
};
use smol::Async;
use std::os::unix::io::AsRawFd;
use std::os::unix::net::SocketAddr;
use std::path::Path;
type StdUnixStream = std::os::unix::net::UnixStream;
type StdUnixListener = std::os::unix::net::UnixListener;
#[derive(Clone, Debug)]
pub struct UnixStream {
inner: Arc<Async<StdUnixStream>>,
}
impl UnixStream {
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let inner = Async::<StdUnixStream>::connect(path).await?;
Ok(Self {
inner: Arc::new(inner),
})
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().local_addr()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().peer_addr()
}
}
#[derive(Debug)]
pub struct UnixListener {
inner: Async<StdUnixListener>,
}
impl UnixListener {
#[allow(clippy::unused_async)] pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let inner = Async::<StdUnixListener>::bind(path)?;
Ok(Self { inner })
}
pub async fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
let (stream, addr) = self.inner.accept().await?;
Ok((
UnixStream {
inner: Arc::new(stream),
},
addr,
))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.get_ref().local_addr()
}
}
impl AsyncRead for UnixStream {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
read_into(&self.inner, buf).await
}
}
impl AsyncWrite for UnixStream {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_from(&self.inner, buf).await
}
async fn write_vectored<B: IoVectoredBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_vectored_from(&self.inner, buf).await
}
async fn flush(&mut self) -> io::Result<()> {
Ok(())
}
async fn shutdown(&mut self) -> io::Result<()> {
SockRef::from(self.inner.get_ref()).shutdown(std::net::Shutdown::Write)
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.inner.get_ref().as_raw_fd()
}
}
}