summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCarl Lerche <me@carllerche.com>2019-11-23 08:24:03 -0800
committerGitHub <noreply@github.com>2019-11-23 08:24:03 -0800
commit3ecaa6d91cef271b4c079a2e28bc3270280bcee6 (patch)
tree93c6eb135a0566e77c39e15120106b60b0565cae
parent0bc68adb34fb981f213b81abac63d6375e513d48 (diff)
docs: improve tokio::io API documentation (#1815)
Adds method level documentation for `tokio::io`.
-rw-r--r--examples/proxy.rs17
-rw-r--r--tokio/src/io/async_read.rs18
-rw-r--r--tokio/src/io/mod.rs27
-rw-r--r--tokio/src/io/util/async_read_ext.rs313
-rw-r--r--tokio/src/io/util/async_write_ext.rs174
-rw-r--r--tokio/src/prelude.rs2
-rw-r--r--tokio/tests/buffered.rs2
-rw-r--r--tokio/tests/io_copy.rs5
-rw-r--r--tokio/tests/tcp_echo.rs2
-rw-r--r--tokio/tests/tcp_shutdown.rs4
10 files changed, 493 insertions, 71 deletions
diff --git a/examples/proxy.rs b/examples/proxy.rs
index 4314d1b9..48f8f057 100644
--- a/examples/proxy.rs
+++ b/examples/proxy.rs
@@ -22,12 +22,13 @@
#![warn(rust_2018_idioms)]
-use futures::{future::try_join, FutureExt};
-use std::{env, error::Error};
-use tokio::{
- io::AsyncReadExt,
- net::{TcpListener, TcpStream},
-};
+use tokio::io;
+use tokio::net::{TcpListener, TcpStream};
+
+use futures::future::try_join;
+use futures::FutureExt;
+use std::env;
+use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
@@ -58,8 +59,8 @@ async fn transfer(mut inbound: TcpStream, proxy_addr: String) -> Result<(), Box<
let (mut ri, mut wi) = inbound.split();
let (mut ro, mut wo) = outbound.split();
- let client_to_server = ri.copy(&mut wo);
- let server_to_client = ro.copy(&mut wi);
+ let client_to_server = io::copy(&mut ri, &mut wo);
+ let server_to_client = io::copy(&mut ro, &mut wi);
try_join(client_to_server, server_to_client).await?;
diff --git a/tokio/src/io/async_read.rs b/tokio/src/io/async_read.rs
index d7e703d4..d28280a5 100644
--- a/tokio/src/io/async_read.rs
+++ b/tokio/src/io/async_read.rs
@@ -5,11 +5,13 @@ use std::ops::DerefMut;
use std::pin::Pin;
use std::task::{Context, Poll};
-/// Read bytes asynchronously.
+/// Read bytes from a source.
///
-/// This trait inherits from `std::io::Read` 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.
+/// This trait is analogous to the [`std::io::Read`] trait, but integrates with
+/// the asynchronous task system. In particular, the [`poll_read`] method,
+/// unlike [`Read::read`], will automatically queue the current task for wakeup
+/// and return if data is not yet available, rather than blocking the calling
+/// thread.
///
/// Specifically, this means that the `poll_read` function will return one of
/// the following:
@@ -30,6 +32,14 @@ use std::task::{Context, Poll};
///
/// This trait importantly means that the `read` method only works in the
/// context of a future's task. The object may panic if used outside of a task.
+///
+/// Utilities for working with `AsyncRead` values are provided by
+/// [`AsyncReadExt`].
+///
+/// [`poll_read`]: AsyncRead::poll_read
+/// [`std::io::Read`]: std::io::Read
+/// [`Read::read`]: std::io::Read::read
+/// [`AsyncReadExt`]: crate::io::AsyncReadExt
pub trait AsyncRead {
/// Prepares an uninitialized buffer to be safe to pass to `read`. Returns
/// `true` if the supplied buffer was zeroed out.
diff --git a/tokio/src/io/mod.rs b/tokio/src/io/mod.rs
index 627e643f..29d700b1 100644
--- a/tokio/src/io/mod.rs
+++ b/tokio/src/io/mod.rs
@@ -1,6 +1,6 @@
#![cfg_attr(loom, allow(dead_code, unreachable_pub))]
-//! Asynchronous I/O.
+//! Traits, helpers, and type definitions for asynchronous I/O functionality.
//!
//! This module is the asynchronous version of `std::io`. Primarily, it
//! defines two traits, [`AsyncRead`] and [`AsyncWrite`], which are asynchronous
@@ -15,7 +15,19 @@
//! type will _yield_ to the Tokio scheduler when IO is not ready, rather than
//! blocking. This allows other tasks to run while waiting on IO.
//!
-//! In asynchronous programs, Tokio's [`AsyncRead`] and [`AsyncWrite`] traits
+//! Another difference is that [`AsyncRead`] and [`AsyncWrite`] only contain
+//! core methods needed to provide asynchronous reading and writing
+//! functionality. Instead, utility methods are defined in the [`AsyncReadExt`]
+//! and [`AsyncWriteExt`] extension traits. These traits are automatically
+//! implemented for all values that implement [`AsyncRead`] and [`AsyncWrite`]
+//! respectively.
+//!
+//! End users will rarely interact directly with [`AsyncRead`] and
+//! [`AsyncWrite`]. Instead, they will use the async functions defined in the
+//! extension traits. Library authors are expected to implement [`AsyncRead`]
+//! and [`AsyncWrite`] in order to provide types that behave like byte streams.
+//!
+//! Even with these differences, Tokio's [`AsyncRead`] and [`AsyncWrite`] traits
//! can be used in almost exactly the same manner as the standard library's
//! `Read` and `Write`. Most types in the standard library that implement `Read`
//! and `Write` have asynchronous equivalents in `tokio` that implement
@@ -26,8 +38,7 @@
//! can do the same with [`tokio::fs::File`][`File`]:
//!
//! ```no_run
-//! use tokio::io;
-//! use tokio::prelude::*;
+//! use tokio::io::{self, AsyncReadExt};
//! use tokio::fs::File;
//!
//! #[tokio::main]
@@ -64,10 +75,8 @@
//! extra methods to any async reader:
//!
//! ```no_run
-//! use tokio::io;
-//! use tokio::io::BufReader;
+//! use tokio::io::{self, BufReader, AsyncBufReadExt};
//! use tokio::fs::File;
-//! use tokio::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
@@ -87,10 +96,8 @@
//! to [`write`](crate::io::AsyncWriteExt::write):
//!
//! ```no_run
-//! use tokio::io;
-//! use tokio::io::BufWriter;
+//! use tokio::io::{self, BufWriter, AsyncWriteExt};
//! use tokio::fs::File;
-//! use tokio::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> io::Result<()> {
diff --git a/tokio/src/io/util/async_read_ext.rs b/tokio/src/io/util/async_read_ext.rs
index faac42d9..fe1e646e 100644
--- a/tokio/src/io/util/async_read_ext.rs
+++ b/tokio/src/io/util/async_read_ext.rs
@@ -1,20 +1,70 @@
use crate::io::util::chain::{chain, Chain};
-use crate::io::util::copy::{copy, Copy};
use crate::io::util::read::{read, Read};
use crate::io::util::read_exact::{read_exact, ReadExact};
use crate::io::util::read_to_end::{read_to_end, ReadToEnd};
use crate::io::util::read_to_string::{read_to_string, ReadToString};
use crate::io::util::take::{take, Take};
-use crate::io::{AsyncRead, AsyncWrite};
+use crate::io::AsyncRead;
cfg_io_util! {
- /// An extension trait which adds utility methods to `AsyncRead` types.
+ /// Read bytes from a source.
+ ///
+ /// Implemented as an extention trait, adding utility methods to all
+ /// [`AsyncRead`] types. Callers will tend to import this trait instead of
+ /// [`AsyncRead`].
+ ///
+ /// As a convenience, this trait may be imported using the [`prelude`]:
+ ///
+ /// ```no_run
+ /// use tokio::fs::File;
+ /// use tokio::prelude::*;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt").await?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // The `read` method is defined by this trait.
+ /// let n = f.read(&mut buffer[..]).await?;
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// See [module][crate::io] documentation for more details.
+ ///
+ /// [`AsyncRead`]: AsyncRead
+ /// [`prelude`]: crate::prelude
pub trait AsyncReadExt: AsyncRead {
- /// Creates an adaptor which will chain this stream with another.
+ /// Create a new `AsyncRead` instance that chains this stream with
+ /// `next`.
///
/// The returned `AsyncRead` instance will first read all bytes from this object
/// until EOF is encountered. Afterwards the output is equivalent to the
/// output of `next`.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `AsyncRead`:
+ ///
+ /// ```no_run
+ /// use tokio::fs::File;
+ /// use tokio::io::{self, AsyncReadExt};
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let f1 = File::open("foo.txt").await?;
+ /// let f2 = File::open("bar.txt").await?;
+ ///
+ /// let mut handle = f1.chain(f2);
+ /// let mut buffer = String::new();
+ ///
+ /// // read the value into a String. We could use any AsyncRead
+ /// // method here, this is just one example.
+ /// handle.read_to_string(&mut buffer).await?;
+ /// Ok(())
+ /// }
+ /// ```
fn chain<R>(self, next: R) -> Chain<Self, R>
where
Self: Sized,
@@ -23,56 +73,222 @@ cfg_io_util! {
chain(self, next)
}
- /// Copy all data from `self` into the provided `AsyncWrite`.
+ /// Pull some bytes from this source into the specified buffer,
+ /// returning how many bytes were read.
///
- /// The returned future will copy all the bytes read from `reader` into the
- /// `writer` specified. This future will only complete once the `reader`
- /// has hit EOF and all bytes have been written to and flushed from the
- /// `writer` provided.
+ /// Equivalent to:
///
- /// On success the number of bytes is returned and the `reader` and `writer`
- /// are consumed. On error the error is returned and the I/O objects are
- /// consumed as well.
- fn copy<'a, W>(&'a mut self, dst: &'a mut W) -> Copy<'a, Self, W>
- where
- Self: Unpin,
- W: AsyncWrite + Unpin + ?Sized,
- {
- copy(self, dst)
- }
-
- /// Read data into the provided buffer.
+ /// ```ignore
+ /// async fn read(&mut self, buf: &mut [u8]) -> io::Result<usize>;
+ /// ```
+ ///
+ /// This function does not provide any guarantees about whether it
+ /// completes immediately or asynchronously
+ ///
+ /// If the return value of this method is `Ok(n)`, then it must be
+ /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
+ /// that the buffer `buf` has been filled in with `n` bytes of data from
+ /// this source. If `n` is `0`, then it can indicate one of two
+ /// scenarios:
+ ///
+ /// 1. This reader has reached its "end of file" and will likely no longer
+ /// be able to produce bytes. Note that this does not mean that the
+ /// reader will *always* no longer be able to produce bytes.
+ /// 2. The buffer specified was 0 bytes in length.
+ ///
+ /// No guarantees are provided about the contents of `buf` when this
+ /// function is called, implementations cannot rely on any property of the
+ /// contents of `buf` being true. It is recommended that *implementations*
+ /// only write data to `buf` instead of reading its contents.
+ ///
+ /// Correspondingly, however, *callers* of this method may not assume
+ /// any guarantees about how the implementation uses `buf`. It is
+ /// possible that the code that's supposed to write to the buffer might
+ /// also read from it. It is your responsibility to make sure that `buf`
+ /// is initialized before calling `read`.
+ ///
+ /// # Errors
///
- /// The returned future will resolve to the number of bytes read once the
- /// read operation is completed.
- fn read<'a>(&'a mut self, dst: &'a mut [u8]) -> Read<'a, Self>
+ /// If this function encounters any form of I/O or other error, an error
+ /// variant will be returned. If an error is returned then it must be
+ /// guaranteed that no bytes were read.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `Read`:
+ ///
+ /// ```no_run
+ /// use tokio::fs::File;
+ /// use tokio::io::{self, AsyncReadExt};
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt").await?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // read up to 10 bytes
+ /// let n = f.read(&mut buffer[..]).await?;
+ ///
+ /// println!("The bytes: {:?}", &buffer[..n]);
+ /// Ok(())
+ /// }
+ /// ```
+ fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>
where
Self: Unpin,
{
- read(self, dst)
+ read(self, buf)
}
- /// Read exactly the amount of data needed to fill the provided buffer.
- fn read_exact<'a>(&'a mut self, dst: &'a mut [u8]) -> ReadExact<'a, Self>
+ /// Read the exact number of bytes required to fill `buf`.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<usize>;
+ /// ```
+ ///
+ /// This function reads as many bytes as necessary to completely fill
+ /// the specified buffer `buf`.
+ ///
+ /// No guarantees are provided about the contents of `buf` when this
+ /// function is called, implementations cannot rely on any property of
+ /// the contents of `buf` being true. It is recommended that
+ /// implementations only write data to `buf` instead of reading its
+ /// contents.
+ ///
+ /// # Errors
+ ///
+ /// If the operation encounters an "end of file" before completely
+ /// filling the buffer, it returns an error of the kind
+ /// [`ErrorKind::UnexpectedEof`]. The contents of `buf` are unspecified
+ /// in this case.
+ ///
+ /// If any other read error is encountered then the operation
+ /// immediately returns. The contents of `buf` are unspecified in this
+ /// case.
+ ///
+ /// If this operation returns an error, it is unspecified how many bytes
+ /// it has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `Read`:
+ ///
+ /// ```no_run
+ /// use tokio::fs::File;
+ /// use tokio::io::{self, AsyncReadExt};
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt").await?;
+ /// let mut buffer = [0; 10];
+ ///
+ /// // read exactly 10 bytes
+ /// f.read_exact(&mut buffer).await?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`ErrorKind::UnexpectedEof`]: std::io::ErrorKind::UnexpectedEof
+ fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>
where
Self: Unpin,
{
- read_exact(self, dst)
+ read_exact(self, buf)
}
- /// Read all bytes until EOF in this source, placing them into `dst`.
+ /// Read all bytes until EOF in this source, placing them into `buf`.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize>;
+ /// ```
+ ///
+ /// All bytes read from this source will be appended to the specified
+ /// buffer `buf`. This function will continuously call [`read()`] to
+ /// append more data to `buf` until [`read()`][read] returns `Ok(0)`.
+ ///
+ /// If successful, the total number of bytes read is returned.
+ ///
+ /// # Errors
+ ///
+ /// If a read error is encountered then the `read_to_end` operation
+ /// immediately completes. Any bytes which have already been read will
+ /// be appended to `buf`.
///
- /// On success the total number of bytes read is returned.
- fn read_to_end<'a>(&'a mut self, dst: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `Read`:
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, AsyncReadExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt").await?;
+ /// let mut buffer = Vec::new();
+ ///
+ /// // read the whole file
+ /// f.read_to_end(&mut buffer).await?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// (See also the [`tokio::fs::read`] convenience function for reading from a
+ /// file.)
+ ///
+ /// [`tokio::fs::read`]: crate::fs::read::read
+ fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>
where
Self: Unpin,
{
- read_to_end(self, dst)
+ read_to_end(self, buf)
}
- /// Read all bytes until EOF in this source, placing them into `dst`.
+ /// Read all bytes until EOF in this source, appending them to `buf`.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize>;
+ /// ```
///
- /// On success the total number of bytes read is returned.
+ /// If successful, the number of bytes which were read and appended to
+ /// `buf` is returned.
+ ///
+ /// # Errors
+ ///
+ /// If the data in this stream is *not* valid UTF-8 then an error is
+ /// returned and `buf` is unchanged.
+ ///
+ /// See [`read_to_end`][AsyncReadExt::read_to_end] for other error semantics.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `Read`:
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, AsyncReadExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut f = File::open("foo.txt").await?;
+ /// let mut buffer = String::new();
+ ///
+ /// f.read_to_string(&mut buffer).await?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// (See also the [`crate::fs::read_to_string`] convenience function for
+ /// reading from a file.)
+ ///
+ /// [`crate::fs::read_to_string`]: crate::fs::read_to_string::read_to_string
fn read_to_string<'a>(&'a mut self, dst: &'a mut String) -> ReadToString<'a, Self>
where
Self: Unpin,
@@ -80,8 +296,33 @@ cfg_io_util! {
read_to_string(self, dst)
}
- /// Creates an AsyncRead adapter which will read at most `limit` bytes
- /// from the underlying reader.
+ /// Creates an adaptor which reads at most `limit` bytes from it.
+ ///
+ /// This function returns a new instance of `AsyncRead` which will read
+ /// at most `limit` bytes, after which it will always return EOF
+ /// (`Ok(0)`). Any read errors will not count towards the number of
+ /// bytes read and future calls to [`read()`][read] may succeed.
+ ///
+ /// # Examples
+ ///
+ /// [`File`][crate::fs::File]s implement `Read`:
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, AsyncReadExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let f = File::open("foo.txt").await?;
+ /// let mut buffer = [0; 5];
+ ///
+ /// // read at most five bytes
+ /// let mut handle = f.take(5);
+ ///
+ /// handle.read(&mut buffer).await?;
+ /// Ok(())
+ /// }
+ /// ```
fn take(self, limit: u64) -> Take<Self>
where
Self: Sized,
diff --git a/tokio/src/io/util/async_write_ext.rs b/tokio/src/io/util/async_write_ext.rs
index 65374428..82de2576 100644
--- a/tokio/src/io/util/async_write_ext.rs
+++ b/tokio/src/io/util/async_write_ext.rs
@@ -5,9 +5,83 @@ use crate::io::util::write_all::{write_all, WriteAll};
use crate::io::AsyncWrite;
cfg_io_util! {
- /// An extension trait which adds utility methods to `AsyncWrite` types.
+ /// Write bytes to a sink.
+ ///
+ /// Implemented as an extention trait, adding utility methods to all
+ /// [`AsyncWrite`] types. Callers will tend to import this trait instead of
+ /// [`AsyncWrite`].
+ ///
+ /// As a convenience, this trait may be imported using the [`prelude`]:
+ ///
+ /// ```no_run
+ /// use tokio::prelude::*;
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let data = b"some bytes";
+ ///
+ /// let mut pos = 0;
+ /// let mut buffer = File::create("foo.txt").await?;
+ ///
+ /// while pos < data.len() {
+ /// let bytes_written = buffer.write(&data[pos..]).await?;
+ /// pos += bytes_written;
+ /// }
+ ///
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// See [module][crate::io] documentation for more details.
+ ///
+ /// [`AsyncWrite`]: AsyncWrite
+ /// [`prelude`]: crate::prelude
pub trait AsyncWriteExt: AsyncWrite {
- /// Write a buffer into this writter, returning how many bytes were written.
+ /// Write a buffer into this writer, returning how many bytes were
+ /// written.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn write(&mut self, buf: &[u8]) -> io::Result<usize>;
+ /// ```
+ ///
+ /// This function will attempt to write the entire contents of `buf`, but
+ /// the entire write may not succeed, or the write may also generate an
+ /// error. A call to `write` represents *at most one* attempt to write to
+ /// any wrapped object.
+ ///
+ /// If the return value is `Ok(n)` then it must be guaranteed that `n <=
+ /// buf.len()`. A return value of `0` typically means that the
+ /// underlying object is no longer able to accept bytes and will likely
+ /// not be able to in the future as well, or that the buffer provided is
+ /// empty.
+ ///
+ /// # Errors
+ ///
+ /// Each call to `write` may generate an I/O error indicating that the
+ /// operation could not be completed. If an error is returned then no bytes
+ /// in the buffer were written to this writer.
+ ///
+ /// It is **not** considered an error if the entire buffer could not be
+ /// written to this writer.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, AsyncWriteExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut buffer = File::create("foo.txt").await?;
+ ///
+ /// // Writes some prefix of the byte string, not necessarily all of it.
+ /// buffer.write(b"some bytes").await?;
+ /// Ok(())
+ /// }
+ /// ```
fn write<'a>(&'a mut self, src: &'a [u8]) -> Write<'a, Self>
where
Self: Unpin,
@@ -15,7 +89,39 @@ cfg_io_util! {
write(self, src)
}
- /// Attempt to write an entire buffer into this writter.
+ /// Attempts to write an entire buffer into this writer.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn write_all(&mut self, buf: &[u8]) -> io::Result<()>;
+ /// ```
+ ///
+ /// This method will continuously call [`write`] until there is no more data
+ /// to be written. This method will not return until the entire buffer
+ /// has been successfully written or such an error occurs. The first
+ /// error generated from this method will be returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error that [`write`] returns.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, AsyncWriteExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let mut buffer = File::create("foo.txt").await?;
+ ///
+ /// buffer.write_all(b"some bytes").await?;
+ /// Ok(())
+ /// }
+ /// ```
+ ///
+ /// [`write`]: AsyncWriteExt::write
fn write_all<'a>(&'a mut self, src: &'a [u8]) -> WriteAll<'a, Self>
where
Self: Unpin,
@@ -23,7 +129,36 @@ cfg_io_util! {
write_all(self, src)
}
- /// Flush the contents of this writer.
+ /// Flush this output stream, ensuring that all intermediately buffered
+ /// contents reach their destination.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn flush(&mut self) -> io::Result<()>;
+ /// ```
+ ///
+ /// # Errors
+ ///
+ /// It is considered an error if not all bytes could be written due to
+ /// I/O errors or EOF being reached.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, BufWriter, AsyncWriteExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let f = File::create("foo.txt").await?;
+ /// let mut buffer = BufWriter::new(f);
+ ///
+ /// buffer.write_all(b"some bytes").await?;
+ /// buffer.flush().await?;
+ /// Ok(())
+ /// }
+ /// ```
fn flush(&mut self) -> Flush<'_, Self>
where
Self: Unpin,
@@ -31,7 +166,36 @@ cfg_io_util! {
flush(self)
}
- /// Shutdown this writer.
+ /// Shuts down the output stream, ensuring that the value can be dropped
+ /// cleanly.
+ ///
+ /// Equivalent to:
+ ///
+ /// ```ignore
+ /// async fn shutdown(&mut self) -> io::Result<()>;
+ /// ```
+ ///
+ /// Similar to [`flush`], all intermediately buffered is written to the
+ /// underlying stream. Once the operation completes, the caller should
+ /// no longer attempt to write to the stream. For example, the
+ /// `TcpStream` implementation will issue a `shutdown(Write)` sys call.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use tokio::io::{self, BufWriter, AsyncWriteExt};
+ /// use tokio::fs::File;
+ ///
+ /// #[tokio::main]
+ /// async fn main() -> io::Result<()> {
+ /// let f = File::create("foo.txt").await?;
+ /// let mut buffer = BufWriter::new(f);
+ ///
+ /// buffer.write_all(b"some bytes").await?;
+ /// buffer.shutdown().await?;
+ /// Ok(())
+ /// }
+ /// ```
fn shutdown(&mut self) -> Shutdown<'_, Self>
where
Self: Unpin,
diff --git a/tokio/src/prelude.rs b/tokio/src/prelude.rs
index 7e482892..d4e790be 100644
--- a/tokio/src/prelude.rs
+++ b/tokio/src/prelude.rs
@@ -13,7 +13,7 @@
//!
//! The prelude may grow over time as additional items see ubiquitous use.
-pub use crate::io::{AsyncBufRead, AsyncRead, AsyncWrite};
+pub use crate::io::{self, AsyncBufRead, AsyncRead, AsyncWrite};
cfg_io_util! {
#[doc(no_inline)]
diff --git a/tokio/tests/buffered.rs b/tokio/tests/buffered.rs
index 7ce3d01c..595f855a 100644
--- a/tokio/tests/buffered.rs
+++ b/tokio/tests/buffered.rs
@@ -41,7 +41,7 @@ async fn echo_server() {
let (mut a, _) = assert_ok!(srv.accept().await);
let (mut b, _) = assert_ok!(srv.accept().await);
- let n = assert_ok!(a.copy(&mut b).await);
+ let n = assert_ok!(io::copy(&mut a, &mut b).await);
let (expected, t2) = t.join().unwrap();
let actual = t2.join().unwrap();
diff --git a/tokio/tests/io_copy.rs b/tokio/tests/io_copy.rs
index 75d77435..c1c6df4e 100644
--- a/tokio/tests/io_copy.rs
+++ b/tokio/tests/io_copy.rs
@@ -1,10 +1,9 @@
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
-use tokio::io::{AsyncRead, AsyncReadExt};
+use tokio::io::{self, AsyncRead};
use tokio_test::assert_ok;
-use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
@@ -31,7 +30,7 @@ async fn copy() {
let mut rd = Rd(true);
let mut wr = Vec::new();
- let n = assert_ok!(rd.copy(&mut wr).await);
+ let n = assert_ok!(io::copy(&mut rd, &mut wr).await);
assert_eq!(n, 11);
assert_eq!(wr, b"hello world");
}
diff --git a/tokio/tests/tcp_echo.rs b/tokio/tests/tcp_echo.rs
index 38377702..1feba63e 100644
--- a/tokio/tests/tcp_echo.rs
+++ b/tokio/tests/tcp_echo.rs
@@ -35,7 +35,7 @@ async fn echo_server() {
let (mut stream, _) = assert_ok!(srv.accept().await);
let (mut rd, mut wr) = stream.split();
- let n = assert_ok!(rd.copy(&mut wr).await);
+ let n = assert_ok!(io::copy(&mut rd, &mut wr).await);
assert_eq!(n, (ITER * msg.len()) as u64);
assert_ok!(rx.await);
diff --git a/tokio/tests/tcp_shutdown.rs b/tokio/tests/tcp_shutdown.rs
index cc5ea26f..bd43e143 100644
--- a/tokio/tests/tcp_shutdown.rs
+++ b/tokio/tests/tcp_shutdown.rs
@@ -1,7 +1,7 @@
#![warn(rust_2018_idioms)]
#![cfg(feature = "full")]
-use tokio::io::AsyncWriteExt;
+use tokio::io::{self, AsyncWriteExt};
use tokio::net::{TcpListener, TcpStream};
use tokio::prelude::*;
use tokio_test::assert_ok;
@@ -24,6 +24,6 @@ async fn shutdown() {
let (mut stream, _) = assert_ok!(srv.accept().await);
let (mut rd, mut wr) = stream.split();
- let n = assert_ok!(rd.copy(&mut wr).await);
+ let n = assert_ok!(io::copy(&mut rd, &mut wr).await);
assert_eq!(n, 0);
}