From: Luca Palmieri <20745048+LukeMathWalker@users.noreply.github.com> Date: Fri, 24 May 2024 14:45:59 +0000 (+0200) Subject: Add CI job to verify that we have no broken links. (#50) X-Git-Url: http://git.euphorik.ch/index.cgi?a=commitdiff_plain;h=f388b2a6c34b6d5b6a1f08674956cac08039f932;p=rust_exercises.git Add CI job to verify that we have no broken links. (#50) Fix all broken links. --- diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..ceaefa7 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +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 diff --git a/book/src/02_basic_calculator/01_integers.md b/book/src/02_basic_calculator/01_integers.md index 7fb37b1..763bc8a 100644 --- a/book/src/02_basic_calculator/01_integers.md +++ b/book/src/02_basic_calculator/01_integers.md @@ -117,7 +117,7 @@ error[E0308]: mismatched types | ``` -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 @@ -131,8 +131,8 @@ We'll see how to convert between types [later in this course](../04_traits/09_fr [^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. diff --git a/book/src/02_basic_calculator/04_panics.md b/book/src/02_basic_calculator/04_panics.md index fa658fa..9132741 100644 --- a/book/src/02_basic_calculator/04_panics.md +++ b/book/src/02_basic_calculator/04_panics.md @@ -1,6 +1,6 @@ # 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 @@ -38,7 +38,7 @@ fn main() { } ``` -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 diff --git a/book/src/02_basic_calculator/10_as_casting.md b/book/src/02_basic_calculator/10_as_casting.md index 92ffc86..258a8ae 100644 --- a/book/src/02_basic_calculator/10_as_casting.md +++ b/book/src/02_basic_calculator/10_as_casting.md @@ -82,7 +82,7 @@ error: literal out of range for `i8` 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 @@ -91,8 +91,8 @@ Surprising behaviour is not the only downside of `as` casting. 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 diff --git a/book/src/03_ticket_v1/05_encapsulation.md b/book/src/03_ticket_v1/05_encapsulation.md index f01b1b8..4f511e6 100644 --- a/book/src/03_ticket_v1/05_encapsulation.md +++ b/book/src/03_ticket_v1/05_encapsulation.md @@ -38,7 +38,7 @@ let ticket = Ticket { 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 @@ -60,4 +60,4 @@ You have to write them yourself—they're just regular 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 diff --git a/book/src/03_ticket_v1/10_references_in_memory.md b/book/src/03_ticket_v1/10_references_in_memory.md index e7c208f..e7363bb 100644 --- a/book/src/03_ticket_v1/10_references_in_memory.md +++ b/book/src/03_ticket_v1/10_references_in_memory.md @@ -49,6 +49,6 @@ They just point to a memory location, which _may_ be on the heap, but doesn't ha - 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**. diff --git a/book/src/04_traits/05_trait_bounds.md b/book/src/04_traits/05_trait_bounds.md index a118b1b..5f321e5 100644 --- a/book/src/04_traits/05_trait_bounds.md +++ b/book/src/04_traits/05_trait_bounds.md @@ -166,7 +166,7 @@ Follow Rust's conventions though: use camel case for type parameter names. 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. diff --git a/book/src/04_traits/08_sized.md b/book/src/04_traits/08_sized.md index 57d0d38..7b7e842 100644 --- a/book/src/04_traits/08_sized.md +++ b/book/src/04_traits/08_sized.md @@ -6,7 +6,7 @@ From our previous [discussion on memory layouts](../03_ticket_v1/10_references_i 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); diff --git a/book/src/04_traits/13_drop.md b/book/src/04_traits/13_drop.md index ff1c54a..6a19321 100644 --- a/book/src/04_traits/13_drop.md +++ b/book/src/04_traits/13_drop.md @@ -1,6 +1,6 @@ # 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) diff --git a/book/src/05_ticket_v2/01_enum.md b/book/src/05_ticket_v2/01_enum.md index d7bfadc..90eb677 100644 --- a/book/src/05_ticket_v2/01_enum.md +++ b/book/src/05_ticket_v2/01_enum.md @@ -1,6 +1,6 @@ # 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: diff --git a/book/src/08_futures/07_cancellation.md b/book/src/08_futures/07_cancellation.md index 70c1954..bad51e7 100644 --- a/book/src/08_futures/07_cancellation.md +++ b/book/src/08_futures/07_cancellation.md @@ -102,7 +102,7 @@ async fn run() { - 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