join_read_write.rs
1 //! Join a readable and writeable into a single `AsyncRead` + `AsyncWrite` 2 3 use std::io::Error; 4 use std::pin::Pin; 5 use std::task::{Context, Poll}; 6 7 use futures::{AsyncRead, AsyncWrite}; 8 use pin_project::pin_project; 9 10 /// Async readable/writeable that dispatches reads to `R` and writes to `W` 11 /// 12 /// `AsyncRead` is forwarded to `R`. 13 /// `AsyncWrite` is forwarded to `W`. 14 /// 15 /// [`JoinReadWrite::new()`] is the converse of 16 /// [`AsyncReadExt::split()`](futures::AsyncReadExt::split). 17 /// But, if `R` and `W` came from splitting a single `AsyncRead + AsyncWrite`, 18 /// you probably want the `reunite` or `unsplit` method, instead of `JoinReadWrite`. 19 /// 20 /// Does *not* implement any kind of flushing behaviour when switching between reading and writing. 21 /// 22 /// # Example 23 /// 24 /// ``` 25 /// # #[tokio::main] 26 /// # async fn main() { 27 /// use tor_async_utils::JoinReadWrite; 28 /// use futures::{AsyncReadExt as _, AsyncWriteExt as _}; 29 /// 30 /// let read = b"hello\n"; 31 /// let mut read = &read[..]; 32 /// let mut write = Vec::<u8>::new(); 33 /// 34 /// let mut joined = JoinReadWrite::new(read, write); 35 /// 36 /// let mut got = String::new(); 37 /// let _: usize = joined.read_to_string(&mut got).await.unwrap(); 38 /// assert_eq!(got, "hello\n"); 39 /// 40 /// let () = joined.write_all(b"some data").await.unwrap(); 41 /// 42 /// let (r, w) = joined.into_parts(); 43 /// assert_eq!(w, b"some data"); 44 /// # } 45 /// ``` 46 #[pin_project] 47 pub struct JoinReadWrite<R: AsyncRead, W: AsyncWrite> { 48 /// readable 49 #[pin] 50 r: R, 51 /// writeable 52 #[pin] 53 w: W, 54 } 55 56 impl<R: AsyncRead, W: AsyncWrite> JoinReadWrite<R, W> { 57 /// Join an `AsyncRead` and an `AsyncWrite` into a single `impl AsyncRead + AsyncWrite` 58 pub fn new(r: R, w: W) -> Self { 59 JoinReadWrite { r, w } 60 } 61 62 /// Dismantle a `JoinReadWrite` into its constituent `AsyncRead` and `AsyncWrite` 63 pub fn into_parts(self) -> (R, W) { 64 let JoinReadWrite { r, w } = self; 65 (r, w) 66 } 67 } 68 69 impl<R: AsyncRead, W: AsyncWrite> AsyncRead for JoinReadWrite<R, W> { 70 fn poll_read( 71 self: Pin<&mut Self>, 72 c: &mut Context, 73 out: &mut [u8], 74 ) -> Poll<Result<usize, Error>> { 75 self.project().r.poll_read(c, out) 76 } 77 } 78 79 impl<R: AsyncRead, W: AsyncWrite> AsyncWrite for JoinReadWrite<R, W> { 80 fn poll_write( 81 self: Pin<&mut Self>, 82 c: &mut Context, 83 data: &[u8], 84 ) -> Poll<Result<usize, Error>> { 85 self.project().w.poll_write(c, data) 86 } 87 88 fn poll_flush(self: Pin<&mut Self>, c: &mut Context) -> Poll<Result<(), Error>> { 89 self.project().w.poll_flush(c) 90 } 91 92 fn poll_close(self: Pin<&mut Self>, c: &mut Context) -> Poll<Result<(), Error>> { 93 self.project().w.poll_close(c) 94 } 95 }