#[cfg_attr(not(feature = "all-implementations"), allow(unused))] use std::{ io::Result, pin::Pin, task::{Context, Poll}, }; pub struct TrackEof { inner: R, eof: bool, } impl TrackEof { pub fn new(inner: R) -> Self { Self { inner, eof: false } } pub fn project(self: Pin<&mut Self>) -> (Pin<&mut R>, &mut bool) { let Self { inner, eof } = Pin::into_inner(self); (Pin::new(inner), eof) } } #[cfg(feature = "futures-io")] impl futures::io::AsyncRead for TrackEof { fn poll_read(self: Pin<&mut Self>, cx: &mut Context, buf: &mut [u8]) -> Poll> { let (inner, eof) = self.project(); assert!(!*eof); match inner.poll_read(cx, buf) { Poll::Ready(Ok(0)) => { if !buf.is_empty() { *eof = true; } Poll::Ready(Ok(0)) } other => other, } } } #[cfg(feature = "futures-io")] impl futures::io::AsyncBufRead for TrackEof { fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let (inner, eof) = self.project(); assert!(!*eof); match inner.poll_fill_buf(cx) { Poll::Ready(Ok(buf)) => { if buf.is_empty() { *eof = true; } Poll::Ready(Ok(buf)) } other => other, } } fn consume(self: Pin<&mut Self>, amt: usize) { self.project().0.consume(amt) } } #[cfg(feature = "tokio")] impl tokio::io::AsyncRead for TrackEof { fn poll_read( self: Pin<&mut Self>, cx: &mut Context, buf: &mut tokio::io::ReadBuf, ) -> Poll> { let (inner, eof) = self.project(); assert!(!*eof); let len = buf.filled().len(); match inner.poll_read(cx, buf) { Poll::Ready(Ok(())) => { if buf.filled().len() == len && buf.remaining() > 0 { *eof = true; } Poll::Ready(Ok(())) } other => other, } } } #[cfg(feature = "tokio")] impl tokio::io::AsyncBufRead for TrackEof { fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context) -> Poll> { let (inner, eof) = self.project(); assert!(!*eof); match inner.poll_fill_buf(cx) { Poll::Ready(Ok(buf)) => { if buf.is_empty() { *eof = true; } Poll::Ready(Ok(buf)) } other => other, } } fn consume(self: Pin<&mut Self>, amt: usize) { self.project().0.consume(amt) } }