use std::io::{IoSlice, IoSliceMut, Result};
use std::pin::{pin, Pin};
use std::task::{Context, Poll};
use bytes::BufMut;
#[doc(no_inline)]
use sys::{pipe as sys_pipe, LeftStream, RightStream};
use tokio::io::{AsyncRead, AsyncWrite, Interest, ReadBuf, Ready};
enum EitherStream {
Left(LeftStream),
Right(RightStream),
}
pub struct Stream(EitherStream);
pub async fn pipe() -> Result<(Stream, Stream)> {
let (tx, rx) = sys_pipe().await?;
Ok((
Stream(EitherStream::Left(tx)),
Stream(EitherStream::Right(rx)),
))
}
macro_rules! multiplex {
($o:ident.$($f:tt)+) => {
match &$o.0 {
EitherStream::Left(inner) => inner.$($f)+,
EitherStream::Right(inner) => inner.$($f)+,
}
};
(pinned, $o:ident.$($f:tt)+) => {
match &mut $o.get_mut().0 {
EitherStream::Left(inner) => pin!(inner).$($f)+,
EitherStream::Right(inner) => pin!(inner).$($f)+,
}
};
}
impl AsyncRead for Stream {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut ReadBuf<'_>,
) -> Poll<Result<()>> {
multiplex!(pinned, self.poll_read(cx, buf))
}
}
impl AsyncWrite for Stream {
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize>> {
multiplex!(pinned, self.poll_write(cx, buf))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
multiplex!(pinned, self.poll_flush(cx))
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>> {
multiplex!(pinned, self.poll_shutdown(cx))
}
fn is_write_vectored(&self) -> bool {
multiplex!(self.is_write_vectored())
}
fn poll_write_vectored(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[IoSlice<'_>],
) -> Poll<Result<usize>> {
multiplex!(pinned, self.poll_write_vectored(cx, buf))
}
}
impl Stream {
pub async fn async_io<R>(&self, interest: Interest, f: impl FnMut() -> Result<R>) -> Result<R> {
multiplex!(self.async_io(interest, f).await)
}
pub async fn readable(&self) -> Result<()> {
multiplex!(self.readable().await)
}
pub async fn ready(&self, interest: Interest) -> Result<Ready> {
multiplex!(self.ready(interest).await)
}
pub fn poll_read_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
multiplex!(self.poll_read_ready(cx))
}
pub fn try_io<R>(&self, interest: Interest, f: impl FnOnce() -> Result<R>) -> Result<R> {
multiplex!(self.try_io(interest, f))
}
pub fn try_read(&self, buf: &mut [u8]) -> Result<usize> {
multiplex!(self.try_read(buf))
}
pub fn try_read_buf<B: BufMut>(&self, buf: &mut B) -> Result<usize> {
multiplex!(self.try_read_buf(buf))
}
pub fn try_read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> Result<usize> {
multiplex!(self.try_read_vectored(bufs))
}
pub async fn writable(&self) -> Result<()> {
multiplex!(self.writable().await)
}
pub fn poll_write_ready(&self, cx: &mut Context<'_>) -> Poll<Result<()>> {
multiplex!(self.poll_write_ready(cx))
}
pub fn try_write(&self, buf: &[u8]) -> Result<usize> {
multiplex!(self.try_write(buf))
}
pub fn try_write_vectored(&self, buf: &[IoSlice<'_>]) -> Result<usize> {
multiplex!(self.try_write_vectored(buf))
}
}
#[cfg_attr(unix, path = "sys/unix.rs")]
#[cfg_attr(windows, path = "sys/windows.rs")]
mod sys;