Skip to content

Commit

Permalink
update original
Browse files Browse the repository at this point in the history
  • Loading branch information
funkill committed Oct 16, 2024
1 parent 36bce06 commit b51c08a
Show file tree
Hide file tree
Showing 35 changed files with 550 additions and 442 deletions.
69 changes: 43 additions & 26 deletions rustbook-en/nostarch/chapter17.md
Original file line number Diff line number Diff line change
Expand Up @@ -1669,10 +1669,10 @@ The version with `yield_now` is *way* faster!
This means that async can be useful even for compute-bound tasks, depending on
what else your program is doing, because it provides a useful tool for
structuring the relationships between different parts of the program. This is a
form of *cooperative multitasking*, where each future has both the power to
determine when it hands over control via await points. Each future therefore
also has the responsibility to avoid blocking for too long. In some Rust-based
embedded operating systems, this is the *only* kind of multitasking!
form of *cooperative multitasking*, where each future has the power to determine
when it hands over control via await points. Each future therefore also has the
responsibility to avoid blocking for too long. In some Rust-based embedded
operating systems, this is the *only* kind of multitasking!

In real-world code, you won’t usually be alternating function calls with await
points on every single line, of course. While yielding control in this way is
Expand Down Expand Up @@ -2046,7 +2046,7 @@ indicates a message arrived in time; the `Err` variant indicates that the
timeout elapsed before any message arrived. We `match` on that result and either
print the message when we receive it successfully, or print a notice about the
timeout. Finally, notice that we pin the messages after applying the timeout to
them, because the timeout helper produces a future which needs to be pinned to
them, because the timeout helper produces a stream which needs to be pinned to
be polled.

Filename: src/main.rs
Expand Down Expand Up @@ -2507,7 +2507,7 @@ it is not yet ready.

### Pinning and the Pin and Unpin Traits

When we introduced the idea of pinning, while working on Listing 17-17, we ran
When we introduced the idea of pinning while working on Listing 17-17, we ran
into a very gnarly error message. Here is the relevant part of it again:

