Files
tokio/tokio-io/src/async_read.rs
T
2019-07-01 20:44:12 -07:00

157 lines
5.3 KiB
Rust

//use crate::split::{ReadHalf, WriteHalf};
//use crate::{framed, split, AsyncWrite};
use bytes::BufMut;
use std::io;
use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};
/// Read bytes asynchronously.
///
/// This trait inherits from `std::io::Read` and indicates that an I/O object is
/// **non-blocking**. All non-blocking I/O objects must return an error when
/// bytes are unavailable instead of blocking the current thread.
///
/// Specifically, this means that the `poll_read` function will return one of
/// the following:
///
/// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately read
/// and placed into the output buffer, where `n` == 0 implies that EOF has
/// been reached.
///
/// * `Poll::Pending` means that no data was read into the buffer
/// provided. The I/O object is not currently readable but may become readable
/// in the future. Most importantly, **the current future's task is scheduled
/// to get unparked when the object is readable**. This means that like
/// `Future::poll` you'll receive a notification when the I/O object is
/// readable again.
///
/// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the
/// underlying object.
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
pub trait AsyncRead {
/// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
/// `true` if the supplied buffer was zeroed out.
///
/// While it would be highly unusual, implementations of [`io::Read`] are
/// able to read data from the buffer passed as an argument. Because of
/// this, the buffer passed to [`io::Read`] must be initialized memory. In
/// situations where large numbers of buffers are used, constantly having to
/// zero out buffers can be expensive.
///
/// This function does any necessary work to prepare an uninitialized buffer
/// to be safe to pass to `read`. If `read` guarantees to never attempt to
/// read data out of the supplied buffer, then `prepare_uninitialized_buffer`
/// doesn't need to do any work.
///
/// If this function returns `true`, then the memory has been zeroed out.
/// This allows implementations of `AsyncRead` which are composed of
/// multiple subimplementations to efficiently implement
/// `prepare_uninitialized_buffer`.
///
/// This function isn't actually `unsafe` to call but `unsafe` to implement.
/// The implementer must ensure that either the whole `buf` has been zeroed
/// or `poll_read_buf()` overwrites the buffer without reading it and returns
/// correct value.
///
/// This function is called from [`poll_read_buf`].
///
/// [`io::Read`]: https://doc.rust-lang.org/std/io/trait.Read.html
/// [`poll_read_buf`]: #method.poll_read_buf
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
for i in 0..buf.len() {
buf[i] = 0;
}
true
}
/// Attempt to read from the `AsyncRead` into `buf`.
///
/// On success, returns `Poll::Ready(Ok(num_bytes_read))`.
///
/// If no data is available for reading, the method returns
/// `Poll::Pending` and arranges for the current task (via
/// `cx.waker()`) to receive a notification when the object becomes
/// readable or is closed.
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>>;
/// Pull some bytes from this source into the specified `BufMut`, returning
/// how many bytes were read.
///
/// The `buf` provided will have bytes read into it and the internal cursor
/// will be advanced if any bytes were read. Note that this method typically
/// will not reallocate the buffer provided.
fn poll_read_buf<B: BufMut>(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut B,
) -> Poll<io::Result<usize>>
where
Self: Sized,
{
if !buf.has_remaining_mut() {
return Poll::Ready(Ok(0));
}
unsafe {
let n = {
let b = buf.bytes_mut();
self.prepare_uninitialized_buffer(b);
ready!(self.poll_read(cx, b))?
};
buf.advance_mut(n);
Poll::Ready(Ok(n))
}
}
}
macro_rules! deref_async_read {
() => {
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
(**self).prepare_uninitialized_buffer(buf)
}
fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8])
-> Poll<io::Result<usize>>
{
Pin::new(&mut **self).poll_read(cx, buf)
}
}
}
impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for Box<T> {
deref_async_read!();
}
impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for &mut T {
deref_async_read!();
}
impl<P> AsyncRead for Pin<P>
where
P: DerefMut + Unpin,
P::Target: AsyncRead,
{
unsafe fn prepare_uninitialized_buffer(&self, buf: &mut [u8]) -> bool {
(**self).prepare_uninitialized_buffer(buf)
}
fn poll_read(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
self.get_mut().as_mut().poll_read(cx, buf)
}
}