1 use super::ReadBuf; 2 use std::io; 3 use std::ops::DerefMut; 4 use std::pin::Pin; 5 use std::task::{Context, Poll}; 6 7 /// Reads bytes from a source. 8 /// 9 /// This trait is analogous to the [`std::io::Read`] trait, but integrates with 10 /// the asynchronous task system. In particular, the [`poll_read`] method, 11 /// unlike [`Read::read`], will automatically queue the current task for wakeup 12 /// and return if data is not yet available, rather than blocking the calling 13 /// thread. 14 /// 15 /// Specifically, this means that the `poll_read` function will return one of 16 /// the following: 17 /// 18 /// * `Poll::Ready(Ok(()))` means that data was immediately read and placed into 19 /// the output buffer. The amount of data read can be determined by the 20 /// increase in the length of the slice returned by `ReadBuf::filled`. If the 21 /// difference is 0, EOF has been reached. 22 /// 23 /// * `Poll::Pending` means that no data was read into the buffer 24 /// provided. The I/O object is not currently readable but may become readable 25 /// in the future. Most importantly, **the current future's task is scheduled 26 /// to get unparked when the object is readable**. This means that like 27 /// `Future::poll` you'll receive a notification when the I/O object is 28 /// readable again. 29 /// 30 /// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the 31 /// underlying object. 32 /// 33 /// This trait importantly means that the `read` method only works in the 34 /// context of a future's task. The object may panic if used outside of a task. 35 /// 36 /// Utilities for working with `AsyncRead` values are provided by 37 /// [`AsyncReadExt`]. 38 /// 39 /// [`poll_read`]: AsyncRead::poll_read 40 /// [`std::io::Read`]: std::io::Read 41 /// [`Read::read`]: std::io::Read::read 42 /// [`AsyncReadExt`]: crate::io::AsyncReadExt 43 pub trait AsyncRead { 44 /// Attempts to read from the `AsyncRead` into `buf`. 45 /// 46 /// On success, returns `Poll::Ready(Ok(()))` and places data in the 47 /// unfilled portion of `buf`. If no data was read (`buf.filled().len()` is 48 /// unchanged), it implies that EOF has been reached. 49 /// 50 /// If no data is available for reading, the method returns `Poll::Pending` 51 /// and arranges for the current task (via `cx.waker()`) to receive a 52 /// notification when the object becomes readable or is closed. poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>53 fn poll_read( 54 self: Pin<&mut Self>, 55 cx: &mut Context<'_>, 56 buf: &mut ReadBuf<'_>, 57 ) -> Poll<io::Result<()>>; 58 } 59 60 macro_rules! deref_async_read { 61 () => { 62 fn poll_read( 63 mut self: Pin<&mut Self>, 64 cx: &mut Context<'_>, 65 buf: &mut ReadBuf<'_>, 66 ) -> Poll<io::Result<()>> { 67 Pin::new(&mut **self).poll_read(cx, buf) 68 } 69 }; 70 } 71 72 impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for Box<T> { 73 deref_async_read!(); 74 } 75 76 impl<T: ?Sized + AsyncRead + Unpin> AsyncRead for &mut T { 77 deref_async_read!(); 78 } 79 80 impl<P> AsyncRead for Pin<P> 81 where 82 P: DerefMut + Unpin, 83 P::Target: AsyncRead, 84 { poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>85 fn poll_read( 86 self: Pin<&mut Self>, 87 cx: &mut Context<'_>, 88 buf: &mut ReadBuf<'_>, 89 ) -> Poll<io::Result<()>> { 90 self.get_mut().as_mut().poll_read(cx, buf) 91 } 92 } 93 94 impl AsyncRead for &[u8] { poll_read( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>95 fn poll_read( 96 mut self: Pin<&mut Self>, 97 _cx: &mut Context<'_>, 98 buf: &mut ReadBuf<'_>, 99 ) -> Poll<io::Result<()>> { 100 let amt = std::cmp::min(self.len(), buf.remaining()); 101 let (a, b) = self.split_at(amt); 102 buf.put_slice(a); 103 *self = b; 104 Poll::Ready(Ok(())) 105 } 106 } 107 108 impl<T: AsRef<[u8]> + Unpin> AsyncRead for io::Cursor<T> { poll_read( mut self: Pin<&mut Self>, _cx: &mut Context<'_>, buf: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>109 fn poll_read( 110 mut self: Pin<&mut Self>, 111 _cx: &mut Context<'_>, 112 buf: &mut ReadBuf<'_>, 113 ) -> Poll<io::Result<()>> { 114 let pos = self.position(); 115 let slice: &[u8] = (*self).get_ref().as_ref(); 116 117 // The position could technically be out of bounds, so don't panic... 118 if pos > slice.len() as u64 { 119 return Poll::Ready(Ok(())); 120 } 121 122 let start = pos as usize; 123 let amt = std::cmp::min(slice.len() - start, buf.remaining()); 124 // Add won't overflow because of pos check above. 125 let end = start + amt; 126 buf.put_slice(&slice[start..end]); 127 self.set_position(end as u64); 128 129 Poll::Ready(Ok(())) 130 } 131 } 132