```
Expand Down Expand Up @@ -2535,12 +2535,20 @@ For more information about an error, try `rustc --explain E0277`.

When we read this error message carefully, it not only tells us that we need to
pin the values, but also tells us why pinning is required. The `trpl::join_all`
function returns a struct called `JoinAll`. That struct, in turn, is generic
over a type `F`, which is constrained to implement the `Future` trait. Finally,
directly awaiting a Future requires that the future in question implement the
`Unpin` trait. That’s a lot! But we can understand it, if we dive a little
further into how the `Future` type actually works, in particular around
*pinning*.
function returns a struct called `JoinAll`. That struct is generic over a type
`F`, which is constrained to implement the `Future` trait. Directly awaiting a
future with `await` pins the future implicitly. That’s why we don’t need to use
`pin!` everywhere we want to await futures.

However, we’re not directly awaiting a future here. Instead, we construct a new
future, `JoinAll`, by passing a collection of futures to the `join_all`
function. The signature for `join_all` produces requires that the type of the
items in the collection all implement the `Future` trait, and `Box<T>` only
implements `Future` if the `T` that it wraps is a future which implements the
`Unpin` trait.

That’s a lot! But we can understand it, if we dive a little further into how the
`Future` type actually works, in particular around *pinning*.

Let’s look again at the definition of `Future`:

Expand Down Expand Up @@ -2684,24 +2692,32 @@ that a given type does *not* need to uphold any particular guarantees about
whether the value in question can be moved.

Just as with `Send` and `Sync`, the compiler implements `Unpin` automatically
for all types where it can prove it is safe. Implementing `Unpin` manually is
unsafe because it requires *you* to uphold all the guarantees which make `Pin`
and `Unpin` safe yourself for a type with internal references. In practice,
this is a very rare thing to implement yourself!
for all types where it can prove it is safe. The special case, again similar to
`Send` and `Sync`, is the case where `Unpin` is *not* implemented for a type.
The notation for this is `impl !Unpin for SomeType`, where `SomeType` is the
name of a type which *does* need to uphold those guarantees to be safe whenever
a pointer to that type it is used in a `Pin`.

In other words, there are two things to keep in mind about the relationship
between `Pin` and `Unpin`. First, `Unpin` is the “normal” case, and `!Unpin` is
the special case. Second, whether a type implements `Unpin` or `!Unpin` *only*
matters when using a pinned pointer to that type like `Pin<&mut SomeType>`.

To make that concrete, think about a `String`: it has a length and the Unicode
characters which make it up. We can wrap a `String` in `Pin`, as seen in Figure
17-7. However
17-8. However, `String` automatically implements `Unpin`, the same as most other
types in Rust.

<img alt="Concurrent work flow" src="img/trpl17-08.svg" />

Figure 17-8: Pinning a String, with a dotted line indicating that the String
implements the `Unpin` trait, so it is not pinned.

This means that we can do things such as replace one string with another at the
exact same location in memory as in Figure 17-9. This doesn’t violate the `Pin`
contract because `String`—like most other types in Rust—implements `Unpin`,
because it has no internal references that make it unsafe to move around!
As a result, we can do things which would be illegal if `String` implemented
`!Unpin` instead, such as replace one string with another at the exact same
location in memory as in Figure 17-9. This doesn’t violate the `Pin` contract,
because `String` has no internal references that make it unsafe to move around!
That is precisely why it implements `Unpin` rather than `!Unpin`.

<img alt="Concurrent work flow" src="img/trpl17-09.svg" />

Expand All @@ -2710,9 +2726,10 @@ Figure 17-9: Replacing the String with an entirely different String in memory.
Now we know enough to understand the errors reported for that `join_all` call
from back in Listing 17-17. We originally tried to move the futures produced by
async blocks into a `Vec<Box<dyn Future<Output = ()>>>`, but as we’ve seen,
those futures may have internal references, so they don’t implement `Unpin`.
They need to be pinned, and then we can pass the `Pin` type into the `Vec`,
confident that the underlying data in the futures will *not* be moved.
those futures may have internal references, so they don’t automatically
implement `Unpin`. Once we pin them, we can pass the resulting `Pin` type into
the `Vec`, confident that the underlying data in the futures will *not* be
moved.

`Pin` and `Unpin` are mostly important for building lower-level libraries, or
when you’re building a runtime itself, rather than for day to day Rust code.
Expand Down Expand Up @@ -2943,9 +2960,9 @@ threads *and* tasks, and therefore futures.
As a default way of thinking about which to use when:
* If the task is *very parallelizable*, such as processing a bunch of data where
* If the work is *very parallelizable*, such as processing a bunch of data where
each part can be processed separately, threads are a better choice.
* If the task is *very concurrent*, such as handling messages from a bunch of
* If the work is *very concurrent*, such as handling messages from a bunch of
different sources which may come in a different intervals or different rates,
async is a better choice.
Expand Down
21 changes: 11 additions & 10 deletions rustbook-en/packages/mdbook-trpl-listing/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ impl<'e> ListingState<'e> {
) -> Result<(), String> {
// We do not *keep* the version constructed here, just temporarily
// construct it so the HTML parser, which expects properly closed tags
// to parse it as a *tag* rather than a *weird text node*, which accept
// to parse it as a *tag* rather than a *weird text node*, will accept
// it and provide a useful view of it.
let to_parse = tag.to_owned().to_string() + "</Listing>";
let listing = Dom::parse(&to_parse)
Expand All @@ -212,21 +212,22 @@ impl<'e> ListingState<'e> {
.try_fold(ListingBuilder::new(), |builder, (key, maybe_value)| {
match (key.as_str(), maybe_value) {
("number", Some(value)) => Ok(builder.with_number(value)),
("number", None) => {
Err(String::from("number attribute without value"))
}

("caption", Some(value)) => Ok(builder.with_caption(value)),
("caption", None) => {
Err(String::from("caption attribute without value"))
}

("file-name", Some(value)) => {
Ok(builder.with_file_name(value))
}
("file-name", None) => {
Err(String::from("file-name attribute without value"))

(attr @ "file-name", None)
| (attr @ "caption", None)
| (attr @ "number", None) => {
Err(format!("Missing value for attribute: '{attr}'"))
}

_ => Ok(builder), // TODO: error on extra attrs?
(attr, _) => {
Err(format!("Unsupported attribute name: '{attr}'"))
}
}
})?
.build();
Expand Down
103 changes: 103 additions & 0 deletions rustbook-en/packages/mdbook-trpl-listing/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,5 +188,108 @@ fn main() {}
);
}

#[test]
fn with_unsupported_attr_name() {
let result = rewrite_listing(
"<Listing invalid-attr>
```rust
fn main() {}
```
</Listing>",
Mode::Default,
);

assert_eq!(
result,
Err(String::from("Unsupported attribute name: 'invalid-attr'"))
)
}

#[test]
fn with_unsupported_attr_name_with_arg() {
let result = rewrite_listing(
r#"<Listing invalid-attr="123">
```rust
fn main() {}
```
</Listing>"#,
Mode::Default,
);

assert_eq!(
result,
Err(String::from("Unsupported attribute name: 'invalid-attr'"))
)
}

#[cfg(test)]
mod missing_value {
use super::*;

#[test]
fn for_number() {
let result = rewrite_listing(
r#"<Listing number>
```rust
fn main() {}
```
</Listing>"#,
Mode::Default,
);

assert_eq!(
result,
Err(String::from("Missing value for attribute: 'number'"))
)
}

#[test]
fn for_caption() {
let result = rewrite_listing(
r#"<Listing caption>
```rust
fn main() {}
```
</Listing>"#,
Mode::Default,
);

assert_eq!(
result,
Err(String::from("Missing value for attribute: 'caption'"))
)
}

#[test]
fn for_file_name() {
let result = rewrite_listing(
r#"<Listing file-name>
```rust
fn main() {}
```
</Listing>"#,
Mode::Default,
);

assert_eq!(
result,
Err(String::from("Missing value for attribute: 'file-name'"))
)
}
}

#[test]
fn missing_value() {}

#[cfg(test)]
mod config;
10 changes: 6 additions & 4 deletions rustbook-en/src/ch06-01-defining-an-enum.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,13 @@ only know what *kind* it is. Given that you just learned about structs in
Chapter 5, you might be tempted to tackle this problem with structs as shown in
Listing 6-1.

<Listing number="6-1" caption="Storing the data and `IpAddrKind` variant of an IP address using a `struct`">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-01/src/main.rs:here}}
```

