diff --git a/src/io/mod.rs b/src/io/mod.rs index 812c97a..9a125b2 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -1,24 +1,273 @@ -//! Basic input and output. +//! Traits, helpers, and type definitions for core I/O functionality. +//! +//! The `async_std::io` module contains a number of common things you'll need +//! when doing input and output. The most core part of this module is +//! the [`Read`] and [`Write`] traits, which provide the +//! most general interface for reading and writing input and output. //! //! This module is an async version of [`std::io`]. //! //! [`std::io`]: https://doc.rust-lang.org/std/io/index.html //! -//! # Examples +//! # Read and Write //! -//! Read a line from the standard input: +//! Because they are traits, [`Read`] and [`Write`] are implemented by a number +//! of other types, and you can implement them for your types too. As such, +//! you'll see a few different types of I/O throughout the documentation in +//! this module: [`File`]s, [`TcpStream`]s, and sometimes even [`Vec`]s. For +//! example, [`Read`] adds a [`read`][`Read::read`] method, which we can use on +//! [`File`]s: //! //! ```no_run +//! use async_std::prelude::*; +//! use async_std::fs::File; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! 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(()) }) } +//! ``` +//! +//! [`Read`] and [`Write`] are so important, implementors of the two traits have a +//! nickname: readers and writers. So you'll sometimes see 'a reader' instead +//! of 'a type that implements the [`Read`] trait'. Much easier! +//! +//! ## Seek and BufRead +//! +//! Beyond that, there are two important traits that are provided: [`Seek`] +//! and [`BufRead`]. Both of these build on top of a reader to control +//! how the reading happens. [`Seek`] lets you control where the next byte is +//! coming from: +//! +//! ```no_run +//! use async_std::io::prelude::*; +//! use async_std::io::SeekFrom; +//! use async_std::fs::File; +//! //! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { //! # +//! let mut f = File::open("foo.txt").await?; +//! let mut buffer = [0; 10]; +//! +//! // skip to the last 10 bytes of the file +//! f.seek(SeekFrom::End(-10)).await?; +//! +//! // read up to 10 bytes +//! let n = f.read(&mut buffer).await?; +//! +//! println!("The bytes: {:?}", &buffer[..n]); +//! # +//! # Ok(()) }) } +//! ``` +//! +//! [`BufRead`] uses an internal buffer to provide a number of other ways to read, but +//! to show it off, we'll need to talk about buffers in general. Keep reading! +//! +//! ## BufReader and BufWriter +//! +//! Byte-based interfaces are unwieldy and can be inefficient, as we'd need to be +//! making near-constant calls to the operating system. To help with this, +//! `std::io` comes with two structs, [`BufReader`] and [`BufWriter`], which wrap +//! readers and writers. The wrapper uses a buffer, reducing the number of +//! calls and providing nicer methods for accessing exactly what you want. +//! +//! For example, [`BufReader`] works with the [`BufRead`] trait to add extra +//! methods to any reader: +//! +//! ```no_run +//! use async_std::io::prelude::*; +//! use async_std::io::BufReader; +//! use async_std::fs::File; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! let f = File::open("foo.txt").await?; +//! let mut reader = BufReader::new(f); +//! let mut buffer = String::new(); +//! +//! // read a line into buffer +//! reader.read_line(&mut buffer).await?; +//! +//! println!("{}", buffer); +//! # +//! # Ok(()) }) } +//! ``` +//! +//! [`BufWriter`] doesn't add any new ways of writing; it just buffers every call +//! to [`write`][`Write::write`]: +//! +//! ```no_run +//! use async_std::io::prelude::*; +//! use async_std::io::BufWriter; +//! use async_std::fs::File; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! let f = File::create("foo.txt").await?; +//! { +//! let mut writer = BufWriter::new(f); +//! +//! // write a byte to the buffer +//! writer.write(&[42]).await?; +//! +//! } // the buffer is flushed once writer goes out of scope +//! # +//! # Ok(()) }) } +//! ``` +//! +//! ## Standard input and output +//! +//! A very common source of input is standard input: +//! +//! ```no_run //! use async_std::io; //! -//! let stdin = io::stdin(); -//! let mut line = String::new(); -//! stdin.read_line(&mut line).await?; +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input).await?; +//! +//! println!("You typed: {}", input.trim()); //! # //! # Ok(()) }) } //! ``` +//! +//! Note that you cannot use the [`?` operator] in functions that do not return +//! a [`Result`][`Result`]. Instead, you can call [`.unwrap()`] +//! or `match` on the return value to catch any possible errors: +//! +//! ```no_run +//! use async_std::io; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input).await.unwrap(); +//! # +//! # Ok(()) }) } +//! ``` +//! +//! And a very common source of output is standard output: +//! +//! ```no_run +//! use async_std::io; +//! use async_std::io::prelude::*; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! io::stdout().write(&[42]).await?; +//! # +//! # Ok(()) }) } +//! ``` +//! +//! Of course, using [`io::stdout`] directly is less common than something like +//! [`println!`]. +//! +//! ## Iterator types +//! +//! A large number of the structures provided by `std::io` are for various +//! ways of iterating over I/O. For example, [`Lines`] is used to split over +//! lines: +//! +//! ```no_run +//! use async_std::prelude::*; +//! use async_std::io::BufReader; +//! use async_std::fs::File; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! let f = File::open("foo.txt").await?; +//! let reader = BufReader::new(f); +//! +//! let mut lines = reader.lines(); +//! while let Some(line) = lines.next().await { +//! println!("{}", line?); +//! } +//! # +//! # Ok(()) }) } +//! ``` +//! +//! ## Functions +//! +//! There are a number of [functions][functions-list] that offer access to various +//! features. For example, we can use three of these functions to copy everything +//! from standard input to standard output: +//! +//! ```no_run +//! use async_std::io; +//! +//! # fn main() -> std::io::Result<()> { async_std::task::block_on(async { +//! # +//! io::copy(&mut io::stdin(), &mut io::stdout()).await?; +//! # +//! # Ok(()) }) } +//! ``` +//! +//! [functions-list]: #functions-1 +//! +//! ## io::Result +//! +//! Last, but certainly not least, is [`io::Result`]. This type is used +//! as the return type of many `std::io` functions that can cause an error, and +//! can be returned from your own functions as well. Many of the examples in this +//! module use the [`?` operator]: +//! +//! ``` +//! #![allow(dead_code)] +//! use async_std::io; +//! +//! async fn read_input() -> io::Result<()> { +//! let mut input = String::new(); +//! +//! io::stdin().read_line(&mut input).await?; +//! +//! println!("You typed: {}", input.trim()); +//! +//! Ok(()) +//! } +//! ``` +//! +//! The return type of `read_input`, [`io::Result<()>`][`io::Result`], is a very +//! common type for functions which don't have a 'real' return value, but do want to +//! return errors if they happen. In this case, the only purpose of this function is +//! to read the line and print it, so we use `()`. +//! +//! ## Platform-specific behavior +//! +//! Many I/O functions throughout the standard library are documented to indicate +//! what various library or syscalls they are delegated to. This is done to help +//! applications both understand what's happening under the hood as well as investigate +//! any possibly unclear semantics. Note, however, that this is informative, not a binding +//! contract. The implementation of many of these functions are subject to change over +//! time and may call fewer or more syscalls/library functions. +//! +//! [`Read`]: trait.Read.html +//! [`Write`]: trait.Write.html +//! [`Seek`]: trait.Seek.html +//! [`BufRead`]: trait.BufRead.html +//! [`File`]: ../fs/struct.File.html +//! [`TcpStream`]: ../net/struct.TcpStream.html +//! [`Vec`]: ../vec/struct.Vec.html +//! [`BufReader`]: struct.BufReader.html +//! [`BufWriter`]: struct.BufWriter.html +//! [`Write::write`]: trait.Write.html#tymethod.write +//! [`io::stdout`]: fn.stdout.html +//! [`println!`]: ../macro.println.html +//! [`Lines`]: struct.Lines.html +//! [`io::Result`]: type.Result.html +//! [`?` operator]: https://doc.rust-lang.org/stable/book/appendix-02-operators.html +//! [`Read::read`]: trait.Read.html#tymethod.read +//! [`Result`]: https://doc.rust-lang.org/std/result/enum.Result.html +//! [`.unwrap()`]: https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap #[doc(inline)] pub use std::io::{Error, ErrorKind, IoSlice, IoSliceMut, Result, SeekFrom};