mirror of
https://github.com/tokio-rs/tokio.git
synced 2026-08-22 00:00:11 +02:00
157 lines
5.3 KiB
Rust
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)
|
|
}
|
|
}
|