Compare commits
44 Commits
9e63a5cdf6
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8791feb495 | ||
|
|
a2fe212f44 | ||
|
|
20a2b45e49 | ||
|
|
c3cb1b38f6 | ||
|
|
af4fe9cedb | ||
|
|
21f3427c92 | ||
|
|
b839c770b5 | ||
|
|
fd23b201fe | ||
|
|
13850a6b01 | ||
|
|
a7865baf3c | ||
|
|
0e1c66814d | ||
|
|
2f059fc5ba | ||
|
|
63402ef5c2 | ||
|
|
892c37ead9 | ||
|
|
c745cf8ddd | ||
|
|
3f60de3712 | ||
|
|
36f6375c20 | ||
|
|
fb19005d5f | ||
|
|
cc0092b2c6 | ||
|
|
d5e1c00108 | ||
|
|
60947aaacd | ||
|
|
fe40e6e2d0 | ||
|
|
7fb0910b39 | ||
|
|
468b74ba4d | ||
|
|
b0e1e5a1ec | ||
|
|
93536fbcfd | ||
|
|
1993507236 | ||
|
|
a1a2dc1588 | ||
|
|
51cad6bdfe | ||
|
|
ab1eb5d80c | ||
|
|
fd6a56fd84 | ||
|
|
0419e2e8b2 | ||
|
|
4b02e92691 | ||
|
|
eb2d858807 | ||
|
|
4194ee9998 | ||
|
|
9f5e4a0d76 | ||
|
|
da610ee79b | ||
|
|
f1a0eab4a6 | ||
|
|
3addd64dc2 | ||
|
|
a53e4f86a1 | ||
|
|
5edddf102e | ||
|
|
dab563a329 | ||
|
|
c75ff98c6a | ||
|
|
b60e021ab1 |
25
.github/workflows/ci.yml
vendored
25
.github/workflows/ci.yml
vendored
@@ -56,7 +56,7 @@ jobs:
|
||||
echo "$PWD/pandoc-${PANDOC_VERSION}/bin" >> $GITHUB_PATH
|
||||
shell: bash
|
||||
- name: Setup TeX Live
|
||||
uses: teatimeguest/setup-texlive-action@v3
|
||||
uses: TeX-Live/setup-texlive-action@v3
|
||||
with:
|
||||
packages:
|
||||
scheme-basic
|
||||
@@ -111,9 +111,9 @@ jobs:
|
||||
with:
|
||||
fail: true
|
||||
args: |
|
||||
--exclude-loopback
|
||||
--require-https
|
||||
--no-progress
|
||||
--exclude-loopback
|
||||
--require-https
|
||||
--no-progress
|
||||
book/book/html/
|
||||
# Upload the HTML book as an artifact
|
||||
- uses: actions/upload-artifact@v4
|
||||
@@ -146,6 +146,23 @@ jobs:
|
||||
- run: |
|
||||
git diff --exit-code site/_redirects
|
||||
|
||||
gravity:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [build]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: book
|
||||
pattern: online-pdf
|
||||
- uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 9
|
||||
- run: ls -las ./book
|
||||
- name: Run Gravity
|
||||
run: pnpm dlx @gravityci/cli "./book/**/*"
|
||||
env:
|
||||
GRAVITY_TOKEN: ${{ secrets.GRAVITY_TOKEN }}
|
||||
|
||||
formatter:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
1927
Cargo.lock
generated
1927
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -18,6 +18,9 @@ after = ["exercise-linker"]
|
||||
[output.html]
|
||||
git-repository-url = "https://github.com/mainmatter/100-exercises-to-learn-rust"
|
||||
|
||||
[output.html.playground]
|
||||
runnable = false
|
||||
|
||||
[output.pandoc]
|
||||
optional = true
|
||||
hosted-html = "https://rust-exercises.com/100-exercises/"
|
||||
@@ -49,8 +52,8 @@ sansfontoptions = [
|
||||
]
|
||||
# You can get these fonts here: https://fonts.google.com/selection?query=noto+color+
|
||||
monofont = "Noto Sans Mono"
|
||||
mainfontfallback = ["Open Sans"]
|
||||
sansfontfallback = ["Open Sans"]
|
||||
mainfontfallback = ["Open Sans:style=Regular"]
|
||||
sansfontfallback = ["Open Sans:style=Regular"]
|
||||
monofontfallback = [
|
||||
"Noto Color Emoji:mode=harf",
|
||||
]
|
||||
@@ -90,8 +93,8 @@ sansfontoptions = [
|
||||
]
|
||||
# You can get these fonts here: https://fonts.google.com/selection?query=noto+color+
|
||||
monofont = "Noto Sans Mono"
|
||||
mainfontfallback = ["Open Sans"]
|
||||
sansfontfallback = ["Open Sans"]
|
||||
mainfontfallback = ["Open Sans:style=Regular"]
|
||||
sansfontfallback = ["Open Sans:style=Regular"]
|
||||
monofontfallback = [
|
||||
"Noto Color Emoji:mode=harf",
|
||||
]
|
||||
@@ -121,8 +124,8 @@ metadata-file = "metadata.yml"
|
||||
[output.pandoc.profile.html.variables]
|
||||
# You can get these fonts here: https://fonts.google.com/selection?query=noto+color+
|
||||
monofont = "Noto Sans Mono"
|
||||
mainfontfallback = ["Open Sans"]
|
||||
sansfontfallback = ["Open Sans"]
|
||||
mainfontfallback = ["Open Sans:style=Regular"]
|
||||
sansfontfallback = ["Open Sans:style=Regular"]
|
||||
monofontfallback = [
|
||||
"Noto Color Emoji:mode=harf",
|
||||
]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"https://blog.acolyer.org/2019/05/28/cheri-abi/": "f2u",
|
||||
"https://code.visualstudio.com": "f6c",
|
||||
"https://crates.io": "f4q",
|
||||
"https://crates.io/crates/cargo-modules": "f2n",
|
||||
"https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types": "ffr",
|
||||
@@ -163,7 +163,9 @@
|
||||
"https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/": "f4r",
|
||||
"https://mainmatter.com/contact/": "ff2",
|
||||
"https://mainmatter.com/rust-consulting/": "fff",
|
||||
"https://mainmatter.github.io/rust-workshop-runner/": "fv2",
|
||||
"https://marabos.nl/atomics/": "fxg",
|
||||
"https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer": "f6a",
|
||||
"https://nostarch.com/rust-rustaceans": "f6p",
|
||||
"https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory": "f2k",
|
||||
"https://owasp.org/www-community/vulnerabilities/Using_freed_memory": "f2s",
|
||||
@@ -177,14 +179,18 @@
|
||||
"https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case": "fze",
|
||||
"https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_battles_buffered_streams.html": "f6w",
|
||||
"https://ryhl.io/blog/async-what-is-blocking/": "f6v",
|
||||
"https://ti.to/mainmatter/rust-from-scratch-jan-2025": "fvf",
|
||||
"https://tokio.rs/tokio/tutorial/select": "f6n",
|
||||
"https://valgrind.org/docs/manual/dh-manual.html": "f2t",
|
||||
"https://veykril.github.io/tlborm/": "fz5",
|
||||
"https://web.archive.org/web/20240517051950/https://blog.acolyer.org/2019/05/28/cheri-abi/": "f2u",
|
||||
"https://without.boats/blog/the-scoped-task-trilemma/": "f67",
|
||||
"https://www.amazon.com/dp/B0DJ14KQQG/": "f6g",
|
||||
"https://www.jetbrains.com/rust/": "f6d",
|
||||
"https://www.lpalmieri.com/": "ffv",
|
||||
"https://www.lpalmieri.com/posts/2020-12-11-zero-to-production-6-domain-modelling/": "f4t",
|
||||
"https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/": "f6y",
|
||||
"https://www.rust-lang.org/tools/install": "f6j",
|
||||
"https://www.youtube.com/playlist?list=PLqbS7AVVErFirH9armw8yXlE6dacF-A6z": "f6l",
|
||||
"https://zero2prod.com": "ff8"
|
||||
}
|
||||
@@ -24,12 +24,12 @@ It has been designed to be interactive and hands-on.
|
||||
to be delivered in a classroom setting, over 4 days: each attendee advances
|
||||
through the lessons at their own pace, with an experienced instructor providing
|
||||
guidance, answering questions and diving deeper into the topics as needed.\
|
||||
If you're interested in attending one of our training sessions, or if you'd like to
|
||||
bring this course to your company, please [get in touch](https://mainmatter.com/contact/).
|
||||
You can sign up for the next tutored session on [our website](https://ti.to/mainmatter/rust-from-scratch-jan-2025).
|
||||
If you'd like to organise a private session for your company, please [get in touch](https://mainmatter.com/contact/).
|
||||
|
||||
You can also follow the course on your own, but we recommend you find a friend or
|
||||
You can also take the courses on your own, but we recommend you find a friend or
|
||||
a mentor to help you along the way should you get stuck. You can
|
||||
also find solutions to all exercises in the
|
||||
find solutions for all exercises in the
|
||||
[`solutions` branch of the GitHub repository](https://github.com/mainmatter/100-exercises-to-learn-rust/tree/solutions).
|
||||
|
||||
## Formats
|
||||
@@ -67,17 +67,23 @@ Each exercise is structured as a Rust package.
|
||||
The package contains the exercise itself, instructions on what to do (in `src/lib.rs`), and a test suite to
|
||||
automatically verify your solution.
|
||||
|
||||
### `wr`, the workshop runner
|
||||
### Tools
|
||||
|
||||
To verify your solutions, we've provided a tool that will guide you through the course.
|
||||
It is the `wr` CLI (short for "workshop runner").
|
||||
Install it with:
|
||||
To work through this course, you'll need:
|
||||
|
||||
```bash
|
||||
cargo install --locked workshop-runner
|
||||
```
|
||||
- [**Rust**](https://www.rust-lang.org/tools/install).
|
||||
If `rustup` is already installed on your system, run `rustup update` (or another appropriate command depending on how you installed Rust on your system) to ensure you're running on the latest stable version.
|
||||
- _(Optional but recommended)_ An IDE with Rust autocompletion support.
|
||||
We recommend one of the following:
|
||||
- [RustRover](https://www.jetbrains.com/rust/);
|
||||
- [Visual Studio Code](https://code.visualstudio.com) with the [`rust-analyzer`](https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer) extension.
|
||||
|
||||
In a new terminal, navigate back to the top-level folder of the repository.
|
||||
### Workshop runner, `wr`
|
||||
|
||||
To verify your solutions, we've also provided a tool to guide you through the course: the `wr` CLI, short for "workshop runner".
|
||||
Install `wr` by following the instructions on [its website](https://mainmatter.github.io/rust-workshop-runner/).
|
||||
|
||||
Once you have `wr` installed, open a new terminal and navigate to the top-level folder of the repository.
|
||||
Run the `wr` command to start the course:
|
||||
|
||||
```bash
|
||||
|
||||
@@ -36,6 +36,38 @@ if number < 5 {
|
||||
}
|
||||
```
|
||||
|
||||
### `else if` clauses
|
||||
|
||||
Your code drifts more and more to the right when you have multiple `if` expressions, one nested inside the other.
|
||||
|
||||
```rust
|
||||
let number = 3;
|
||||
|
||||
if number < 5 {
|
||||
println!("`number` is smaller than 5");
|
||||
} else {
|
||||
if number >= 3 {
|
||||
println!("`number` is greater than or equal to 3, but smaller than 5");
|
||||
} else {
|
||||
println!("`number` is smaller than 3");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
You can use the `else if` keyword to combine multiple `if` expressions into a single one:
|
||||
|
||||
```rust
|
||||
let number = 3;
|
||||
|
||||
if number < 5 {
|
||||
println!("`number` is smaller than 5");
|
||||
} else if number >= 3 {
|
||||
println!("`number` is greater than or equal to 3, but smaller than 5");
|
||||
} else {
|
||||
println!("`number` is smaller than 3");
|
||||
}
|
||||
```
|
||||
|
||||
## Booleans
|
||||
|
||||
The condition in an `if` expression must be of type `bool`, a **boolean**.\
|
||||
|
||||
@@ -75,16 +75,14 @@ development,
|
||||
therefore it sacrifices runtime performance in favor of faster compilation times and a better debugging experience.\
|
||||
The `release` profile, instead, is optimized for runtime performance but incurs longer compilation times. You need
|
||||
to explicitly request via the `--release` flag—e.g. `cargo build --release` or `cargo run --release`.
|
||||
The `test` profile is the default profile used by `cargo test`. The `test` profile inherits the settings form the `dev` profile.
|
||||
The `test` profile is the default profile used by `cargo test`. The `test` profile inherits the settings from the `dev` profile.
|
||||
The `bench` profile is the default profile used by `cargo bench`. The `bench` profile inherits from the `release` profile.
|
||||
Use `dev` for iterative development and debugging, `release` for optimized production builds,\
|
||||
`test` for correctness testing, and `bench` for performance benchmarking.
|
||||
|
||||
|
||||
|
||||
> "Have you built your project in release mode?" is almost a meme in the Rust community.\
|
||||
> It refers to developers who are not familiar with Rust and complain about its performance on
|
||||
> social media (e.g. Reddit, Twitter, etc.) before realizing they haven't built their project in
|
||||
> social media (e.g. Reddit, Twitter) before realizing they haven't built their project in
|
||||
> release mode.
|
||||
|
||||
You can also define custom profiles or customize the built-in ones.
|
||||
|
||||
@@ -85,6 +85,9 @@ You can compose the path in various ways:
|
||||
- starting from the parent module, e.g. `super::my_function`
|
||||
- starting from the current module, e.g. `sub_module_1::MyStruct`
|
||||
|
||||
Both `crate` and `super` are **keywords**.\
|
||||
`crate` refers to the root of the current crate, while `super` refers to the parent of the current module.
|
||||
|
||||
Having to write the full path every time you want to refer to a type can be cumbersome.
|
||||
To make your life easier, you can introduce a `use` statement to bring the entity into scope.
|
||||
|
||||
|
||||
@@ -137,6 +137,6 @@ or [a custom allocator](https://docs.rs/dhat/latest/dhat/)) to inspect the heap
|
||||
Heap memory will be reserved when you push data into it for the first time.
|
||||
|
||||
[^equivalence]: The size of a pointer depends on the operating system too.
|
||||
In certain environments, a pointer is **larger** than a memory address (e.g. [CHERI](https://blog.acolyer.org/2019/05/28/cheri-abi/)).
|
||||
In certain environments, a pointer is **larger** than a memory address (e.g. [CHERI](https://web.archive.org/web/20240517051950/https://blog.acolyer.org/2019/05/28/cheri-abi/)).
|
||||
Rust makes the simplifying assumption that pointers are the same size as memory addresses,
|
||||
which is true for most modern systems you're likely to encounter.
|
||||
|
||||
@@ -56,7 +56,7 @@ that to `consumer` instead.\
|
||||
## In memory
|
||||
|
||||
Let's look at what happened in memory in the example above.
|
||||
When `let mut s: String::from("hello");` is executed, the memory looks like this:
|
||||
When `let mut s = String::from("hello");` is executed, the memory looks like this:
|
||||
|
||||
```text
|
||||
s
|
||||
|
||||
@@ -68,3 +68,11 @@ match status {
|
||||
```
|
||||
|
||||
The `_` pattern matches anything that wasn't matched by the previous patterns.
|
||||
|
||||
<div class="warning">
|
||||
By using this catch-all pattern, you _won't_ get the benefits of compiler-driven refactoring.
|
||||
If you add a new enum variant, the compiler _won't_ tell you that you're not handling it.
|
||||
|
||||
If you're keen on correctness, avoid using catch-alls. Leverage the compiler to re-examine all matching sites and determine how new enum variants should be handled.
|
||||
|
||||
</div>
|
||||
|
||||
@@ -64,7 +64,7 @@ match status {
|
||||
println!("Assigned to: {}", assigned_to);
|
||||
},
|
||||
Status::ToDo | Status::Done => {
|
||||
println!("Done");
|
||||
println!("ToDo or Done");
|
||||
}
|
||||
}
|
||||
```
|
||||
@@ -82,7 +82,7 @@ match status {
|
||||
println!("Assigned to: {}", person);
|
||||
},
|
||||
Status::ToDo | Status::Done => {
|
||||
println!("Done");
|
||||
println!("ToDo or Done");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -21,6 +21,15 @@ let numbers: [u32; 3] = [1, 2, 3];
|
||||
This creates an array of 3 integers, initialized with the values `1`, `2`, and `3`.\
|
||||
The type of the array is `[u32; 3]`, which reads as "an array of `u32`s with a length of 3".
|
||||
|
||||
If all array elements are the same, you can use a shorter syntax to initialize it:
|
||||
|
||||
```rust
|
||||
// [ <value> ; <number of elements> ]
|
||||
let numbers: [u32; 3] = [1; 3];
|
||||
```
|
||||
|
||||
`[1; 3]` creates an array of three elements, all equal to `1`.
|
||||
|
||||
### Accessing elements
|
||||
|
||||
You can access elements of an array using square brackets:
|
||||
|
||||
@@ -38,7 +38,7 @@ When the process exits, the operating system will reclaim that memory.
|
||||
|
||||
Keeping this in mind, it can be OK to leak memory when:
|
||||
|
||||
- The amount of memory you need to leak is not unbounded/known upfront, or
|
||||
- The amount of memory you need to leak is bounded/known upfront, or
|
||||
- Your process is short-lived and you're confident you won't exhaust
|
||||
all the available memory before it exits
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ Let's unpack what's happening.
|
||||
## `scope`
|
||||
|
||||
The `std::thread::scope` function creates a new **scope**.\
|
||||
`std::thread::scope` takes as input a closure, with a single argument: a `Scope` instance.
|
||||
`std::thread::scope` takes a closure as input, with a single argument: a `Scope` instance.
|
||||
|
||||
## Scoped spawns
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ drop(guard)
|
||||
## Locking granularity
|
||||
|
||||
What should our `Mutex` wrap?\
|
||||
The simplest option would be the wrap the entire `TicketStore` in a single `Mutex`.\
|
||||
The simplest option would be to wrap the entire `TicketStore` in a single `Mutex`.\
|
||||
This would work, but it would severely limit the system's performance: you wouldn't be able to read tickets in parallel,
|
||||
because every read would have to wait for the lock to be released.\
|
||||
This is known as **coarse-grained locking**.
|
||||
|
||||
@@ -5,20 +5,20 @@ Before we wrap up this chapter, let's talk about another key trait in Rust's sta
|
||||
`Sync` is an auto trait, just like `Send`.\
|
||||
It is automatically implemented by all types that can be safely **shared** between threads.
|
||||
|
||||
In order words: `T: Sync` means that `&T` is `Send`.
|
||||
In other words: `T` is Sync if `&T` is `Send`.
|
||||
|
||||
## `Sync` doesn't imply `Send`
|
||||
## `T: Sync` doesn't imply `T: Send`
|
||||
|
||||
It's important to note that `Sync` doesn't imply `Send`.\
|
||||
It's important to note that `T` can be `Sync` without being `Send`.\
|
||||
For example: `MutexGuard` is not `Send`, but it is `Sync`.
|
||||
|
||||
It isn't `Send` because the lock must be released on the same thread that acquired it, therefore we don't
|
||||
want `MutexGuard` to be dropped on a different thread.\
|
||||
But it is `Sync`, because giving a `&MutexGuard` to another thread has no impact on where the lock is released.
|
||||
|
||||
## `Send` doesn't imply `Sync`
|
||||
## `T: Send` doesn't imply `T: Sync`
|
||||
|
||||
The opposite is also true: `Send` doesn't imply `Sync`.\
|
||||
The opposite is also true: `T` can be `Send` without being `Sync`.\
|
||||
For example: `RefCell<T>` is `Send` (if `T` is `Send`), but it is not `Sync`.
|
||||
|
||||
`RefCell<T>` performs runtime borrow checking, but the counters it uses to track borrows are not thread-safe.
|
||||
|
||||
@@ -26,7 +26,7 @@ at any given time.
|
||||
|
||||
### Multithreaded runtime
|
||||
|
||||
When using the multithreaded runtime, instead, there can up to `N` tasks running
|
||||
When using the multithreaded runtime, instead, there can be up to `N` tasks running
|
||||
_in parallel_ at any given time, where `N` is the number of threads used by the
|
||||
runtime. By default, `N` matches the number of available CPU cores.
|
||||
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "welcome_00"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "syntax"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "intro_01"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "integers"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
fn compute(a: u32, b: u32) -> u32 {
|
||||
// TODO: change the line below to fix the compiler error and make the tests pass.
|
||||
a + b * 4u8
|
||||
let multiplier: u8 = 4;
|
||||
a + b * multiplier
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "variables"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "if_else"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -1,24 +1,36 @@
|
||||
/// Return `true` if `n` is even, `false` otherwise.
|
||||
fn is_even(n: u32) -> bool {
|
||||
/// Return `12` if `n` is even,
|
||||
/// `13` if `n` is divisible by `3`,
|
||||
/// `17` otherwise.
|
||||
fn magic_number(n: u32) -> u32 {
|
||||
todo!()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::is_even;
|
||||
use crate::magic_number;
|
||||
|
||||
#[test]
|
||||
fn one() {
|
||||
assert!(!is_even(1));
|
||||
assert_eq!(magic_number(1), 17);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn two() {
|
||||
assert!(is_even(2));
|
||||
assert_eq!(magic_number(2), 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn six() {
|
||||
assert_eq!(magic_number(6), 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nine() {
|
||||
assert_eq!(magic_number(9), 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn high() {
|
||||
assert!(!is_even(231));
|
||||
assert_eq!(magic_number(233), 17);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "panics"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "factorial"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "while_"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "for_"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "overflow"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "saturating"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "as_cast"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "intro_02"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "struct_"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -5,3 +5,9 @@ edition = "2021"
|
||||
|
||||
[dev-dependencies]
|
||||
common = { path = "../../../helpers/common" }
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -2,3 +2,9 @@
|
||||
name = "modules"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[lints.rust]
|
||||
# We silence dead code warnings for the time being in order to reduce
|
||||
# compiler noise.
|
||||
# We'll re-enable them again once we explain how visibility works in Rust.
|
||||
dead_code = "allow"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// TODO: based on what we just learned about ownership, it sounds like immutable references
|
||||
// are a good fit for our accessor methods.
|
||||
// Change the existing implementation of `Ticket`'s accessor methods take a reference
|
||||
// Change the existing implementation of `Ticket`'s accessor methods to take a reference
|
||||
// to `self` as an argument, rather than taking ownership of it.
|
||||
|
||||
pub struct Ticket {
|
||||
|
||||
@@ -4,7 +4,7 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.59"
|
||||
thiserror = "1.0.69"
|
||||
|
||||
[dev-dependencies]
|
||||
common = { path = "../../../helpers/common" }
|
||||
|
||||
@@ -5,6 +5,9 @@ use ticket_fields::{TicketDescription, TicketTitle};
|
||||
// it contains using a `for` loop.
|
||||
//
|
||||
// Hint: you shouldn't have to implement the `Iterator` trait in this case.
|
||||
// You want to *delegate* the iteration to the `Vec<Ticket>` field in `TicketStore`.
|
||||
// Look at the standard library documentation for `Vec` to find the right type
|
||||
// to return from `into_iter`.
|
||||
#[derive(Clone)]
|
||||
pub struct TicketStore {
|
||||
tickets: Vec<Ticket>,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
use ticket_fields::{TicketDescription, TicketTitle};
|
||||
|
||||
// TODO: Provide an `iter` method that returns an iterator over `&Ticket` items.
|
||||
//
|
||||
// Hint: just like in the previous exercise, you want to delegate the iteration to
|
||||
// the `Vec<Ticket>` field in `TicketStore`. Look at the standard library documentation
|
||||
// for `Vec` to find the right type to return from `iter`.
|
||||
#[derive(Clone)]
|
||||
pub struct TicketStore {
|
||||
tickets: Vec<Ticket>,
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.59"
|
||||
thiserror = "1.0.69"
|
||||
ticket_fields = { path = "../../../helpers/ticket_fields" }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.60"
|
||||
thiserror = "1.0.69"
|
||||
ticket_fields = { path = "../../../helpers/ticket_fields" }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "1.0.60"
|
||||
thiserror = "1.0.69"
|
||||
ticket_fields = { path = "../../../helpers/ticket_fields" }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.83"
|
||||
anyhow = "1.0.100"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.83"
|
||||
anyhow = "1.0.100"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.83"
|
||||
anyhow = "1.0.100"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -4,5 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.83"
|
||||
anyhow = "1.0.100"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
|
||||
@@ -4,8 +4,8 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
clap = "4.5.4"
|
||||
mdbook = "0.4.40"
|
||||
semver = "1.0.23"
|
||||
serde_json = "1.0.117"
|
||||
anyhow = "1.0.100"
|
||||
clap = "4.5.50"
|
||||
mdbook = "0.4.52"
|
||||
semver = "1.0.27"
|
||||
serde_json = "1.0.145"
|
||||
|
||||
@@ -4,12 +4,12 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.86"
|
||||
anyhow = "1.0.100"
|
||||
bimap = { version = "0.6.3", features = ["serde"] }
|
||||
clap = { version = "4.5.4", features = ["derive"] }
|
||||
clap = { version = "4.5.50", features = ["derive"] }
|
||||
itertools = "0.13.0"
|
||||
mdbook = "0.4.40"
|
||||
pulldown-cmark = "0.11.0"
|
||||
mdbook = "0.4.52"
|
||||
pulldown-cmark = "0.11.3"
|
||||
pulldown-cmark-to-cmark = "15"
|
||||
semver = "1.0.23"
|
||||
serde_json = "1.0.117"
|
||||
semver = "1.0.27"
|
||||
serde_json = "1.0.145"
|
||||
|
||||
@@ -5,4 +5,4 @@ edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
common = { path = "../common" }
|
||||
thiserror = "1.0.59"
|
||||
thiserror = "1.0.69"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/f2u https://blog.acolyer.org/2019/05/28/cheri-abi/
|
||||
/f6c https://code.visualstudio.com
|
||||
/f4q https://crates.io
|
||||
/f2n https://crates.io/crates/cargo-modules
|
||||
/ffr https://doc.rust-lang.org/book/ch03-02-data-types.html#integer-types
|
||||
@@ -162,7 +162,9 @@
|
||||
/f4r https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t-validate/
|
||||
/ff2 https://mainmatter.com/contact/
|
||||
/fff https://mainmatter.com/rust-consulting/
|
||||
/fv2 https://mainmatter.github.io/rust-workshop-runner/
|
||||
/fxg https://marabos.nl/atomics/
|
||||
/f6a https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer
|
||||
/f6p https://nostarch.com/rust-rustaceans
|
||||
/f2k https://owasp.org/www-community/vulnerabilities/Doubly_freeing_memory
|
||||
/f2s https://owasp.org/www-community/vulnerabilities/Using_freed_memory
|
||||
@@ -176,13 +178,17 @@
|
||||
/fze https://rust-lang.github.io/api-guidelines/naming.html#casing-conforms-to-rfc-430-c-case
|
||||
/f6w https://rust-lang.github.io/wg-async/vision/submitted_stories/status_quo/barbara_battles_buffered_streams.html
|
||||
/f6v https://ryhl.io/blog/async-what-is-blocking/
|
||||
/fvf https://ti.to/mainmatter/rust-from-scratch-jan-2025
|
||||
/f6n https://tokio.rs/tokio/tutorial/select
|
||||
/f2t https://valgrind.org/docs/manual/dh-manual.html
|
||||
/fz5 https://veykril.github.io/tlborm/
|
||||
/f2u https://web.archive.org/web/20240517051950/https://blog.acolyer.org/2019/05/28/cheri-abi/
|
||||
/f67 https://without.boats/blog/the-scoped-task-trilemma/
|
||||
/f6g https://www.amazon.com/dp/B0DJ14KQQG/
|
||||
/f6d https://www.jetbrains.com/rust/
|
||||
/ffv https://www.lpalmieri.com/
|
||||
/f4t https://www.lpalmieri.com/posts/2020-12-11-zero-to-production-6-domain-modelling/
|
||||
/f6y https://www.oreilly.com/library/view/programming-rust-2nd/9781492052586/
|
||||
/f6j https://www.rust-lang.org/tools/install
|
||||
/f6l https://www.youtube.com/playlist?list=PLqbS7AVVErFirH9armw8yXlE6dacF-A6z
|
||||
/ff8 https://zero2prod.com
|
||||
|
||||
Reference in New Issue
Block a user