-
Notifications
You must be signed in to change notification settings - Fork 341
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
151: Split io into multiple files r=stjepang a=yoshuawuyts Counterpart to #150, splits `io::read` and `io::write` into multiple files. This is useful to prevent a single file from becoming hard to navigate as we add more combinators. No other changes were made. Ref #131. Thanks! Co-authored-by: Yoshua Wuyts <[email protected]>
- Loading branch information
Showing
11 changed files
with
347 additions
and
266 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
use crate::future::Future; | ||
use crate::task::{Context, Poll}; | ||
|
||
use std::io; | ||
use std::pin::Pin; | ||
|
||
use futures_io::AsyncRead; | ||
|
||
#[doc(hidden)] | ||
#[allow(missing_debug_implementations)] | ||
pub struct ReadFuture<'a, T: Unpin + ?Sized> { | ||
pub(crate) reader: &'a mut T, | ||
pub(crate) buf: &'a mut [u8], | ||
} | ||
|
||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadFuture<'_, T> { | ||
type Output = io::Result<usize>; | ||
|
||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let Self { reader, buf } = &mut *self; | ||
Pin::new(reader).poll_read(cx, buf) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
use crate::future::Future; | ||
use crate::task::{Context, Poll}; | ||
|
||
use std::io; | ||
use std::mem; | ||
use std::pin::Pin; | ||
|
||
use futures_io::AsyncRead; | ||
|
||
#[doc(hidden)] | ||
#[allow(missing_debug_implementations)] | ||
pub struct ReadExactFuture<'a, T: Unpin + ?Sized> { | ||
pub(crate) reader: &'a mut T, | ||
pub(crate) buf: &'a mut [u8], | ||
} | ||
|
||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadExactFuture<'_, T> { | ||
type Output = io::Result<()>; | ||
|
||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let Self { reader, buf } = &mut *self; | ||
|
||
while !buf.is_empty() { | ||
let n = futures_core::ready!(Pin::new(&mut *reader).poll_read(cx, buf))?; | ||
let (_, rest) = mem::replace(buf, &mut []).split_at_mut(n); | ||
*buf = rest; | ||
|
||
if n == 0 { | ||
return Poll::Ready(Err(io::ErrorKind::UnexpectedEof.into())); | ||
} | ||
} | ||
|
||
Poll::Ready(Ok(())) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
use crate::future::Future; | ||
use crate::task::{Context, Poll}; | ||
|
||
use std::io; | ||
use std::pin::Pin; | ||
|
||
use futures_io::AsyncRead; | ||
|
||
#[doc(hidden)] | ||
#[allow(missing_debug_implementations)] | ||
pub struct ReadToEndFuture<'a, T: Unpin + ?Sized> { | ||
pub(crate) reader: &'a mut T, | ||
pub(crate) buf: &'a mut Vec<u8>, | ||
pub(crate) start_len: usize, | ||
} | ||
|
||
impl<T: AsyncRead + Unpin + ?Sized> Future for ReadToEndFuture<'_, T> { | ||
type Output = io::Result<usize>; | ||
|
||
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
let Self { | ||
reader, | ||
buf, | ||
start_len, | ||
} = &mut *self; | ||
read_to_end_internal(Pin::new(reader), cx, buf, *start_len) | ||
} | ||
} | ||
|
||
// This uses an adaptive system to extend the vector when it fills. We want to | ||
// avoid paying to allocate and zero a huge chunk of memory if the reader only | ||
// has 4 bytes while still making large reads if the reader does have a ton | ||
// of data to return. Simply tacking on an extra DEFAULT_BUF_SIZE space every | ||
// time is 4,500 times (!) slower than this if the reader has a very small | ||
// amount of data to return. | ||
// | ||
// Because we're extending the buffer with uninitialized data for trusted | ||
// readers, we need to make sure to truncate that if any of this panics. | ||
pub fn read_to_end_internal<R: AsyncRead + ?Sized>( | ||
mut rd: Pin<&mut R>, | ||
cx: &mut Context<'_>, | ||
buf: &mut Vec<u8>, | ||
start_len: usize, | ||
) -> Poll<io::Result<usize>> { | ||
struct Guard<'a> { | ||
buf: &'a mut Vec<u8>, | ||
len: usize, | ||
} | ||
|
||
impl Drop for Guard<'_> { | ||
fn drop(&mut self) { | ||
unsafe { | ||
self.buf.set_len(self.len); | ||
} | ||
} | ||
} | ||
|
||
let mut g = Guard { | ||
len: buf.len(), | ||
buf, | ||
}; | ||
let ret; | ||
loop { | ||
if g.len == g.buf.len() { | ||
unsafe { | ||
g.buf.reserve(32); | ||
let capacity = g.buf.capacity(); | ||
g.buf.set_len(capacity); | ||
rd.initializer().initialize(&mut g.buf[g.len..]); | ||
} | ||
} | ||
|
||
match futures_core::ready!(rd.as_mut().poll_read(cx, &mut g.buf[g.len..])) { | ||
Ok(0) => { | ||
ret = Poll::Ready(Ok(g.len - start_len)); | ||
break; | ||
} | ||
Ok(n) => g.len += n, | ||
Err(e) => { | ||
ret = Poll::Ready(Err(e)); | ||
break; | ||
} | ||
} | ||
} | ||
|
||
ret | ||
} |
Oops, something went wrong.