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