use std::{
io,
net::SocketAddr,
pin::Pin,
task::{Context, Poll},
};
use madsim::net::ToSocketAddrs;
use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
#[derive(Debug)]
pub struct TcpStream {
inner: madsim::net::TcpStream,
dirty: bool,
}
impl TcpStream {
pub async fn connect(addr: impl ToSocketAddrs) -> io::Result<Self> {
Ok(Self {
inner: madsim::net::TcpStream::connect(addr).await?,
dirty: false,
})
}
}
impl AsyncRead for TcpStream {
fn poll_read(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<io::Result<()>> {
Pin::new(&mut self.inner).poll_read(cx, buf)
}
}
impl AsyncWrite for TcpStream {
fn poll_write(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
let result = Pin::new(&mut self.inner).poll_write(cx, buf);
if matches!(result, Poll::Ready(Ok(n)) if n > 0) {
self.dirty = true;
}
result
}
fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
if !self.dirty {
return Poll::Ready(Ok(()));
}
let result = Pin::new(&mut self.inner).poll_flush(cx);
if matches!(result, Poll::Ready(Ok(()))) {
self.dirty = false;
}
result
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
self.poll_flush(cx)
}
}
#[derive(Debug)]
pub struct TcpListener(madsim::net::TcpListener);
impl TcpListener {
pub async fn bind(addr: impl ToSocketAddrs) -> io::Result<Self> {
Ok(Self(madsim::net::TcpListener::bind(addr).await?))
}
pub async fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
let (inner, peer) = self.0.accept().await?;
Ok((
TcpStream {
inner,
dirty: false,
},
peer,
))
}
}