Fix all broken links.
--- /dev/null
+name: "CI"
+
+on:
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ check-links:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout repository
+ uses: actions/checkout@v4
+ - name: Build book
+ run: |
+ cd book
+ curl -sSL https://github.com/rust-lang/mdBook/releases/download/v0.4.40/mdbook-v0.4.40-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=.
+ ./mdbook build
+ - name: Link Checker
+ uses: lycheeverse/lychee-action@v1
+ with:
+ fail: true
+ args: |
+ --exclude-loopback
+ --require-https
+ --no-progress
+ book/book
|
```
-We'll see how to convert between types [later in this course](../04_traits/09_from).
+We'll see how to convert between types [later in this course](../04_traits/09_from.md).
## References
[^traits]: Rust doesn't let you define custom operators, but it puts you in control of how the built-in operators
behave.
-We'll talk about operator overloading [later in the course](../04_traits/03_operator_overloading), after we've covered traits.
+We'll talk about operator overloading [later in the course](../04_traits/03_operator_overloading.md), after we've covered traits.
[^coercion]: There are some exceptions to this rule, mostly related to references, smart pointers and ergonomics. We'll
-cover those [later on](../04_traits/07_deref).
+cover those [later on](../04_traits/07_deref.md).
A mental model of "all conversions are explicit" will serve you well in the meantime.
# Panics
-Let's go back to the `speed` function you wrote for the ["Variables" section](02_variables).
+Let's go back to the `speed` function you wrote for the ["Variables" section](02_variables.md).
It probably looked something like this:
```rust
}
```
-There are other mechanisms to work with recoverable errors in Rust, which [we'll cover later](../05_ticket_v2/06_fallibility).
+There are other mechanisms to work with recoverable errors in Rust, which [we'll cover later](../05_ticket_v2/06_fallibility.md).
For the time being we'll stick with panics as a brutal but simple stopgap solution.
## References
As a rule of thumb, be quite careful with `as` casting.
Use it _exclusively_ for going from a smaller type to a larger type.
To convert from a larger to smaller integer type, rely on the
-[*fallible* conversion machinery](../05_ticket_v2/13_try_from) that we'll
+[*fallible* conversion machinery](../05_ticket_v2/13_try_from.md) that we'll
explore later in the course.
### Limitations
It is also fairly limited: you can only rely on `as` casting
for primitive types and a few other special cases.
When working with composite types, you'll have to rely on
-different conversion mechanisms ([fallible](../05_ticket_v2/13_try_from)
-and [infallible](../04_traits/09_from)), which we'll explore later on.
+different conversion mechanisms ([fallible](../05_ticket_v2/13_try_from.md)
+and [infallible](../04_traits/09_from.md)), which we'll explore later on.
## References
You've seen this in action in the previous exercise on visibility.
We now need to provide one or more public **constructors**—i.e. static methods or functions that can be used
from outside the module to create a new instance of the struct.
-Luckily enough we already have one: `Ticket::new`, as implemented in [a previous exercise](02_validation).
+Luckily enough we already have one: `Ticket::new`, as implemented in [a previous exercise](02_validation.md).
## Accessor methods
- The exercise for this section is located in `exercises/03_ticket_v1/05_encapsulation`
-[^newtype]: Or refine their type, a technique we'll explore [later on](../05_ticket_v2/15_outro).
\ No newline at end of file
+[^newtype]: Or refine their type, a technique we'll explore [later on](../05_ticket_v2/15_outro.md).
\ No newline at end of file
- The exercise for this section is located in `exercises/03_ticket_v1/10_references_in_memory`
-[^fat]: [Later in the course](../04_traits/06_str_slice) we'll talk about **fat pointers**,
+[^fat]: [Later in the course](../04_traits/06_str_slice.md) we'll talk about **fat pointers**,
i.e. pointers with additional metadata. As the name implies, they are larger than
the pointers we discussed in this chapter, also known as **thin pointers**.
You may wonder why we need trait bounds at all. Can't the compiler infer the required traits from the function's body?
It could, but it won't.
-The rationale is the same as for [explicit type annotations on function parameters](../02_basic_calculator/02_variables#function-arguments-are-variables):
+The rationale is the same as for [explicit type annotations on function parameters](../02_basic_calculator/02_variables.md#function-arguments-are-variables):
each function signature is a contract between the caller and the callee, and the terms must be explicitly stated.
This allows for better error messages, better documentation, less unintentional breakages across versions,
and faster compilation times.
it would have been reasonable to expect `&str` to be represented as a single `usize` on
the stack, a pointer. That's not the case though. `&str` stores some **metadata** next
to the pointer: the length of the slice it points to. Going back to the example from
-[a previous section](06_str_slice):
+[a previous section](06_str_slice.md):
```rust
let mut s = String::with_capacity(5);
# The `Drop` trait
-When we introduced [destructors](../03_ticket_v1/11_destructor),
+When we introduced [destructors](../03_ticket_v1/11_destructor.md),
we mentioned that the `drop` function:
1. reclaims the memory occupied by the type (i.e. `std::mem::size_of` bytes)
# Enumerations
-Based on the validation logic you wrote [in a previous chapter](../03_ticket_v1/02_validation),
+Based on the validation logic you wrote [in a previous chapter](../03_ticket_v1/02_validation.md),
there are only a few valid statuses for a ticket: `To-Do`, `InProgress` and `Done`.
This is not obvious if we look at the `status` field in the `Ticket` struct or at the type of the `status`
parameter in the `new` method:
- Be extremely careful when using `tokio`'s `select!` macro to "race" two different futures.
Retrying the same task in a loop is dangerous unless you can ensure **cancellation safety**.
- Check out [`select!`'s documentation](https://docs.rs/tokio/macro.select.html) for more details.
+ Check out [`select!`'s documentation](https://tokio.rs/tokio/tutorial/select) for more details.
If you need to interleave two asynchronous streams of data (e.g. a socket and a channel), prefer using
[`StreamExt::merge`](https://docs.rs/tokio-stream/latest/tokio_stream/trait.StreamExt.html#method.merge) instead.
- Rather than "abrupt" cancellation, it can be preferable to rely