Skip to content

Commit 1fe8a28

Browse files
authored
Merge branch 'master' into book-typos-and-small-edits
2 parents 9974ff6 + d656882 commit 1fe8a28

24 files changed

+52
-50
lines changed

docs/src/concepts/futures.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ Every call to `poll()` can result in one of these two cases:
9999
2. The computation has not finished executing, it will return [`Poll::Pending`](https://doc.rust-lang.org/std/task/enum.Poll.html#variant.Pending)
100100

101101
This allows us to externally check if a `Future` still has unfinished work, or is finally done and can give us the value. The most simple (but not efficient) way would be to just constantly poll futures in a loop. There are optimisations possible, and this is what a good runtime does for you.
102-
Note that calling `poll` after case 1 happened may result in confusing behaviour. See the [futures-docs](https://doc.rust-lang.org/std/future/trait.Future.html) for details.
102+
Note that calling `poll` again after case 1 happened may result in confusing behaviour. See the [futures-docs](https://doc.rust-lang.org/std/future/trait.Future.html) for details.
103103

104104
## Async
105105

@@ -118,7 +118,7 @@ async fn read_file(path: &str) -> Result<String, io::Error> {
118118

119119
Amazingly little difference, right? All we did is label the function `async` and insert 2 special commands: `.await`.
120120

121-
This `async` function sets up a deferred computation. When this function is called, instead of returning the computed `String`, it will produce a `Future<Output=String>`. (Or, more precisely, will generate a type for you that implements `Future<Output=String>`.)
121+
This `async` function sets up a deferred computation. When this function is called, it will produce a `Future<Output=Result<String, io::Error>>` instead of immediately returning a `Result<String, io::Error>`. (Or, more precisely, generate a type for you that implements `Future<Output=Result<String, io::Error>>`.)
122122

123123
## What does `.await` do?
124124

@@ -137,3 +137,5 @@ A `Future` is any data type that does not represent a value, but the ability to
137137
Next, we will introduce you to `tasks`, which we need to actually *run* Futures.
138138

139139
[^1]: Two parties reading while it is guaranteed that no one is writing is always safe.
140+
141+
[futures]: https://rust-lang.github.io/async-book/02_execution/02_future.html

docs/src/concepts/tasks.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ async fn read_file(path: &str) -> Result<String, io::Error> {
1717

1818
fn main() {
1919
let reader_task = task::spawn(async {
20-
let result = read_file("data.csv");
20+
let result = read_file("data.csv").await;
2121
match result {
2222
Ok(s) => println!("{}", s),
2323
Err(e) => println!("Error reading file: {:?}", e)
@@ -33,7 +33,7 @@ This asks the runtime baked into `async_std` to execute the code that reads a fi
3333

3434
```rust
3535
async {
36-
let result = read_file("data.csv");
36+
let result = read_file("data.csv").await;
3737
match result {
3838
Ok(s) => println!("{}", s),
3939
Err(e) => println!("Error reading file: {:?}", e)

docs/src/glossary.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,6 @@
22

33
### blocking
44

5-
"blocked" generally refers to conditions that keep a task from doing its work. For example, it might need data to be sent by a client before continuing. When tasks becomes blocked, usually, other tasks are scheduled.
5+
"blocked" generally refers to conditions that keep a task from doing its work. For example, it might need data to be sent by a client before continuing. When tasks become blocked, usually, other tasks are scheduled.
66

7-
Sometimes you hear that you should never call "blocking functions" in an async context. What this refers to is functions that block the current thread and do not yield control back. This keeps the executor from using this thread to schedule another task.
7+
Sometimes you hear that you should never call "blocking functions" in an async context. What this refers to is functions that block the current thread and do not yield control back. This keeps the executor from using this thread to schedule another task.

docs/src/introduction.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
![async-std logo](./images/horizontal_color.svg)
44

5-
This book serves as high-level documentation for `async-std` and a way of learning async programming in Rust through it. As such, it focusses on the `async-std` API and the task model it gives you.
5+
This book serves as high-level documentation for `async-std` and a way of learning async programming in Rust through it. As such, it focuses on the `async-std` API and the task model it gives you.
66

77
Please note that the Rust project provides its own book on asynchronous programming, called ["Asynchronous Programming in Rust"][async-book], which we highly recommend reading along with this book, as it provides a different, wider view on the topic.
88

docs/src/overview/async-std.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Welcome to `async-std`
22

3-
`async-std` along with its [supporting libraries][organization] is a library making your life in async programming easier. It provides provide fundamental implementations for downstream libraries and applications alike. The name reflects the approach of this library: it is a closely modeled to the Rust main standard library as possible, replacing all components by async counterparts.
3+
`async-std`, along with its [supporting libraries][organization], is a library making your life in async programming easier. It provides fundamental implementations for downstream libraries and applications alike. The name reflects the approach of this library: it is as closely modeled to the Rust main standard library as possible, replacing all components by async counterparts.
44

5-
`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes an `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include io primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std].
5+
`async-std` provides an interface to all important primitives: filesystem operations, network operations and concurrency basics like timers. It also exposes a `task` in a model similar to the `thread` module found in the Rust standard lib. But it does not only include I/O primitives, but also `async/await` compatible versions of primitives like `Mutex`. You can read more about `async-std` in [the overview chapter][overview-std].
66

77
[organization]: https://github.com/async-rs/async-std
88
[overview-std]: overview/async-std/

docs/src/overview/stability-guarantees.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ Security fixes will be applied to _all_ minor branches of this library in all _s
3535

3636
## Credits
3737

38-
This policy is based on [burntsushis regex crate][regex-policy].
38+
This policy is based on [BurntSushi's regex crate][regex-policy].
3939

4040
[regex-policy]: https://github.com/rust-lang/regex#minimum-rust-version-policy

docs/src/overview/std-and-library-futures.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ The future defined in the [futures-rs](https://docs.rs/futures-preview/0.3.0-alp
1010

1111
It is critical to understand the difference between `std::future::Future` and `futures::future::Future`, and the approach that `async-std` takes towards them. In itself, `std::future::Future` is not something you want to interact with as a user—except by calling `.await` on it. The inner workings of `std::future::Future` are mostly of interest to people implementing `Future`. Make no mistake—this is very useful! Most of the functionality that used to be defined on `Future` itself has been moved to an extension trait called [`FuturesExt`](https://docs.rs/futures-preview/0.3.0-alpha.17/futures/future/trait.FutureExt.html). From this information, you might be able to infer that the `futures` library serves as an extension to the core Rust async features.
1212

13-
In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can get actively opt into the extensions provided by the `futures-preview` crate by adding it your `Cargo.toml` and importing `FuturesExt`.
13+
In the same tradition as `futures`, `async-std` re-exports the core `std::future::Future` type. You can actively opt into the extensions provided by the `futures-preview` crate by adding it to your `Cargo.toml` and importing `FuturesExt`.
1414

1515
## Interfaces and Stability
1616

1717
`async-std` aims to be a stable and reliable library, at the level of the Rust standard library. This also means that we don't rely on the `futures` library for our interface. Yet, we appreciate that many users have come to like the conveniences that `futures-rs` brings. For that reason, `async-std` implements all `futures` traits for its types.
1818

19-
Luckily, the approach from above gives you full flexibility. If you care about stability a lot, you can just use `async-std` as is. If you prefer the `futures` library interfaces, you link those in.. Both uses are first class.
19+
Luckily, the approach from above gives you full flexibility. If you care about stability a lot, you can just use `async-std` as is. If you prefer the `futures` library interfaces, you link those in. Both uses are first class.
2020

2121
## `async_std::future`
2222

docs/src/tutorial/accept_loop.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>
2121

2222
1. `async_std` uses `std` types where appropriate.
2323
We'll need `ToSocketAddrs` to specify address to listen on.
24-
2. `prelude` re-exports some traits required to work with futures and streams
25-
3. The `task` module roughtly corresponds to `std::thread` module, but tasks are much lighter weight.
24+
2. `prelude` re-exports some traits required to work with futures and streams.
25+
3. The `task` module roughly corresponds to the `std::thread` module, but tasks are much lighter weight.
2626
A single thread can run many tasks.
2727
4. For the socket type, we use `TcpListener` from `async_std`, which is just like `std::net::TcpListener`, but is non-blocking and uses `async` API.
2828
5. We will skip implementing comprehensive error handling in this example.
@@ -43,7 +43,7 @@ async fn server(addr: impl ToSocketAddrs) -> Result<()> { // 1
4343
}
4444
```
4545

46-
1. We mark `server` function as `async`, which allows us to use `.await` syntax inside.
46+
1. We mark the `server` function as `async`, which allows us to use `.await` syntax inside.
4747
2. `TcpListener::bind` call returns a future, which we `.await` to extract the `Result`, and then `?` to get a `TcpListener`.
4848
Note how `.await` and `?` work nicely together.
4949
This is exactly how `std::net::TcpListener` works, but with `.await` added.
@@ -73,4 +73,4 @@ The crucial thing to realise that is in Rust, unlike other languages, calling an
7373
Async functions only construct futures, which are inert state machines.
7474
To start stepping through the future state-machine in an async function, you should use `.await`.
7575
In a non-async function, a way to execute a future is to handle it to the executor.
76-
In this case, we use `task::block_on` to execute future on the current thread and block until it's done.
76+
In this case, we use `task::block_on` to execute a future on the current thread and block until it's done.

docs/src/tutorial/all_together.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11

22
## All Together
33

4-
At this point, we only need to start broker to get a fully-functioning (in the happy case!) chat:
4+
At this point, we only need to start the broker to get a fully-functioning (in the happy case!) chat:
55

66
```rust
77
#![feature(async_await)]
@@ -129,7 +129,7 @@ async fn broker(mut events: Receiver<Event>) -> Result<()> {
129129
}
130130
```
131131

132-
1. Inside the `server`, we create broker's channel and `task`.
132+
1. Inside the `server`, we create the broker's channel and `task`.
133133
2. Inside `client`, we need to wrap `TcpStream` into an `Arc`, to be able to share it with the `client_writer`.
134134
3. On login, we notify the broker.
135135
Note that we `.unwrap` on send: broker should outlive all the clients and if that's not the case the broker probably panicked, so we can escalate the panic as well.

docs/src/tutorial/clean_shutdown.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
## Clean Shutdown
22

3-
On of the problems of the current implementation is that it doesn't handle graceful shutdown.
3+
One of the problems of the current implementation is that it doesn't handle graceful shutdown.
44
If we break from the accept loop for some reason, all in-flight tasks are just dropped on the floor.
55
A more correct shutdown sequence would be:
66

@@ -10,7 +10,7 @@ A more correct shutdown sequence would be:
1010

1111
A clean shutdown in a channel based architecture is easy, although it can appear a magic trick at first.
1212
In Rust, receiver side of a channel is closed as soon as all senders are dropped.
13-
That is, as soon as producers exit and drop their senders, the rest of the system shutdowns naturally.
13+
That is, as soon as producers exit and drop their senders, the rest of the system shuts down naturally.
1414
In `async_std` this translates to two rules:
1515

1616
1. Make sure that channels form an acyclic graph.
@@ -83,4 +83,4 @@ Notice what happens with all of the channels once we exit the accept loop:
8383
3. It's crucial that, at this stage, we drop the `peers` map.
8484
This drops writer's senders.
8585
4. Now we can join all of the writers.
86-
5. Finally, we join the broker, which also guarantees that all the writes have terminated.
86+
5. Finally, we join the broker, which also guarantees that all the writes have terminated.

docs/src/tutorial/connecting_readers_and_writers.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11

22
## Connecting Readers and Writers
33

4-
So how we make sure that messages read in `client` flow into the relevant `client_writer`?
4+
So how do we make sure that messages read in `client` flow into the relevant `client_writer`?
55
We should somehow maintain an `peers: HashMap<String, Sender<String>>` map which allows a client to find destination channels.
66
However, this map would be a bit of shared mutable state, so we'll have to wrap an `RwLock` over it and answer tough questions of what should happen if the client joins at the same moment as it receives a message.
77

88
One trick to make reasoning about state simpler comes from the actor model.
99
We can create a dedicated broker tasks which owns the `peers` map and communicates with other tasks by channels.
10-
By hiding `peers` inside such "actor" task, we remove the need for mutxes and also make serialization point explicit.
10+
By hiding `peers` inside such an "actor" task, we remove the need for mutxes and also make serialization point explicit.
1111
The order of events "Bob sends message to Alice" and "Alice joins" is determined by the order of the corresponding events in the broker's event queue.
1212

1313
```rust
@@ -55,6 +55,6 @@ async fn broker(mut events: Receiver<Event>) -> Result<()> {
5555
1. Broker should handle two types of events: a message or an arrival of a new peer.
5656
2. Internal state of the broker is a `HashMap`.
5757
Note how we don't need a `Mutex` here and can confidently say, at each iteration of the broker's loop, what is the current set of peers
58-
3. To handle a message we send it over a channel to each destination
58+
3. To handle a message, we send it over a channel to each destination
5959
4. To handle new peer, we first register it in the peer's map ...
6060
5. ... and then spawn a dedicated task to actually write the messages to the socket.

docs/src/tutorial/handling_disconnection.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,11 @@ If the read side finishes we will notify the write side that it should stop as w
1111
That is, we need to add an ability to signal shutdown for the writer task.
1212

1313
One way to approach this is a `shutdown: Receiver<()>` channel.
14-
There's a more minimal solution however, which makes a clever use of RAII.
14+
There's a more minimal solution however, which makes clever use of RAII.
1515
Closing a channel is a synchronization event, so we don't need to send a shutdown message, we can just drop the sender.
1616
This way, we statically guarantee that we issue shutdown exactly once, even if we early return via `?` or panic.
1717

18-
First, let's add shutdown channel to the `client`:
18+
First, let's add a shutdown channel to the `client`:
1919

2020
```rust
2121
#[derive(Debug)]
@@ -51,10 +51,10 @@ async fn client(mut broker: Sender<Event>, stream: TcpStream) -> Result<()> {
5151

5252
1. To enforce that no messages are send along the shutdown channel, we use an uninhabited type.
5353
2. We pass the shutdown channel to the writer task
54-
3. In the reader, we create an `_shutdown_sender` whose only purpose is to get dropped.
54+
3. In the reader, we create a `_shutdown_sender` whose only purpose is to get dropped.
5555

56-
In the `client_writer`, we now need to chose between shutdown and message channels.
57-
We use `select` macro for this purpose:
56+
In the `client_writer`, we now need to choose between shutdown and message channels.
57+
We use the `select` macro for this purpose:
5858

5959
```rust
6060
use futures::select;
@@ -83,12 +83,12 @@ async fn client_writer(
8383
```
8484

8585
1. We add shutdown channel as an argument.
86-
2. Because of `select`, we can't use a `white let` loop, so we desugar it further into a `loop`.
86+
2. Because of `select`, we can't use a `while let` loop, so we desugar it further into a `loop`.
8787
3. In the shutdown case we use `match void {}` as a statically-checked `unreachable!()`.
8888

8989
Another problem is that between the moment we detect disconnection in `client_writer` and the moment when we actually remove the peer from the `peers` map, new messages might be pushed into the peer's channel.
90-
To not lose these messages completely, we'll return the messages channel back to broker.
91-
This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and make the broker itself infailable.
90+
To not lose these messages completely, we'll return the messages channel back to the broker.
91+
This also allows us to establish a useful invariant that the message channel strictly outlives the peer in the `peers` map, and makes the broker itself infailable.
9292

9393
## Final Code
9494

@@ -280,7 +280,7 @@ where
280280
2. The broker's main loop exits when the input events channel is exhausted (that is, when all readers exit).
281281
3. Because broker itself holds a `disconnect_sender`, we know that the disconnections channel can't be fully drained in the main loop.
282282
4. We send peer's name and pending messages to the disconnections channel in both the happy and the not-so-happy path.
283-
Again, we can safely unwrap because broker outlives writers.
283+
Again, we can safely unwrap because the broker outlives writers.
284284
5. We drop `peers` map to close writers' messages channel and shut down the writers for sure.
285285
It is not strictly necessary in the current setup, where the broker waits for readers' shutdown anyway.
286286
However, if we add a server-initiated shutdown (for example, kbd:[ctrl+c] handling), this will be a way for the broker to shutdown the writers.

docs/src/tutorial/handling_disconnections.md

Lines changed: 0 additions & 1 deletion
This file was deleted.

docs/src/tutorial/implementing_a_client.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
Let's now implement the client for the chat.
44
Because the protocol is line-based, the implementation is pretty straightforward:
55

6-
* Lines read from stdin should be send over the socket.
6+
* Lines read from stdin should be sent over the socket.
77
* Lines read from the socket should be echoed to stdout.
88

99
Unlike the server, the client needs only limited concurrency, as it interacts with only a single user.
@@ -67,6 +67,6 @@ async fn try_main(addr: impl ToSocketAddrs) -> Result<()> {
6767
}
6868
```
6969

70-
1. Here we split `TcpStream` into read and write halfs: there's `impl AsyncRead for &'_ TcpStream`, just like the one in std.
71-
2. We crate a steam of lines for both the socket and stdin.
72-
3. In the main select loop, we print the lines we receive from server and send the lines we read from the console.
70+
1. Here we split `TcpStream` into read and write halves: there's `impl AsyncRead for &'_ TcpStream`, just like the one in std.
71+
2. We create a stream of lines for both the socket and stdin.
72+
3. In the main select loop, we print the lines we receive from the server and send the lines we read from the console.

docs/src/tutorial/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
Nothing is as simple as a chat server, right? Not quite, chat servers
44
already expose you to all the fun of asynchronous programming: how
55
do you handle clients connecting concurrently. How do you handle them disconnecting?
6+
67
How do you distribute the messages?
78

89
In this tutorial, we will show you how to write one in `async-std`.

0 commit comments

Comments
 (0)