<span class="caption">Listing 6-1: Storing the data and `IpAddrKind` variant of
an IP address using a `struct`</span>
</Listing>

Here, we’ve defined a struct `IpAddr` that has two fields: a `kind` field that
is of type `IpAddrKind` (the enum we defined previously) and an `address` field
Expand Down Expand Up @@ -140,12 +141,13 @@ more about bringing types into scope in Chapter 7.
Let’s look at another example of an enum in Listing 6-2: this one has a wide
variety of types embedded in its variants.

<Listing number="6-2" caption="A `Message` enum whose variants each store different amounts and types of values">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-02/src/main.rs:here}}
```

<span class="caption">Listing 6-2: A `Message` enum whose variants each store
different amounts and types of values</span>
</Listing>

This enum has four variants with different types:

Expand Down
15 changes: 9 additions & 6 deletions rustbook-en/src/ch06-02-match.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,13 @@ function that takes an unknown US coin and, in a similar way as the counting
machine, determines which coin it is and returns its value in cents, as shown
in Listing 6-3.

<Listing number="6-3" caption="An enum and a `match` expression that has the variants of the enum as its patterns">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-03/src/main.rs:here}}
```

<span class="caption">Listing 6-3: An enum and a `match` expression that has
the variants of the enum as its patterns</span>
</Listing>

Let’s break down the `match` in the `value_in_cents` function. First we list
the `match` keyword followed by an expression, which in this case is the value
Expand Down Expand Up @@ -75,12 +76,13 @@ designs, so only quarters have this extra value. We can add this information to
our `enum` by changing the `Quarter` variant to include a `UsState` value
stored inside it, which we’ve done in Listing 6-4.

<Listing number="6-4" caption="A `Coin` enum in which the `Quarter` variant also holds a `UsState` value">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-04/src/main.rs:here}}
```

<span class="caption">Listing 6-4: A `Coin` enum in which the `Quarter` variant
also holds a `UsState` value</span>
</Listing>

Let’s imagine that a friend is trying to collect all 50 state quarters. While
we sort our loose change by coin type, we’ll also call out the name of the
Expand Down Expand Up @@ -119,12 +121,13 @@ operations.
This function is very easy to write, thanks to `match`, and will look like
Listing 6-5.

<Listing number="6-5" caption="A function that uses a `match` expression on an `Option<i32>`">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-05/src/main.rs:here}}
```

<span class="caption">Listing 6-5: A function that uses a `match` expression on
an `Option<i32>`</span>
</Listing>

Let’s examine the first execution of `plus_one` in more detail. When we call
`plus_one(five)`, the variable `x` in the body of `plus_one` will have the
Expand Down
5 changes: 3 additions & 2 deletions rustbook-en/src/ch06-03-if-let.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ program in Listing 6-6 that matches on an `Option<u8>` value in the
`config_max` variable but only wants to execute code if the value is the `Some`
variant.

<Listing number="6-6" caption="A `match` that only cares about executing code when the value is `Some`">

```rust
{{#rustdoc_include ../listings/ch06-enums-and-pattern-matching/listing-06-06/src/main.rs:here}}
```

<span class="caption">Listing 6-6: A `match` that only cares about executing
code when the value is `Some`</span>
</Listing>

If the value is `Some`, we print out the value in the `Some` variant by binding
the value to the variable `max` in the pattern. We don’t want to do anything
Expand Down
Loading

0 comments on commit b51c08a

Please sign in to comment.