mirror of
https://github.com/tokio-rs/tokio.git
synced 2025-10-01 12:20:39 +00:00
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`.
This commit is contained in:
parent
45da5f3510
commit
780d6f91a0
@ -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.
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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,
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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,
|
||||
|
@ -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: () }
|
||||
}
|
||||
|
@ -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 }
|
||||
}
|
||||
|
@ -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: () }
|
||||
|
Loading…
x
Reference in New Issue
Block a user