diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index d77250c3..40a52603 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -147,6 +147,11 @@ jobs:
MDBOOK_OUTPUT='{"xgettext": {"pot-file": "messages.pot"}}' mdbook build -d po
msgfmt -o /dev/null --statistics po/messages.pot
+ - name: Install mdbook-linkcheck
+ # Opt-in for checking links in translations - add the language below.
+ if: contains(fromJSON('["en", ]'), matrix.language)
+ run: cargo install mdbook-linkcheck --locked --version 0.7.7
+
- name: Build ${{ matrix.language }} translation
run: |
.github/workflows/build.sh ${{ matrix.language }} book/comprehensive-rust-${{ matrix.language }}
diff --git a/README.md b/README.md
index ece42cb5..aaaa75cc 100644
--- a/README.md
+++ b/README.md
@@ -53,6 +53,10 @@ The course is built using a few tools:
- [mdbook-exerciser](mdbook-exerciser/)
- [mdbook-course](mdbook-course/)
+In addition,
+[mdbook-linkcheck](https://github.com/Michael-F-Bryan/mdbook-linkcheck) checks
+the internal links.
+
First install Rust by following the instructions on https://rustup.rs/. Then
clone this repository:
@@ -68,6 +72,7 @@ cargo install mdbook
cargo install --locked mdbook-svgbob
cargo install --locked mdbook-i18n-helpers
cargo install --locked i18n-report
+cargo install --locked mdbook-linkcheck
cargo install --locked --path mdbook-exerciser
cargo install --locked --path mdbook-course
```
diff --git a/book.toml b/book.toml
index b6f0ed95..9f4a6691 100644
--- a/book.toml
+++ b/book.toml
@@ -46,7 +46,7 @@ linkcolor = "blue"
urlcolor = "red"
[output.html]
-curly-quotes = true
+smart-punctuation = true
additional-js = [
"theme/speaker-notes.js",
]
@@ -278,3 +278,12 @@ use-boolean-and = true
[output.exerciser]
output-directory = "comprehensive-rust-exercises"
+
+[output.linkcheck]
+optional = true
+follow-web-links = false # change to true to check web links
+exclude = [
+ "comprehensive-rust.pdf",
+ "comprehensive-rust-exercises.zip",
+ # "crates.io", # uncomment when follow-web-links is true
+]
diff --git a/src/android/aidl/types/arrays.md b/src/android/aidl/types/arrays.md
index 7b278433..9bd1d5b8 100644
--- a/src/android/aidl/types/arrays.md
+++ b/src/android/aidl/types/arrays.md
@@ -13,8 +13,8 @@ signature:
- In Android 13 or higher, fixed-size arrays are supported, i.e. `T[N]` becomes
- `[T; N]`. Fixed-size arrays can have multiple dimensions (e.g. int[3][4]). In
- the Java backend, fixed-size arrays are represented as array types.
+ `[T; N]`. Fixed-size arrays can have multiple dimensions (e.g. `int[3][4]`).
+ In the Java backend, fixed-size arrays are represented as array types.
- Arrays in parcelable fields always get translated to `Vec`.
diff --git a/src/android/interoperability/with-c.md b/src/android/interoperability/with-c.md
index de6ab3c2..ddbe7bbb 100644
--- a/src/android/interoperability/with-c.md
+++ b/src/android/interoperability/with-c.md
@@ -19,7 +19,7 @@ fn main() {
```
We already saw this in the
-[Safe FFI Wrapper exercise](../../exercises/day-3/safe-ffi-wrapper.md).
+[Safe FFI Wrapper exercise](../../unsafe-rust/exercise.md).
> This assumes full knowledge of the target platform. Not recommended for
> production.
diff --git a/src/concurrency/async-exercises/dining-philosophers.md b/src/concurrency/async-exercises/dining-philosophers.md
index 44c54df2..e84d53b3 100644
--- a/src/concurrency/async-exercises/dining-philosophers.md
+++ b/src/concurrency/async-exercises/dining-philosophers.md
@@ -4,8 +4,8 @@ minutes: 20
# Dining Philosophers --- Async
-See [dining philosophers](concurrency/sync-exercises/dining-philosophers.md) for
-a description of the problem.
+See [dining philosophers](../sync-exercises/dining-philosophers.md) for a
+description of the problem.
As before, you will need a local
[Cargo installation](../../cargo/running-locally.md) for this exercise. Copy the
diff --git a/src/concurrency/shared-state/mutex.md b/src/concurrency/shared-state/mutex.md
index 555ee55f..57721a18 100644
--- a/src/concurrency/shared-state/mutex.md
+++ b/src/concurrency/shared-state/mutex.md
@@ -6,7 +6,7 @@ minutes: 14
[`Mutex`][1] ensures mutual exclusion _and_ allows mutable access to `T`
behind a read-only interface (another form of
-[interior mutability](../../borrowing/interior-mutability)):
+[interior mutability](../../borrowing/interior-mutability.md)):
```rust,editable
use std::sync::Mutex;
diff --git a/src/glossary.md b/src/glossary.md
index 275587cc..c00c255e 100644
--- a/src/glossary.md
+++ b/src/glossary.md
@@ -29,16 +29,16 @@ h1#glossary ~ ul > li:first-line {
- allocate:\
- Dynamic memory allocation on [the heap](memory-management/stack-vs-heap.md).
+ Dynamic memory allocation on [the heap](memory-management/review.md).
- argument:\
Information that is passed into a function or method.
- Bare-metal Rust:\
Low-level Rust development, often deployed to a system without an operating
system. See [Bare-metal Rust](bare-metal.md).
- block:\
- See [Blocks](control-flow/blocks.md) and _scope_.
+ See [Blocks](control-flow-basics/blocks-and-scopes.md) and _scope_.
- borrow:\
- See [Borrowing](ownership/borrowing.md).
+ See [Borrowing](borrowing/shared.md).
- borrow checker:\
The part of the Rust compiler which checks that all borrows are valid.
- brace:\
@@ -55,7 +55,7 @@ h1#glossary ~ ul > li:first-line {
- concurrency:\
The execution of multiple tasks or processes at the same time.
- Concurrency in Rust:\
- See [Concurrency in Rust](concurrency.md).
+ See [Concurrency in Rust](concurrency/welcome.md).
- constant:\
A value that does not change during the execution of a program.
- control flow:\
@@ -199,6 +199,6 @@ h1#glossary ~ ul > li:first-line {
Type that holds no data, written as a tuple with no members.
- unsafe:\
The subset of Rust which allows you to trigger _undefined behavior_. See
- [Unsafe Rust](unsafe.html).
+ [Unsafe Rust](unsafe-rust/unsafe.md).
- variable:\
A memory location storing data. Variables are valid in a _scope_.
diff --git a/src/index.md b/src/index.md
index 08eb1d1b..a0f2f7f1 100644
--- a/src/index.md
+++ b/src/index.md
@@ -38,9 +38,10 @@ Building on this, you're invited to dive into one or more specialized topics:
- [Bare-metal](bare-metal.md): a whole-day class on using Rust for bare-metal
(embedded) development. Both microcontrollers and application processors are
covered.
-- [Concurrency](concurrency.md): a whole-day class on concurrency in Rust. We
- cover both classical concurrency (preemptively scheduling using threads and
- mutexes) and async/await concurrency (cooperative multitasking using futures).
+- [Concurrency](concurrency/welcome.md): a whole-day class on concurrency in
+ Rust. We cover both classical concurrency (preemptively scheduling using
+ threads and mutexes) and async/await concurrency (cooperative multitasking
+ using futures).
## Non-Goals
diff --git a/src/other-resources.md b/src/other-resources.md
index 3e684260..531de74e 100644
--- a/src/other-resources.md
+++ b/src/other-resources.md
@@ -36,7 +36,7 @@ A small selection of other guides and tutorial for Rust:
- [Learn Rust the Dangerous Way](http://cliffle.com/p/dangerust/): covers Rust
from the perspective of low-level C programmers.
-- [Rust for Embedded C Programmers](https://docs.opentitan.org/doc/ug/rust_for_c/):
+- [Rust for Embedded C Programmers](https://opentitan.org/book/doc/rust_for_c_devs.html):
covers Rust from the perspective of developers who write firmware in C.
- [Rust for professionals](https://overexact.com/rust-for-professionals/):
covers the syntax of Rust using side-by-side comparisons with other languages
diff --git a/src/running-the-course/course-structure.md b/src/running-the-course/course-structure.md
index bf0334fe..d47e56d0 100644
--- a/src/running-the-course/course-structure.md
+++ b/src/running-the-course/course-structure.md
@@ -56,8 +56,8 @@ Everybody will need to install a number of packages as described on the
### Concurrency in Rust
-The [Concurrency in Rust](../concurrency.md) deep dive is a full day class on
-classical as well as `async`/`await` concurrency.
+The [Concurrency in Rust](../concurrency/welcome.md) deep dive is a full day
+class on classical as well as `async`/`await` concurrency.
You will need a fresh crate set up and the dependencies downloaded and ready to
go. You can then copy/paste the examples into `src/main.rs` to experiment with
diff --git a/src/running-the-course/translations.md b/src/running-the-course/translations.md
index 0625347d..4c1cf2cc 100644
--- a/src/running-the-course/translations.md
+++ b/src/running-the-course/translations.md
@@ -6,7 +6,7 @@ volunteers:
- [Brazilian Portuguese][pt-BR] by [@rastringer], [@hugojacob],
[@joaovicmendes], and [@henrif75].
- [Chinese (Simplified)][zh-CN] by [@suetfei], [@wnghl], [@anlunx], [@kongy],
- [@noahdragon], [@superwhd], [@SketchK], and [@nodmp].
+ [@noahdragon], [@superwhd], @SketchK, and [@nodmp].
- [Chinese (Traditional)][zh-TW] by [@hueich], [@victorhsieh], [@mingyc],
[@kuanhungchen], and [@johnathan79717].
- [Japanese][ja] by [@CoinEZ-JPN], [@momotaro1105], [@HidenoriKobayashi] and
@@ -76,7 +76,6 @@ get going. Translations are coordinated on the [issue tracker].
[@rastringer]: https://github.com/rastringer
[@reta]: https://github.com/reta
[@ronaldfw]: https://github.com/ronaldfw
-[@SketchK]: https://github.com/SketchK
[@suetfei]: https://github.com/suetfei
[@superwhd]: https://github.com/superwhd
[@Throvn]: https://github.com/Throvn
diff --git a/src/smart-pointers/rc.md b/src/smart-pointers/rc.md
index 6b55d5f4..525b3e66 100644
--- a/src/smart-pointers/rc.md
+++ b/src/smart-pointers/rc.md
@@ -24,7 +24,7 @@ fn main() {
cycles that will get dropped.
[1]: https://doc.rust-lang.org/std/rc/struct.Rc.html
-[2]: ../concurrency/shared_state/arc.md
+[2]: ../concurrency/shared-state/arc.md
[3]: https://doc.rust-lang.org/std/sync/struct.Mutex.html
[4]: https://doc.rust-lang.org/std/rc/struct.Weak.html