use compio_buf::{BufResult, IoBuf, IoBufMut, IoVectoredBuf};
#[allow(unused_imports)]
use compio_io::{AsyncRead, AsyncWrite};
use std::future::{Future, poll_fn};
use std::io;
use std::net::SocketAddr;
use std::pin::Pin;
use tokio::io::{AsyncWrite as TokioAsyncWrite, ReadBuf};
pub use tokio::net::ToSocketAddrs;
pub use tokio::time::{sleep, timeout};
pub type JoinHandle<T> = tokio::task::JoinHandle<T>;
#[inline]
pub fn spawn<F>(fut: F) -> JoinHandle<F::Output>
where
F: Future + 'static,
F::Output: 'static,
{
tokio::task::spawn_local(fut)
}
#[inline]
pub fn spawn_detached<F>(fut: F)
where
F: Future + 'static,
F::Output: 'static,
{
drop(tokio::task::spawn_local(fut));
}
#[inline]
pub async fn spawn_blocking<F, T>(f: F) -> T
where
F: FnOnce() -> T + Send + Sync + 'static,
T: Send + 'static,
{
tokio::task::spawn_blocking(f)
.await
.expect("blocking task panicked")
}
#[inline]
pub async fn join<T>(handle: JoinHandle<T>) -> T {
handle
.await
.expect("spawned task panicked or was cancelled")
}
pub struct LocalRuntime {
inner: tokio::runtime::Runtime,
local: tokio::task::LocalSet,
}
impl LocalRuntime {
pub fn new() -> std::io::Result<Self> {
let inner = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
Ok(Self {
inner,
local: tokio::task::LocalSet::new(),
})
}
pub fn block_on<F: Future>(&self, fut: F) -> F::Output {
self.local.block_on(&self.inner, fut)
}
}
async fn read_into<R, B>(reader: &mut R, buf: B) -> BufResult<usize, B>
where
R: tokio::io::AsyncRead + Unpin,
B: IoBufMut,
{
crate::io::fill_read(buf, async move |spare| {
let mut read_buf = ReadBuf::uninit(spare);
poll_fn(|cx| Pin::new(&mut *reader).poll_read(cx, &mut read_buf)).await?;
Ok(read_buf.filled().len())
})
.await
}
async fn write_from<W, B>(writer: &mut W, buf: B) -> BufResult<usize, B>
where
W: tokio::io::AsyncWrite + Unpin,
B: IoBuf,
{
let slice = buf.as_init();
let result = poll_fn(|cx| Pin::new(&mut *writer).poll_write(cx, slice)).await;
match result {
Ok(n) => BufResult(Ok(n), buf),
Err(e) => BufResult(Err(e), buf),
}
}
async fn write_vectored_from<W, B>(writer: &mut W, buf: B) -> BufResult<usize, B>
where
W: tokio::io::AsyncWrite + Unpin,
B: IoVectoredBuf,
{
let result = poll_fn(|cx| {
crate::io::with_vectored_slices(&buf, |slices| {
Pin::new(&mut *writer).poll_write_vectored(cx, slices)
})
})
.await;
match result {
Ok(n) => BufResult(Ok(n), buf),
Err(e) => BufResult(Err(e), buf),
}
}
macro_rules! impl_compio_io {
(read $ty:ty) => {
impl AsyncRead for $ty {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
read_into(&mut self.inner, buf).await
}
}
};
(write $ty:ty) => {
impl AsyncWrite for $ty {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_from(&mut self.inner, buf).await
}
async fn write_vectored<B: IoVectoredBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_vectored_from(&mut self.inner, buf).await
}
async fn flush(&mut self) -> io::Result<()> {
poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await
}
async fn shutdown(&mut self) -> io::Result<()> {
poll_fn(|cx| Pin::new(&mut self.inner).poll_shutdown(cx)).await
}
}
};
(raw_fd $ty:ty) => {
#[cfg(unix)]
impl std::os::unix::io::AsRawFd for $ty {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.inner.as_raw_fd()
}
}
};
}
#[derive(Debug)]
pub struct TcpStream {
inner: tokio::net::TcpStream,
}
#[derive(Debug)]
pub struct OwnedReadHalf {
inner: tokio::net::tcp::OwnedReadHalf,
}
#[derive(Debug)]
pub struct OwnedWriteHalf {
inner: tokio::net::tcp::OwnedWriteHalf,
}
impl TcpStream {
pub async fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
let inner = tokio::net::TcpStream::connect(addr).await?;
Ok(Self { inner })
}
pub fn from_std(stream: std::net::TcpStream) -> io::Result<Self> {
stream.set_nonblocking(true)?;
Ok(Self {
inner: tokio::net::TcpStream::from_std(stream)?,
})
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
self.inner.peer_addr()
}
pub fn into_split(self) -> (OwnedReadHalf, OwnedWriteHalf) {
let (r, w) = self.inner.into_split();
(OwnedReadHalf { inner: r }, OwnedWriteHalf { inner: w })
}
}
#[derive(Debug)]
pub struct TcpListener {
inner: tokio::net::TcpListener,
}
impl TcpListener {
pub async fn bind<A: ToSocketAddrs>(addr: A) -> io::Result<Self> {
let inner = tokio::net::TcpListener::bind(addr).await?;
Ok(Self { inner })
}
pub fn from_std(listener: std::net::TcpListener) -> io::Result<Self> {
listener.set_nonblocking(true)?;
Ok(Self {
inner: tokio::net::TcpListener::from_std(listener)?,
})
}
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (stream, addr) = self.inner.accept().await?;
Ok((TcpStream { inner: stream }, addr))
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.inner.local_addr()
}
}
pub fn bind_reuseport(addr: SocketAddr) -> io::Result<TcpListener> {
TcpListener::from_std(crate::tcp::reuseport_listener(addr)?)
}
impl_compio_io!(read TcpStream);
impl_compio_io!(write TcpStream);
impl_compio_io!(raw_fd TcpStream);
impl_compio_io!(read OwnedReadHalf);
impl_compio_io!(write OwnedWriteHalf);
#[cfg(unix)]
pub use unix::{UnixListener, UnixStream};
#[cfg(unix)]
mod unix {
use super::{
AsyncRead, AsyncWrite, BufResult, IoBuf, IoBufMut, Pin, TokioAsyncWrite, io, poll_fn,
read_into, write_from,
};
use std::os::unix::io::AsRawFd;
use std::path::Path;
#[derive(Debug)]
pub struct UnixStream {
inner: tokio::net::UnixStream,
}
impl UnixStream {
pub async fn connect<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let inner = tokio::net::UnixStream::connect(path).await?;
Ok(Self { inner })
}
pub fn local_addr(&self) -> io::Result<tokio::net::unix::SocketAddr> {
self.inner.local_addr()
}
pub fn peer_addr(&self) -> io::Result<tokio::net::unix::SocketAddr> {
self.inner.peer_addr()
}
}
#[derive(Debug)]
pub struct UnixListener {
inner: tokio::net::UnixListener,
}
impl UnixListener {
#[allow(clippy::unused_async)] pub async fn bind<P: AsRef<Path>>(path: P) -> io::Result<Self> {
let inner = tokio::net::UnixListener::bind(path)?;
Ok(Self { inner })
}
pub async fn accept(&self) -> io::Result<(UnixStream, tokio::net::unix::SocketAddr)> {
let (stream, addr) = self.inner.accept().await?;
Ok((UnixStream { inner: stream }, addr))
}
pub fn local_addr(&self) -> io::Result<tokio::net::unix::SocketAddr> {
self.inner.local_addr()
}
}
impl AsyncRead for UnixStream {
async fn read<B: IoBufMut>(&mut self, buf: B) -> BufResult<usize, B> {
read_into(&mut self.inner, buf).await
}
}
impl AsyncWrite for UnixStream {
async fn write<B: IoBuf>(&mut self, buf: B) -> BufResult<usize, B> {
write_from(&mut self.inner, buf).await
}
async fn flush(&mut self) -> io::Result<()> {
poll_fn(|cx| Pin::new(&mut self.inner).poll_flush(cx)).await
}
async fn shutdown(&mut self) -> io::Result<()> {
poll_fn(|cx| Pin::new(&mut self.inner).poll_shutdown(cx)).await
}
}
impl AsRawFd for UnixStream {
fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
self.inner.as_raw_fd()
}
}
}