From 85b577aae01cbe41be383424a3e5ecbe947d3ef8 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Wed, 11 Sep 2019 00:41:09 +0900 Subject: [PATCH 1/3] Add BufRead::fill_buf --- src/io/buf_read/fill_buf.rs | 32 ++++++++++++++++++++++++++++++++ src/io/buf_read/mod.rs | 22 ++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 src/io/buf_read/fill_buf.rs diff --git a/src/io/buf_read/fill_buf.rs b/src/io/buf_read/fill_buf.rs new file mode 100644 index 000000000..2dd1f9d07 --- /dev/null +++ b/src/io/buf_read/fill_buf.rs @@ -0,0 +1,32 @@ +use std::pin::Pin; + +use futures_io::AsyncBufRead; + +use crate::future::Future; +use crate::io; +use crate::task::{Context, Poll}; + +#[doc(hidden)] +#[allow(missing_debug_implementations)] +pub struct FillBufFuture<'a, R: ?Sized> { + reader: &'a mut R, +} + +impl<'a, R: ?Sized> From<&'a mut R> for FillBufFuture<'a, R> { + fn from(reader: &'a mut R) -> Self { + Self { reader } + } +} + +impl<'a, R: AsyncBufRead + Unpin + ?Sized> Future for FillBufFuture<'a, R> { + type Output = io::Result<&'a [u8]>; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { + let Self { reader } = &mut *self; + let result = Pin::new(reader).poll_fill_buf(cx); + // This is safe because: + // 1. The buffer is valid for the lifetime of the reader. + // 2. Output is unrelated to the wrapper (Self). + result.map_ok(|buf| unsafe { std::mem::transmute::<_, &'a [u8]>(buf) }) + } +} diff --git a/src/io/buf_read/mod.rs b/src/io/buf_read/mod.rs index e320375fa..3c0b9616a 100644 --- a/src/io/buf_read/mod.rs +++ b/src/io/buf_read/mod.rs @@ -1,7 +1,9 @@ +mod fill_buf; mod lines; mod read_line; mod read_until; +use fill_buf::FillBufFuture; pub use lines::Lines; use read_line::ReadLineFuture; use read_until::ReadUntilFuture; @@ -41,6 +43,26 @@ cfg_if! { /// [`futures::io::AsyncBufRead`]: /// https://docs.rs/futures-preview/0.3.0-alpha.17/futures/io/trait.AsyncBufRead.html pub trait BufRead { + /// Returns the contents of the internal buffer, filling it with more data from the inner + /// reader if it is empty. + /// + /// This function is a lower-level call. It needs to be paired with the [`consume`] method to + /// function properly. When calling this method, none of the contents will be "read" in the + /// sense that later calling `read` may return the same contents. As such, [`consume`] must be + /// called with the number of bytes that are consumed from this buffer to ensure that the bytes + /// are never returned twice. + /// + /// [`consume`]: #tymethod.consume + /// + /// An empty buffer returned indicates that the stream has reached EOF. + // TODO: write a proper doctest with `consume` + fn fill_buf<'a>(&'a mut self) -> ret!('a, FillBufFuture, io::Result<&'a [u8]>) + where + Self: Unpin, + { + FillBufFuture::from(self) + } + /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. /// /// This function will read bytes from the underlying stream until the delimiter or EOF is From d9b40ff2390a0d09c42b1cfd7460aa3daab64e66 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Wed, 11 Sep 2019 23:02:20 +0900 Subject: [PATCH 2/3] Make FillBufFuture constructor pub(crate) --- src/io/buf_read/fill_buf.rs | 4 ++-- src/io/buf_read/mod.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/io/buf_read/fill_buf.rs b/src/io/buf_read/fill_buf.rs index 2dd1f9d07..a03525241 100644 --- a/src/io/buf_read/fill_buf.rs +++ b/src/io/buf_read/fill_buf.rs @@ -12,8 +12,8 @@ pub struct FillBufFuture<'a, R: ?Sized> { reader: &'a mut R, } -impl<'a, R: ?Sized> From<&'a mut R> for FillBufFuture<'a, R> { - fn from(reader: &'a mut R) -> Self { +impl<'a, R: ?Sized> FillBufFuture<'a, R> { + pub(crate) fn new(reader: &'a mut R) -> Self { Self { reader } } } diff --git a/src/io/buf_read/mod.rs b/src/io/buf_read/mod.rs index 3c0b9616a..6018439a9 100644 --- a/src/io/buf_read/mod.rs +++ b/src/io/buf_read/mod.rs @@ -60,7 +60,7 @@ pub trait BufRead { where Self: Unpin, { - FillBufFuture::from(self) + FillBufFuture::new(self) } /// Reads all bytes into `buf` until the delimiter `byte` or EOF is reached. From 67f2cedf60cfa8d22faea971f7b5b56f2ec08bc8 Mon Sep 17 00:00:00 2001 From: Wonwoo Choi Date: Wed, 11 Sep 2019 23:03:01 +0900 Subject: [PATCH 3/3] Give more information about the transmutation source type --- src/io/buf_read/fill_buf.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/io/buf_read/fill_buf.rs b/src/io/buf_read/fill_buf.rs index a03525241..0ce58cfbc 100644 --- a/src/io/buf_read/fill_buf.rs +++ b/src/io/buf_read/fill_buf.rs @@ -27,6 +27,6 @@ impl<'a, R: AsyncBufRead + Unpin + ?Sized> Future for FillBufFuture<'a, R> { // This is safe because: // 1. The buffer is valid for the lifetime of the reader. // 2. Output is unrelated to the wrapper (Self). - result.map_ok(|buf| unsafe { std::mem::transmute::<_, &'a [u8]>(buf) }) + result.map_ok(|buf| unsafe { std::mem::transmute::<&'_ [u8], &'a [u8]>(buf) }) } }