use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use pin_project_lite::pin_project;
use crate::net::ToSocketAddrs;
pin_project! {
#[derive(Debug)]
pub struct TcpStream {
#[pin]
inner: FromRuntime! {
"std" => std::net::TcpStream,
"async-std" => async_io::Async<std::net::TcpStream>,
"tokio" => tokio::net::TcpStream,
},
}
}
impl TcpStream {
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
pub async fn connect<A: ToSocketAddrs>(address: A) -> io::Result<Self> {
let addrs = address.to_socket_addrs().await?;
let mut last_error = None;
for addr in addrs {
let r = pick_async_runtime_async!(addr, {
"async-std" => |addr| async_io::Async::<std::net::TcpStream>::connect(addr),
"tokio" => |addr| tokio::net::TcpStream::connect(addr),
})
.resolve()
.await
.into_result();
match r {
Ok(stream) => {
return Ok(Self { inner: stream });
}
Err(error) => {
last_error = Some(error);
}
}
}
Err(last_error.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
#[cfg(any(feature = "blocking", doc))]
#[cfg_attr(docsrs, doc(cfg(feature = "blocking")))]
pub fn connect_blocking<A: ToSocketAddrs>(address: A) -> io::Result<Self> {
let addrs = address.to_socket_addrs_blocking()?;
let mut last_error = None;
for addr in addrs {
let r = pick_blocking_runtime!(addr, {
"std" => |addr| std::net::TcpStream::connect(addr),
});
match r {
Ok(stream) => {
return Ok(Self { inner: stream });
}
Err(error) => {
last_error = Some(error);
}
}
}
Err(last_error.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any addresses",
)
}))
}
pub fn nodelay(&self) -> io::Result<bool> {
apply_runtime!(&self.inner, {
"std" => |stream| stream.nodelay(),
"async-std" => |stream| stream.get_ref().nodelay(),
"tokio" => |stream| stream.nodelay(),
})
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
apply_runtime!(&self.inner, {
"std" => |stream| stream.set_nodelay(nodelay),
"async-std" => |stream| stream.get_ref().set_nodelay(nodelay),
"tokio" => |stream| stream.set_nodelay(nodelay),
})
}
}
impl io::Read for TcpStream {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
apply_mut_runtime!(&mut self.inner, buf, {
"std" => |stream, buf| stream.read(buf),
"async-std" => |stream, buf| stream.get_mut().read(buf),
"tokio" => |stream, buf| stream.try_read(buf),
})
}
}
impl io::Write for TcpStream {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
apply_mut_runtime!(&mut self.inner, {
"std" => |stream| stream.write(buf),
"async-std" => |stream| stream.get_mut().write(buf),
"tokio" => |stream| stream.try_write(buf),
})
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl crate::io::Ready for TcpStream {
fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
apply_runtime!(&self.inner, cx, {
"std" => |_, _| Poll::Ready(Ok(())),
"async-std" => |stream, cx| {
Pin::new(stream).poll_readable(cx)
},
"tokio" => |stream, cx| {
Pin::new(stream).poll_read_ready(cx)
},
})
}
fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
apply_runtime!(&self.inner, cx, {
"std" => |_, _| Poll::Ready(Ok(())),
"async-std" => |stream, cx| {
Pin::new(stream).poll_writable(cx)
},
"tokio" => |stream, cx| {
Pin::new(stream).poll_write_ready(cx)
},
})
}
}
#[cfg(feature = "async")]
impl crate::io::AsyncRead for TcpStream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
apply_mut_runtime_async!(&mut self.project().inner, (cx, buf), {
"async-std" => |stream, (cx, buf)| {
Pin::new(stream).poll_read(cx, buf)
},
"tokio" => |stream, (cx, buf)| {
use tokio::io::{AsyncRead, ReadBuf};
let mut rbuf = ReadBuf::new(buf);
futures_core::ready!(Pin::new(stream).poll_read(cx, &mut rbuf)?);
Poll::Ready(Ok(rbuf.filled().len()))
},
})
}
}
#[cfg(feature = "async")]
impl crate::io::AsyncWrite for TcpStream {
fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<io::Result<usize>> {
apply_mut_runtime_async!(&mut self.project().inner, (cx, buf), {
"async-std" => |stream, (cx, buf)| {
Pin::new(stream).poll_write(cx, buf)
},
"tokio" => |stream, (cx, buf)| {
use tokio::io::AsyncWrite;
Pin::new(stream).poll_write(cx, buf)
},
})
}
fn poll_flush(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<io::Result<()>> {
Poll::Ready(Ok(()))
}
fn poll_close(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
apply_mut_runtime_async!(&mut self.project().inner, cx, {
"async-std" => |stream, cx| {
Pin::new(stream).poll_close(cx)
},
"tokio" => |stream, cx| {
use tokio::io::AsyncWrite;
Pin::new(stream).poll_shutdown(cx)
},
})
}
}