diff options
author | Alice Ryhl <alice@ryhl.io> | 2020-01-07 18:17:01 +0100 |
---|---|---|
committer | Carl Lerche <me@carllerche.com> | 2020-01-07 09:17:01 -0800 |
commit | 780d6f91a0b56c9cbfca01a9a4694f21eb670f96 (patch) | |
tree | f95d4d7d6d61fd1b68f32536750cc7c0b86fc465 /tokio | |
parent | 45da5f3510a61599c89dc458ecc859f13a81e255 (diff) |
docs: improve tokio::io API documentation (#2060)
* Links are added where missing and examples are improved.
* Improve `stdin`, `stdout`, and `stderr` documentation by going
into more details regarding what can go wrong in concurrent
situations and provide examples for `stdout` and `stderr`.
Diffstat (limited to 'tokio')
-rw-r--r-- | tokio/src/io/async_buf_read.rs | 8 | ||||
-rw-r--r-- | tokio/src/io/async_seek.rs | 11 | ||||
-rw-r--r-- | tokio/src/io/async_write.rs | 21 | ||||
-rw-r--r-- | tokio/src/io/split.rs | 8 | ||||
-rw-r--r-- | tokio/src/io/stderr.rs | 43 | ||||
-rw-r--r-- | tokio/src/io/stdin.rs | 8 | ||||
-rw-r--r-- | tokio/src/io/stdout.rs | 51 | ||||
-rw-r--r-- | tokio/src/io/util/async_buf_read_ext.rs | 4 | ||||
-rw-r--r-- | tokio/src/io/util/copy.rs | 4 | ||||
-rw-r--r-- | tokio/src/io/util/empty.rs | 22 | ||||
-rw-r--r-- | tokio/src/io/util/repeat.rs | 20 | ||||
-rw-r--r-- | tokio/src/io/util/sink.rs | 29 |
12 files changed, 174 insertions, 55 deletions
diff --git a/tokio/src/io/async_buf_read.rs b/tokio/src/io/async_buf_read.rs index 1499bd4f..18127351 100644 --- a/tokio/src/io/async_buf_read.rs +++ b/tokio/src/io/async_buf_read.rs @@ -7,9 +7,15 @@ use std::task::{Context, Poll}; /// Read bytes asynchronously. /// -/// This trait inherits from `std::io::BufRead` and indicates that an I/O object is +/// This trait inherits from [`std::io::BufRead`] 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. +/// +/// Utilities for working with `AsyncBufRead` values are provided by +/// [`AsyncBufReadExt`]. +/// +/// [`std::io::BufRead`]: std::io::BufRead +/// [`AsyncBufReadExt`]: crate::io::AsyncBufReadExt pub trait AsyncBufRead: AsyncRead { /// Attempt to return the contents of the internal buffer, filling it with more data /// from the inner reader if it is empty. diff --git a/tokio/src/io/async_seek.rs b/tokio/src/io/async_seek.rs index d36d404f..f3e6fcdc 100644 --- a/tokio/src/io/async_seek.rs +++ b/tokio/src/io/async_seek.rs @@ -5,9 +5,16 @@ use std::task::{Context, Poll}; /// Seek bytes asynchronously. /// -/// This trait is analogous to the `std::io::Seek` trait, but integrates +/// This trait is analogous to the [`std::io::Seek`] trait, but integrates /// with the asynchronous task system. In particular, the `start_seek` -/// method, unlike `Seek::seek`, will not block the calling thread. +/// method, unlike [`Seek::seek`], will not block the calling thread. +/// +/// Utilities for working with `AsyncSeek` values are provided by +/// [`AsyncSeekExt`]. +/// +/// [`std::io::Seek`]: std::io::Seek +/// [`Seek::seek`]: std::io::Seek::seek() +/// [`AsyncSeekExt`]: crate::io::AsyncSeekExt pub trait AsyncSeek { /// Attempt to seek to an offset, in bytes, in a stream. /// diff --git a/tokio/src/io/async_write.rs b/tokio/src/io/async_write.rs index 2d5e4578..8ae7cf84 100644 --- a/tokio/src/io/async_write.rs +++ b/tokio/src/io/async_write.rs @@ -6,11 +6,11 @@ use std::task::{Context, Poll}; /// Writes bytes asynchronously. /// -/// The trait inherits from `std::io::Write` and indicates that an I/O object is +/// The trait inherits from [`std::io::Write`] and indicates that an I/O object is /// **nonblocking**. All non-blocking I/O objects must return an error when /// bytes cannot be written instead of blocking the current thread. /// -/// Specifically, this means that the `poll_write` function will return one of +/// Specifically, this means that the [`poll_write`] function will return one of /// the following: /// /// * `Poll::Ready(Ok(n))` means that `n` bytes of data was immediately @@ -26,14 +26,23 @@ use std::task::{Context, Poll}; /// * `Poll::Ready(Err(e))` for other errors are standard I/O errors coming from the /// underlying object. /// -/// This trait importantly means that the `write` method only works in the -/// context of a future's task. The object may panic if used outside of a task. +/// This trait importantly means that the [`write`][stdwrite] method only works in +/// the context of a future's task. The object may panic if used outside of a task. /// -/// Note that this trait also represents that the `Write::flush` method works -/// very similarly to the `write` method, notably that `Ok(())` means that the +/// Note that this trait also represents that the [`Write::flush`][stdflush] method +/// works very similarly to the `write` method, notably that `Ok(())` means that the /// writer has successfully been flushed, a "would block" error means that the /// current task is ready to receive a notification when flushing can make more /// progress, and otherwise normal errors can happen as well. +/// +/// Utilities for working with `AsyncWrite` values are provided by +/// [`AsyncWriteExt`]. +/// +/// [`std::io::Write`]: std::io::Write +/// [`poll_write`]: AsyncWrite::poll_write() +/// [stdwrite]: std::io::Write::write() +/// [stdflush]: std::io::Write::flush() +/// [`AsyncWriteExt`]: crate::io::AsyncWriteExt pub trait AsyncWrite { /// Attempt to write bytes from `buf` into the object. /// diff --git a/tokio/src/io/split.rs b/tokio/src/io/split.rs index 50cd498c..7f21533e 100644 --- a/tokio/src/io/split.rs +++ b/tokio/src/io/split.rs @@ -17,12 +17,12 @@ use std::sync::Arc; use std::task::{Context, Poll}; cfg_io_util! { - /// The readable half of a value returned from `split`. + /// The readable half of a value returned from [`split`](split()). pub struct ReadHalf<T> { inner: Arc<Inner<T>>, } - /// The writable half of a value returned from `split`. + /// The writable half of a value returned from [`split`](split()). pub struct WriteHalf<T> { inner: Arc<Inner<T>>, } @@ -30,8 +30,8 @@ cfg_io_util! { /// Split a single value implementing `AsyncRead + AsyncWrite` into separate /// `AsyncRead` and `AsyncWrite` handles. /// - /// To restore this read/write object from its `split::ReadHalf` and - /// `split::WriteHalf` use `unsplit`. + /// To restore this read/write object from its `ReadHalf` and + /// `WriteHalf` use [`unsplit`](ReadHalf::unsplit()). pub fn split<T>(stream: T) -> (ReadHalf<T>, WriteHalf<T>) where T: AsyncRead + AsyncWrite, diff --git a/tokio/src/io/stderr.rs b/tokio/src/io/stderr.rs index d91dd481..fa5d0fbd 100644 --- a/tokio/src/io/stderr.rs +++ b/tokio/src/io/stderr.rs @@ -9,13 +9,30 @@ use std::task::Poll; cfg_io_std! { /// A handle to the standard error stream of a process. /// - /// The handle implements the [`AsyncWrite`] trait, but beware that concurrent - /// writes to `Stderr` must be executed with care. + /// Concurrent writes to stderr must be executed with care: Only individual + /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular + /// you should be aware that writes using [`write_all`] are not guaranteed + /// to occur as a single write, so multiple threads writing data with + /// [`write_all`] may result in interleaved output. /// /// Created by the [`stderr`] function. /// /// [`stderr`]: stderr() /// [`AsyncWrite`]: AsyncWrite + /// [`write_all`]: crate::io::AsyncWriteExt::write_all() + /// + /// # Examples + /// + /// ``` + /// use tokio::io::{self, AsyncWriteExt}; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut stderr = io::stdout(); + /// stderr.write_all(b"Print some error here.").await?; + /// Ok(()) + /// } + /// ``` #[derive(Debug)] pub struct Stderr { std: Blocking<std::io::Stderr>, @@ -25,6 +42,28 @@ cfg_io_std! { /// /// The returned handle allows writing to standard error from the within the /// Tokio runtime. + /// + /// Concurrent writes to stderr must be executed with care: Only individual + /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular + /// you should be aware that writes using [`write_all`] are not guaranteed + /// to occur as a single write, so multiple threads writing data with + /// [`write_all`] may result in interleaved output. + /// + /// [`AsyncWrite`]: AsyncWrite + /// [`write_all`]: crate::io::AsyncWriteExt::write_all() + /// + /// # Examples + /// + /// ``` + /// use tokio::io::{self, AsyncWriteExt}; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut stderr = io::stdout(); + /// stderr.write_all(b"Print some error here.").await?; + /// Ok(()) + /// } + /// ``` pub fn stderr() -> Stderr { let std = io::stderr(); Stderr { diff --git a/tokio/src/io/stdin.rs b/tokio/src/io/stdin.rs index 81bc5abb..6c937447 100644 --- a/tokio/src/io/stdin.rs +++ b/tokio/src/io/stdin.rs @@ -13,7 +13,7 @@ cfg_io_std! { /// reads of `Stdin` must be executed with care. /// /// As an additional caveat, reading from the handle may block the calling - /// future indefinitely, if there is not enough data available. This makes this + /// future indefinitely if there is not enough data available. This makes this /// handle unsuitable for use in any circumstance where immediate reaction to /// available data is required, e.g. interactive use or when implementing a /// subprocess driven by requests on the standard input. @@ -31,6 +31,12 @@ cfg_io_std! { /// /// The returned handle allows reading from standard input from the within the /// Tokio runtime. + /// + /// As an additional caveat, reading from the handle may block the calling + /// future indefinitely if there is not enough data available. This makes this + /// handle unsuitable for use in any circumstance where immediate reaction to + /// available data is required, e.g. interactive use or when implementing a + /// subprocess driven by requests on the standard input. pub fn stdin() -> Stdin { let std = io::stdin(); Stdin { diff --git a/tokio/src/io/stdout.rs b/tokio/src/io/stdout.rs index 86de1c58..ff1bfd5d 100644 --- a/tokio/src/io/stdout.rs +++ b/tokio/src/io/stdout.rs @@ -9,13 +9,30 @@ use std::task::Poll; cfg_io_std! { /// A handle to the standard output stream of a process. /// - /// The handle implements the [`AsyncWrite`] trait, but beware that concurrent - /// writes to `Stdout` must be executed with care. + /// Concurrent writes to stdout must be executed with care: Only individual + /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular + /// you should be aware that writes using [`write_all`] are not guaranteed + /// to occur as a single write, so multiple threads writing data with + /// [`write_all`] may result in interleaved output. /// /// Created by the [`stdout`] function. /// - /// [`stdout`]: fn.stdout.html - /// [`AsyncWrite`]: trait.AsyncWrite.html + /// [`stdout`]: stdout() + /// [`AsyncWrite`]: AsyncWrite + /// [`write_all`]: crate::io::AsyncWriteExt::write_all() + /// + /// # Examples + /// + /// ``` + /// use tokio::io::{self, AsyncWriteExt}; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut stdout = io::stdout(); + /// stdout.write_all(b"Hello world!").await?; + /// Ok(()) + /// } + /// ``` #[derive(Debug)] pub struct Stdout { std: Blocking<std::io::Stdout>, @@ -23,8 +40,30 @@ cfg_io_std! { /// Constructs a new handle to the standard output of the current process. /// - /// The returned handle allows writing to standard out from the within the Tokio - /// runtime. + /// The returned handle allows writing to standard out from the within the + /// Tokio runtime. + /// + /// Concurrent writes to stdout must be executed with care: Only individual + /// writes to this [`AsyncWrite`] are guaranteed to be intact. In particular + /// you should be aware that writes using [`write_all`] are not guaranteed + /// to occur as a single write, so multiple threads writing data with + /// [`write_all`] may result in interleaved output. + /// + /// [`AsyncWrite`]: AsyncWrite + /// [`write_all`]: crate::io::AsyncWriteExt::write_all() + /// + /// # Examples + /// + /// ``` + /// use tokio::io::{self, AsyncWriteExt}; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let mut stdout = io::stdout(); + /// stdout.write_all(b"Hello world!").await?; + /// Ok(()) + /// } + /// ``` pub fn stdout() -> Stdout { let std = io::stdout(); Stdout { diff --git a/tokio/src/io/util/async_buf_read_ext.rs b/tokio/src/io/util/async_buf_read_ext.rs index b2930652..90789744 100644 --- a/tokio/src/io/util/async_buf_read_ext.rs +++ b/tokio/src/io/util/async_buf_read_ext.rs @@ -5,7 +5,9 @@ use crate::io::util::split::{split, Split}; use crate::io::AsyncBufRead; cfg_io_util! { - /// An extension trait which adds utility methods to `AsyncBufRead` types. + /// An extension trait which adds utility methods to [`AsyncBufRead`] types. + /// + /// [`AsyncBufRead`]: crate::io::AsyncBufRead pub trait AsyncBufReadExt: AsyncBufRead { /// Read all bytes into `buf` until the delimiter `byte` or EOF is reached. /// diff --git a/tokio/src/io/util/copy.rs b/tokio/src/io/util/copy.rs index 0a2aea73..8e0058c1 100644 --- a/tokio/src/io/util/copy.rs +++ b/tokio/src/io/util/copy.rs @@ -36,6 +36,8 @@ cfg_io_util! { /// /// This is an asynchronous version of [`std::io::copy`][std]. /// + /// [std]: std::io::copy + /// /// # Errors /// /// The returned future will finish with an error will return an error @@ -56,8 +58,6 @@ cfg_io_util! { /// # Ok(()) /// # } /// ``` - /// - /// [std]: std::io::copy pub fn copy<'a, R, W>(reader: &'a mut R, writer: &'a mut W) -> Copy<'a, R, W> where R: AsyncRead + Unpin + ?Sized, diff --git a/tokio/src/io/util/empty.rs b/tokio/src/io/util/empty.rs index 054d8e60..7075612f 100644 --- a/tokio/src/io/util/empty.rs +++ b/tokio/src/io/util/empty.rs @@ -6,7 +6,7 @@ use std::pin::Pin; use std::task::{Context, Poll}; cfg_io_util! { - // An async reader which is always at EOF. + /// An async reader which is always at EOF. /// /// This struct is generally created by calling [`empty`]. Please see /// the documentation of [`empty()`][`empty`] for more details. @@ -14,7 +14,7 @@ cfg_io_util! { /// This is an asynchronous version of [`std::io::empty`][std]. /// /// [`empty`]: fn.empty.html - /// [std]: https://doc.rust-lang.org/std/io/struct.Empty.html + /// [std]: std::io::empty pub struct Empty { _p: (), } @@ -25,20 +25,22 @@ cfg_io_util! { /// /// This is an asynchronous version of [`std::io::empty`][std]. /// + /// [std]: std::io::empty + /// /// # Examples /// /// A slightly sad example of not reading anything into a buffer: /// - /// ```rust - /// # use tokio::io::{self, AsyncReadExt}; - /// # async fn dox() { - /// let mut buffer = String::new(); - /// io::empty().read_to_string(&mut buffer).await.unwrap(); - /// assert!(buffer.is_empty()); - /// # } /// ``` + /// use tokio::io::{self, AsyncReadExt}; /// - /// [std]: https://doc.rust-lang.org/std/io/fn.empty.html + /// #[tokio::main] + /// async fn main() { + /// let mut buffer = String::new(); + /// io::empty().read_to_string(&mut buffer).await.unwrap(); + /// assert!(buffer.is_empty()); + /// } + /// ``` pub fn empty() -> Empty { Empty { _p: () } } diff --git a/tokio/src/io/util/repeat.rs b/tokio/src/io/util/repeat.rs index a74a153b..064775ee 100644 --- a/tokio/src/io/util/repeat.rs +++ b/tokio/src/io/util/repeat.rs @@ -14,7 +14,7 @@ cfg_io_util! { /// This is an asynchronous version of [`std::io::Repeat`][std]. /// /// [repeat]: fn.repeat.html - /// [std]: https://doc.rust-lang.org/std/io/struct.Repeat.html + /// [std]: std::io::Repeat #[derive(Debug)] pub struct Repeat { byte: u8, @@ -27,18 +27,20 @@ cfg_io_util! { /// /// This is an asynchronous version of [`std::io::repeat`][std]. /// + /// [std]: std::io::repeat + /// /// # Examples /// /// ``` - /// # use tokio::io::{self, AsyncReadExt}; - /// # async fn dox() { - /// let mut buffer = [0; 3]; - /// io::repeat(0b101).read_exact(&mut buffer).await.unwrap(); - /// assert_eq!(buffer, [0b101, 0b101, 0b101]); - /// # } - /// ``` + /// use tokio::io::{self, AsyncReadExt}; /// - /// [std]: https://doc.rust-lang.org/std/io/fn.repeat.html + /// #[tokio::main] + /// async fn main() { + /// let mut buffer = [0; 3]; + /// io::repeat(0b101).read_exact(&mut buffer).await.unwrap(); + /// assert_eq!(buffer, [0b101, 0b101, 0b101]); + /// } + /// ``` pub fn repeat(byte: u8) -> Repeat { Repeat { byte } } diff --git a/tokio/src/io/util/sink.rs b/tokio/src/io/util/sink.rs index 74802f97..05ee773f 100644 --- a/tokio/src/io/util/sink.rs +++ b/tokio/src/io/util/sink.rs @@ -11,9 +11,10 @@ cfg_io_util! { /// This struct is generally created by calling [`sink`][sink]. Please /// see the documentation of `sink()` for more details. /// - /// This is an asynchronous version of `std::io::Sink`. + /// This is an asynchronous version of [`std::io::Sink`][std]. /// - /// [sink]: fn.sink.html + /// [sink]: sink() + /// [std]: std::io::Sink pub struct Sink { _p: (), } @@ -21,21 +22,27 @@ cfg_io_util! { /// Creates an instance of an async writer which will successfully consume all /// data. /// - /// All calls to `poll_write` on the returned instance will return + /// All calls to [`poll_write`] on the returned instance will return /// `Poll::Ready(Ok(buf.len()))` and the contents of the buffer will not be /// inspected. /// - /// This is an asynchronous version of `std::io::sink`. + /// This is an asynchronous version of [`std::io::sink`][std]. + /// + /// [`poll_write`]: crate::io::AsyncWrite::poll_write() + /// [std]: std::io::sink /// /// # Examples /// - /// ```rust - /// # use tokio::io::{self, AsyncWriteExt}; - /// # async fn dox() { - /// let buffer = vec![1, 2, 3, 5, 8]; - /// let num_bytes = io::sink().write(&buffer).await.unwrap(); - /// assert_eq!(num_bytes, 5); - /// # } + /// ``` + /// use tokio::io::{self, AsyncWriteExt}; + /// + /// #[tokio::main] + /// async fn main() -> io::Result<()> { + /// let buffer = vec![1, 2, 3, 5, 8]; + /// let num_bytes = io::sink().write(&buffer).await?; + /// assert_eq!(num_bytes, 5); + /// Ok(()) + /// } /// ``` pub fn sink() -> Sink { Sink { _p: () } |