|
1 | 1 | //! In-process memory IO types.
|
2 | 2 |
|
3 |
| -use crate::io::{AsyncRead, AsyncWrite, ReadBuf}; |
| 3 | +use crate::io::{split, AsyncRead, AsyncWrite, ReadBuf, ReadHalf, WriteHalf}; |
4 | 4 | use crate::loom::sync::Mutex;
|
5 | 5 |
|
6 | 6 | use bytes::{Buf, BytesMut};
|
@@ -47,15 +47,34 @@ use std::{
|
47 | 47 | #[derive(Debug)]
|
48 | 48 | #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
49 | 49 | pub struct DuplexStream {
|
50 |
| - read: Arc<Mutex<Pipe>>, |
51 |
| - write: Arc<Mutex<Pipe>>, |
| 50 | + read: Arc<Mutex<SimplexStream>>, |
| 51 | + write: Arc<Mutex<SimplexStream>>, |
52 | 52 | }
|
53 | 53 |
|
54 |
| -/// A unidirectional IO over a piece of memory. |
| 54 | +/// A unidirectional pipe to read and write bytes in memory. |
55 | 55 | ///
|
56 |
| -/// Data can be written to the pipe, and reading will return that data. |
| 56 | +/// It can be constructed by [`simplex`] function which will create a pair of |
| 57 | +/// reader and writer or by calling [`SimplexStream::new_unsplit`] that will |
| 58 | +/// create a handle for both reading and writing. |
| 59 | +/// |
| 60 | +/// # Example |
| 61 | +/// |
| 62 | +/// ``` |
| 63 | +/// # async fn ex() -> std::io::Result<()> { |
| 64 | +/// # use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
| 65 | +/// let (mut receiver, mut sender) = tokio::io::simplex(64); |
| 66 | +/// |
| 67 | +/// sender.write_all(b"ping").await?; |
| 68 | +/// |
| 69 | +/// let mut buf = [0u8; 4]; |
| 70 | +/// receiver.read_exact(&mut buf).await?; |
| 71 | +/// assert_eq!(&buf, b"ping"); |
| 72 | +/// # Ok(()) |
| 73 | +/// # } |
| 74 | +/// ``` |
57 | 75 | #[derive(Debug)]
|
58 |
| -struct Pipe { |
| 76 | +#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] |
| 77 | +pub struct SimplexStream { |
59 | 78 | /// The buffer storing the bytes written, also read from.
|
60 | 79 | ///
|
61 | 80 | /// Using a `BytesMut` because it has efficient `Buf` and `BufMut`
|
@@ -83,8 +102,8 @@ struct Pipe {
|
83 | 102 | /// written to a side before the write returns `Poll::Pending`.
|
84 | 103 | #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))]
|
85 | 104 | pub fn duplex(max_buf_size: usize) -> (DuplexStream, DuplexStream) {
|
86 |
| - let one = Arc::new(Mutex::new(Pipe::new(max_buf_size))); |
87 |
| - let two = Arc::new(Mutex::new(Pipe::new(max_buf_size))); |
| 105 | + let one = Arc::new(Mutex::new(SimplexStream::new_unsplit(max_buf_size))); |
| 106 | + let two = Arc::new(Mutex::new(SimplexStream::new_unsplit(max_buf_size))); |
88 | 107 |
|
89 | 108 | (
|
90 | 109 | DuplexStream {
|
@@ -161,11 +180,47 @@ impl Drop for DuplexStream {
|
161 | 180 | }
|
162 | 181 | }
|
163 | 182 |
|
164 |
| -// ===== impl Pipe ===== |
| 183 | +// ===== impl SimplexStream ===== |
| 184 | + |
| 185 | +/// Creates unidirectional buffer that acts like in memory pipe. |
| 186 | +/// |
| 187 | +/// The `max_buf_size` argument is the maximum amount of bytes that can be |
| 188 | +/// written to a buffer before the it returns `Poll::Pending`. |
| 189 | +/// |
| 190 | +/// # Unify reader and writer |
| 191 | +/// |
| 192 | +/// The reader and writer half can be unified into a single structure |
| 193 | +/// of `SimplexStream` that supports both reading and writing or |
| 194 | +/// the `SimplexStream` can be already created as unified structure |
| 195 | +/// using [`SimplexStream::new_unsplit()`]. |
| 196 | +/// |
| 197 | +/// ``` |
| 198 | +/// # async fn ex() -> std::io::Result<()> { |
| 199 | +/// # use tokio::io::{AsyncReadExt, AsyncWriteExt}; |
| 200 | +/// let (writer, reader) = tokio::io::simplex(64); |
| 201 | +/// let mut simplex_stream = writer.unsplit(reader); |
| 202 | +/// simplex_stream.write_all(b"hello").await?; |
| 203 | +/// |
| 204 | +/// let mut buf = [0u8; 5]; |
| 205 | +/// simplex_stream.read_exact(&mut buf).await?; |
| 206 | +/// assert_eq!(&buf, b"hello"); |
| 207 | +/// # Ok(()) |
| 208 | +/// # } |
| 209 | +/// ``` |
| 210 | +#[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] |
| 211 | +pub fn simplex(max_buf_size: usize) -> (ReadHalf<SimplexStream>, WriteHalf<SimplexStream>) { |
| 212 | + split(SimplexStream::new_unsplit(max_buf_size)) |
| 213 | +} |
165 | 214 |
|
166 |
| -impl Pipe { |
167 |
| - fn new(max_buf_size: usize) -> Self { |
168 |
| - Pipe { |
| 215 | +impl SimplexStream { |
| 216 | + /// Creates unidirectional buffer that acts like in memory pipe. To create split |
| 217 | + /// version with separate reader and writer you can use [`simplex`] function. |
| 218 | + /// |
| 219 | + /// The `max_buf_size` argument is the maximum amount of bytes that can be |
| 220 | + /// written to a buffer before the it returns `Poll::Pending`. |
| 221 | + #[cfg_attr(docsrs, doc(cfg(feature = "io-util")))] |
| 222 | + pub fn new_unsplit(max_buf_size: usize) -> SimplexStream { |
| 223 | + SimplexStream { |
169 | 224 | buffer: BytesMut::new(),
|
170 | 225 | is_closed: false,
|
171 | 226 | max_buf_size,
|
@@ -269,7 +324,7 @@ impl Pipe {
|
269 | 324 | }
|
270 | 325 | }
|
271 | 326 |
|
272 |
| -impl AsyncRead for Pipe { |
| 327 | +impl AsyncRead for SimplexStream { |
273 | 328 | cfg_coop! {
|
274 | 329 | fn poll_read(
|
275 | 330 | self: Pin<&mut Self>,
|
@@ -299,7 +354,7 @@ impl AsyncRead for Pipe {
|
299 | 354 | }
|
300 | 355 | }
|
301 | 356 |
|
302 |
| -impl AsyncWrite for Pipe { |
| 357 | +impl AsyncWrite for SimplexStream { |
303 | 358 | cfg_coop! {
|
304 | 359 | fn poll_write(
|
305 | 360 | self: Pin<&mut Self>,
|
|
0 commit comments