Compare commits

...

61 Commits

Author SHA1 Message Date
732235ab69 finsihed The Rust Programming Language Bookgit add -Agit add -A
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 17s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-18 16:14:55 -06:00
ff4c4fccee finished ch20.5 and ch20 WHOOH
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-17 16:09:28 -06:00
4274106509 started ch20.5
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-17 12:50:58 -06:00
e6bb4977b8 almost finished ch20.4
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 19s
Test Gitea Actions / documentation-check (push) Successful in 19s
2025-04-16 17:13:02 -06:00
e73197aa26 finished ch20.3 2025-04-16 15:44:05 -06:00
0c0dcfee81 finished ch20.2 2025-04-15 17:03:30 -06:00
5da2a5c2b5 finished ch20.1
All checks were successful
Test Gitea Actions / first (push) Successful in 19s
Test Gitea Actions / check-code (push) Successful in 15s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-15 12:33:04 -06:00
6aa4deab15 started ch20.1
All checks were successful
Test Gitea Actions / first (push) Successful in 32s
Test Gitea Actions / check-code (push) Successful in 15s
Test Gitea Actions / test (push) Successful in 15s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-14 17:18:50 -06:00
848e5c4e33 finished ch20 intro
All checks were successful
Test Gitea Actions / first (push) Successful in 20s
Test Gitea Actions / check-code (push) Successful in 18s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-11 11:26:46 -06:00
295d603cbd finished ch19.3 and ch19
All checks were successful
Test Gitea Actions / first (push) Successful in 16s
Test Gitea Actions / check-code (push) Successful in 16s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 15s
2025-04-10 16:47:49 -06:00
730b0091e8 finished ch19.2 and started ch19.3
All checks were successful
Test Gitea Actions / first (push) Successful in 21s
Test Gitea Actions / check-code (push) Successful in 18s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-09 17:00:42 -06:00
f0cbfdf024 finished ch19.1
All checks were successful
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 18s
Test Gitea Actions / documentation-check (push) Successful in 18s
2025-04-08 16:00:21 -06:00
c3ea7d26e3 finished ch19 intro 2025-04-08 11:54:40 -06:00
849d24a10b finished ch18.3 and ch18
All checks were successful
Test Gitea Actions / first (push) Successful in 22s
Test Gitea Actions / check-code (push) Successful in 17s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 16s
2025-04-07 16:56:06 -06:00
35fda43f47 75% done ch18.3 2025-04-07 14:35:07 -06:00
070680441b fixed workflow
All checks were successful
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Successful in 14s
Test Gitea Actions / test (push) Successful in 16s
Test Gitea Actions / documentation-check (push) Successful in 17s
2025-04-03 22:56:23 -06:00
7118958a77 started ch 18.3
Some checks failed
Test Gitea Actions / first (push) Successful in 28s
Test Gitea Actions / check-code (push) Failing after 28s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-03 17:01:38 -06:00
559d4bcdef finished 18.2 2025-04-03 13:09:01 -06:00
cb2ac6ab69 removed old dead code
Some checks failed
Test Gitea Actions / first (push) Successful in 16s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-02 16:17:36 -06:00
5ab5d5105e fixing github actions 2025-04-02 16:16:03 -06:00
cd63c9fd53 attempted fix to github actions 2025-04-02 16:06:58 -06:00
3c3c5cf67b finished ch18.1 2025-04-02 15:37:00 -06:00
dbdd3d8d07 started ch18.1
Some checks failed
Test Gitea Actions / first (push) Successful in 23s
Test Gitea Actions / check-code (push) Failing after 18s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-04-01 16:47:10 -06:00
665215bd19 finished ch17.6 and ch18 intro
Some checks failed
Test Gitea Actions / first (push) Successful in 14s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-31 16:32:24 -06:00
1092bec5ad Merge branch 'master' of github.com:darkicewolf50/RustBrock 2025-03-31 14:56:54 -06:00
97fdc130c3 Merge branch 'master' of github.com:darkicewolf50/RustBrock 2025-03-31 14:56:30 -06:00
c1bdb1043e finished ch17.5 2025-03-31 14:55:57 -06:00
1338d4f994 fix actions
Some checks failed
Test Gitea Actions / first (push) Successful in 25s
Test Gitea Actions / check-code (push) Failing after 23s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-27 16:37:41 -06:00
0e0e0ea857 started ch17.5 2025-03-27 16:36:00 -06:00
f79a47defd finshed ch17.4 2025-03-27 14:37:10 -06:00
f76d2c7454 completed half of ch17.4
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 14s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-25 16:59:44 -06:00
455516765e finshed ch17.3
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-25 11:56:31 -06:00
c73d875808 started ch17.3, completed half
Some checks failed
Test Gitea Actions / first (push) Successful in 18s
Test Gitea Actions / check-code (push) Failing after 12s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-24 16:01:40 -06:00
9ac0d0563c finished ch17.2
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-20 15:57:40 -06:00
8f01c0e0e4 finshed ch17.1
Some checks failed
Test Gitea Actions / first (push) Successful in 16s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-19 16:16:19 -06:00
20d58f8ef5 finshed ch17 intro
Some checks failed
Test Gitea Actions / first (push) Successful in 19s
Test Gitea Actions / check-code (push) Failing after 14s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-18 16:10:25 -06:00
6e94e27e06 finished ch16.4 and ch16
Some checks failed
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-17 15:54:52 -06:00
084ac0ecff finished ch16.3 2025-03-17 15:05:12 -06:00
96dbd779e7 started ch16.3
Some checks failed
Test Gitea Actions / first (push) Successful in 45s
Test Gitea Actions / check-code (push) Failing after 20s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-13 17:59:05 -06:00
661e8bf5c7 finished ch16.2
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-12 12:00:31 -06:00
54cc434db5 finished ch16.1
Some checks failed
Test Gitea Actions / first (push) Successful in 13s
Test Gitea Actions / check-code (push) Failing after 15s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-11 15:07:15 -06:00
a3f4929b42 finished ch16.0 2025-03-11 11:56:28 -06:00
329c2e0d8d finished ch15.6 and ch15
Some checks failed
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-10 05:29:01 -06:00
fbc76348ad finished ch 15.5
Some checks failed
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-07 10:55:30 -07:00
94359e3975 partway through ch15.5
Some checks failed
Test Gitea Actions / first (push) Successful in 13s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-06 16:52:47 -07:00
90ffa5d8a5 finished ch15.4
Some checks failed
Test Gitea Actions / first (push) Successful in 14s
Test Gitea Actions / check-code (push) Failing after 14s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-05 17:07:24 -07:00
0052658af0 finihed ch15.3
Some checks failed
Test Gitea Actions / first (push) Successful in 41s
Test Gitea Actions / check-code (push) Failing after 16s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-04 16:55:02 -07:00
78b0782ac9 finished ch15.2 2025-03-04 14:13:02 -07:00
856e0e992a started ch15.2
Some checks failed
Test Gitea Actions / first (push) Successful in 17s
Test Gitea Actions / check-code (push) Failing after 14s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-03-04 11:59:38 -07:00
ad92fedb9c did some inital testing with actix
Some checks failed
Test Gitea Actions / first (push) Successful in 14s
Test Gitea Actions / check-code (push) Failing after 12s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-02-27 16:30:59 -07:00
efdb732c96 finished ch15.1 2025-02-27 15:58:37 -07:00
eee8170f44 finished ch14.5 and finished ch14 2025-02-27 11:54:21 -07:00
572d5906a6 finished ch14.4 2025-02-27 11:48:40 -07:00
629cbea79d finished ch14.4
Some checks failed
Test Gitea Actions / first (push) Successful in 15s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-02-26 16:41:39 -07:00
43816205f3 finished ch14.2 2025-02-26 12:04:36 -07:00
29f8753827 started to edit down the baja stuff
Some checks failed
Test Gitea Actions / first (push) Successful in 12s
Test Gitea Actions / check-code (push) Failing after 13s
Test Gitea Actions / documentation-check (push) Has been skipped
Test Gitea Actions / test (push) Has been skipped
2025-02-25 21:48:21 -07:00
f3ec0d98cc finsihed ch14.1 and more than halfway through ch14.2
Some checks failed
Test Gitea Actions / first (push) Successful in 12s
Test Gitea Actions / check-code (push) Failing after 21s
Test Gitea Actions / test (push) Has been skipped
Test Gitea Actions / documentation-check (push) Has been skipped
2025-02-25 17:02:50 -07:00
c47bd9cfae finished ch13.4 and finished ch13
All checks were successful
Test Gitea Actions / first (push) Successful in 13s
2025-02-24 17:06:04 -07:00
d961dd4ee9 finished 13.3 2025-02-24 16:02:55 -07:00
ba2884744b almost done with ch13.3 2025-02-24 15:35:01 -07:00
ef22125714 finished ch13.2 2025-02-24 13:11:28 -07:00
67 changed files with 16305 additions and 99 deletions

View File

@ -3,11 +3,12 @@
name: Test Gitea Actions
# events that will trigger this workflow.
# here, we only have "pull_request", so the workflow will run
# whenever we create a pull request.
# other examples: [push] and [pull_request, push]
# here, we only have "push", so the workflow will run
# whenever we push code to the repository.
on: [push]
env:
CARGO_TERM_COLOR: always
# each workflow must have at least one job.
# jobs run in parallel by default (we can change that).
@ -15,23 +16,63 @@ on: [push]
jobs:
# name of the job
first:
# the platform or OS that the workflow will run on.
runs-on: ubuntu-latest
# series of steps to finish the job.
steps:
# name of the step.
# steps run sequentially.
# this is optionale
- name: checkout
# each step can either have "uses" or "run".
# "uses" run an action written somewhere other than this workflow .
# usually from the community.
# this action checks out the repo code to the runner (instance)
# running the action
uses: actions/checkout@v3
# another step.
# this step runs a bash (Ubuntu's default shell) command
- name: list files
run: ls
run: ls
# name of the job
check-code:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
# Step 1: Move to minigrep directory and list files to debug
# - name: Move to minigrep and list files
# run: |
# cd minigrep/
# ls -la # This will list the contents of the minigrep directory to ensure it's correct
- name: Check
run: |
cd minigrep/ # Make sure we're in the correct directory
cargo check --verbose
# name of the job
test:
runs-on: ubuntu-latest
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Run Tests
run: |
cd minigrep/
cargo test --tests --verbose
# name of the job
documentation-check:
runs-on: ubuntu-latest
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Check for Documentation Tests
run: |
cd minigrep/
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi

View File

@ -1,22 +1,78 @@
name: Rust
# name of the workflow.
# this is optional.
name: Test Rust Actions
on:
# push:
# branches: [ "master" ]
pull_request:
branches: [ "master" ]
# events that will trigger this workflow.
# here, we only have "push", so the workflow will run
# whenever we push code to the repository.
on: [push]
env:
CARGO_TERM_COLOR: always
# each workflow must have at least one job.
# jobs run in parallel by default (we can change that).
# each job groups together a series of steps to accomplish a purpose.
jobs:
build:
# name of the job
first:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test --verbose
- name: checkout
uses: actions/checkout@v3
- name: list files
run: ls
# name of the job
check-code:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
# Step 1: Move to minigrep directory and list files to debug
# - name: Move to minigrep and list files
# run: |
# cd minigrep/
# ls -la # This will list the contents of the minigrep directory to ensure it's correct
- name: Check
run: |
cd minigrep/ # Make sure we're in the correct directory
cargo check --verbose
# name of the job
test:
runs-on: ubuntu-latest
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Run Tests
run: |
cd minigrep/
cargo test --tests --verbose
# name of the job
documentation-check:
runs-on: ubuntu-latest
needs: check-code
steps:
- name: checkout
uses: actions/checkout@v4
- name: Check for Documentation Tests
run: |
cd minigrep/
DOC_TESTS=$(cargo test --doc --verbose)
if [[ ! "$DOC_TESTS" =~ "running" ]]; then
echo "No documentation tests were run!" && exit 1
fi

View File

@ -1,5 +1,5 @@
{
"collapse-filter": true,
"collapse-filter": false,
"search": "",
"showTags": false,
"showAttachments": false,
@ -17,6 +17,6 @@
"repelStrength": 10,
"linkStrength": 1,
"linkDistance": 250,
"scale": 1.0000000000000013,
"close": false
"scale": 0.8410178518902366,
"close": true
}

View File

@ -8,49 +8,86 @@
"type": "tabs",
"children": [
{
"id": "caf0233e624d6c1c",
"id": "de2ac5df5b921166",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Test Controls.md",
"file": "Advanced Features.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Test Controls"
"title": "Advanced Features"
}
},
{
"id": "53b36d00b704136e",
"id": "0cdb5cb65c12cd29",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Tests.md",
"file": "Macros.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Tests"
"title": "Macros"
}
},
{
"id": "ec34d2df2728a299",
"id": "8efdb57e394f2650",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "minigrep/README.md",
"file": "Advanced Traits.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "README"
"title": "Advanced Traits"
}
},
{
"id": "74db89a42def0b8b",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Advanced Types.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Advanced Types"
}
},
{
"id": "8cdde5c4be386d20",
"type": "leaf",
"state": {
"type": "markdown",
"state": {
"file": "Unsafe Rust.md",
"mode": "source",
"source": false
},
"icon": "lucide-file",
"title": "Unsafe Rust"
}
},
{
"id": "6ed9f182aa3d5f3e",
"type": "leaf",
"state": {
"type": "graph",
"state": {},
"icon": "lucide-git-fork",
"title": "Graph view"
}
}
],
"currentTab": 2
]
}
],
"direction": "vertical"
@ -193,35 +230,35 @@
"command-palette:Open command palette": false
}
},
"active": "ec34d2df2728a299",
"active": "de2ac5df5b921166",
"lastOpenFiles": [
"Writing_Tests.md",
"Tests.md",
"minigrep/README.md",
"minigrep/src/lib.rs",
"Test_Organization.md",
"Test Controls.md",
"Traits.md",
"Modules and Use.md",
"Modules.md",
"Generic Types Traits and Lifetimes.md",
"Generics.md",
"Lifetimes.md",
"2025-02-04.md",
"data_types.md",
"Collection of Common Data Structs.md",
"Constants.md",
"Crates.md",
"Data Types.md",
"Macros.md",
"Advanced Features.md",
"Advanced Functions and Closures.md",
"Advanced Traits.md",
"Advanced Types.md",
"Enums.md",
"Error Handling.md",
"Hash.md",
"ownership.md",
"Packages.md",
"Paths.md",
"Primitives.md",
"Project Organization.md",
"README.md",
"Unsafe Rust.md",
"Pattern Matching.md",
"Places Patterns Can Be Used.md",
"Pattern Syntax.md",
"Refutability.md",
"Implementing OO Design Pattern.md",
"Trait Objects that allow for Values of Different Types.md",
"Characteristics of OO Languages.md",
"OOP Programming Features.md",
"Futures, Tasks and Threads Together.md",
"Traits for Async.md",
"Futures in Sequence.md",
"Any Number of Futures.md",
"Futures and Async.md",
"Async, Await, Futures and Streams.md",
"Concurrency.md",
"Shared State Concurrency.md",
"Sync and Send.md",
"().md",
"Smart Pointers.md",
"minigrep/src/lib.rs",
"does_not_compile.svg",
"Untitled.canvas",
"Good and Bad Code/Commenting Pratices",

26
Advanced Features.md Normal file
View File

@ -0,0 +1,26 @@
# Advanced Features
So far we learned about the most commonly used parts of the Rust programming language.
Here we will look at a few aspects of the language you may run into once in a while but may not use everyday.
This is intended to be used as a reference for when you encounter any unknowns.
The features covered here are useful in very specific situations.
In this chapter we will cover
- [Unsafe Rust](./Unsafe%20Rust.md): How to opt out of some of Rust's guarantees and take responsibility for manually upholding those guarantees
- [Advanced traits](./Advanced%20Traits.md): associated types, default type parameters, fully qualified syntax, supertraits, and the new type pattern in relation to traits
- [Advanced types](./Advanced%20Types.md): more about the newtype pattern, type aliases, the never type, and dynamically sized types
- [Advanced functions and closures](./Advanced%20Functions%20and%20Closures.md): function pointers and returning closures
- [Macros](./Macros.md): ways to define code that defines more code at compile time
## Summary
These are great tools to have in your toolbox that you like likely not use often.
Knowing that they are available is very valuable.
The complex topics introduced are useful for when you encounter them in error messages in other people's code.
So you will be able to recognize the concepts and syntax.
Use this chapter as a reference to guide you solutions.

View File

@ -0,0 +1,145 @@
# Advanced Functions and Closures
This section includes some more advanced features including function pointers and returning closures.
## Function Pointers
We have talked about how to pass closures to functions; you can also pass regular functions to functions.
This technique is useful when you want to pass a function that you have already defined rather than defining a new closure.
Functions coerce to the type `fn` (with a lowercase f), not to be confused with, not to be confused with the `Fn` closure trait.
The `fn` type is called a *function pointer*.
Passing function pointers will allow you to use functions as arguments to other functions.
The syntax for specifying that a parameter is a function pointer is similar to that of closures as shown below.
This shows that we have defined a function `add_one` that adds one to its parameter.
The function `do_twice` takes two parameters: a function pointer to any function takes an `i32` parameter and returns an `i32`, and one `i32` value.
The `do_twice` function calls the function `f` twice, passing it the `arg` value, then adds the two function call results together.
The `main` function calls `do_twice` with the arguments `add_one` and `5`.
```rust
fn add_one(x: i32) -> i32 {
x + 1
}
fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
f(arg) + f(arg)
}
fn main() {
let answer = do_twice(add_one, 5);
println!("The answer is: {answer}");
}
```
Output
```
The answer is: 12
```
Here we specify that the parameter `f` in `do_twice` is an `fn` that takes one parameter of type `i32` and returns a `i32`.
We can then call `f` from the body of `do_twice`.
In `main` we can pass the function name `add_one` as the first arg to `do_twice`.
Unlike closures, `fn` is a type rather than a trait, so we need to specify `fn` as the parameter type directly rather than declaring a generic type parameter with one of the `Fn` traits as a trait bound.
Function pointers implement all three of the closure traits (`Fn`, `FnMut` and `FnOnce`).
This means that you can always pass a function pointer as an argument for a function that expects a closure.
It is best to write functions using a generic type and one of the closure traits so your functions can accept either functions or closures.
That being said, one example of where you would only want to accept `fn` and not closures is when interfacing with external code that doesn't have closures.
C functions can accept functions as arguments, but C doesn't have closures.
As an example of where you could use either a closure defined inline or a named function.
Lets look at a use of the `map` method provided by the `Iterator` trait in the std library.
To use the `map` function to turn a vector of numbers into a vector of strings, we could use a closure.
Like this:
```rust
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> =
list_of_numbers.iter().map(|i| i.to_string()).collect();
```
We could have a function as the argument to `map` instead of the closure.
Like this:
```rust
let list_of_numbers = vec![1, 2, 3];
let list_of_strings: Vec<String> =
list_of_numbers.iter().map(ToString::to_string).collect();
```
Note, we must use the fully qualified syntax that we talked about earlier in ["Advanced Traits"](./Advanced%20Traits.md) section.
This is because there are multiple functions available named `to_string`.
Here we are using the `to_string` function defined in the `ToString` trait, which is in the std library has implemented for any type that implements `Display`.
Recall form the ["Enum values"]() section of Ch6 that the name of each enum variant that we define also becomes an initializer function.
We can use these initializer functions as function pointers that implement the closure traits, this means we can specify the initializer functions as arguments for methods that take closures.
Like this:
```rust
enum Status {
Value(u32),
Stop,
}
let list_of_statuses: Vec<Status> = (0u32..20).map(Status::Value).collect();
```
Here we creates `Status::Value` instances using each `u32` value in the range that `map` is called on by using the initializer function of `Status::Value`.
Some prefer to use this style, and some people prefer to use closures.
They compile to the same code, so use whatever style is clearer to you.
## Returning Closures
Closures are represented by traits, meaning that you can't return closures directly.
In cases where you want to return a trait, you instead use the concrete type that implements the trait as the return value of the function.
You are unable to do that with closures because they do not have a concrete type that is returnable.
You are not allowed to use the function pointer `fn` as a return type, for example.
Instead, you would normally use the `impl Trait` syntax we learned from Ch10.
You can return any function type using the `Fn`, `FnOnce` and `FnMut`.
This code would work just fine.
```rust
fn returns_closure() -> impl Fn(i32) -> i32 {
|x| x + 1
}
```
As noted in the ["Closure Type Inference and Annotation"](./Closures.md#closure-type-inference-and-annoation) section in Ch13, each closure is also its own distinct type.
If you needed to work with multiple functions that have the same signature but slightly different implementations, you will need to use a trait object for them.
```rust
fn main() {
let handlers = vec![returns_closure(), returns_initialized_closure(123)];
for handler in handlers {
let output = handler(5);
println!("{output}");
}
}
fn returns_closure() -> Box<dyn Fn(i32) -> i32> {
Box::new(|x| x + 1)
}
fn returns_initialized_closure(init: i32) -> Box<dyn Fn(i32) -> i32> {
Box::new(move |x| x + init)
}
```
This will compile just fine, but it wouldn't if we had tried to stick with `impl Fn(i32) -> i32`.

542
Advanced Traits.md Normal file
View File

@ -0,0 +1,542 @@
# Advanced Traits
Here we will go into the nitty-gritty of traits..
## Specifying Placeholder Types in Trait Definitions with Associated Types
*Associated types* connect a type placeholder with a trait such that the trait method definitions can use these placeholder types in their signatures.
The implementor of a trait will specify the concrete type to be used instead of the placeholder type for the particular implementation.
This way we can define a trait that uses some types without needing to know exactly what those types are until the trait is implemented.
We have described most of the advanced features in this chapter as being rarely needed.
Associated types are somewhere in the middle: they are used more rarely than features explained in the rest of the book, but more commonly than many of the other features discussed in this chapter.
One example of trait with an associated type is the `Iterator` trait that the std library provides.
The associated type is named `Item` and stands in for the type of the values the type implementing the `Iterator` trait is iterating over.
Here is the definition of the `Iterator` trait.
```rust
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
}
```
The type `Item` is a placeholder, and the `next` method's definition shows that it will return values of type `Option<Self::Item>`.
Implementors of the `Iterator` trait will specify the concrete type for `Item` and the `next` method will return an `Option` containing a value of that concrete type.
Associated types may seem like a similar concept to generics, in that the latter allow us to define a function without specifying what types it can handle.
To examine the difference between the two, we will look at the implementation of the `Iterator` trait on a type named `Counter` that specifies the `Item` type is `u32`.
```rust
impl Iterator for Counter {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
// --snip--
```
This syntax seems similar to that of generics.
So why not just define the `Iterator` trait with generics
```rust
pub trait Iterator<T> {
fn next(&mut self) -> Option<T>;
}
```
The differences is that when using generics, we must annotate the types in each implementation.
Because we can also implement `Iterator<String> for Counter` or any other type, we could have multiple implementations of `Iterator` for `Counter`.
This could also be said, when a trait has a generic parameter, it can be implemented for a type multiple times, changing the concrete types of the generic type parameters each time.
When we use the `next` method on `Counter`, we would have to provide type annotations to indicate which implementation of `Iterator` we want to use.
With associated types, we don't need to annotate types because we can't implement a trait on a type multiple times.
In the first definition that uses associated types, we can only choose what the type of `Item` will be once because there can only be one `impl Iterator for Counter`.
We don't have to specify that we want an iterator of `u32` values everywhere that we call `next` on `Counter`.
Associated types also become part of the trait's contract.
Implementors of the trait must also provide a type to stand in for the associated type placeholder.
Associated types often have a name that describes how the type will be used, and documenting the associated type in the API documentation is good practice.
## Default Generic Type Parameters and Operator Overloading
When we use generic type parameters, we can specify a default concrete type for the generic type.
This eliminates the need for implementors of the trait to specify a concrete type if the default type works.
You can specify a default type when declaring a generic type with the `<PlaceholderType=ConcreteType>` syntax.
A good example of a situation where this technique is useful is with *operator overloading*, where you customize the behavior of an operator (such as `+`) in particular situations.
Rust doesn't allow you to create your own operators or overload arbitrary operators.
You can overload the operation and corresponding traits listed in `std::ops` by implementing the traits associated with the operator.
For example here we overload the `+` operator to add two `Point` instances together.
We do this by implementing the `Add` trait on a `Point` struct.
```rust
use std::ops::Add;
#[derive(Debug, Copy, Clone, PartialEq)]
struct Point {
x: i32,
y: i32,
}
impl Add for Point {
type Output = Point;
fn add(self, other: Point) -> Point {
Point {
x: self.x + other.x,
y: self.y + other.y,
}
}
}
fn main() {
assert_eq!(
Point { x: 1, y: 0 } + Point { x: 2, y: 3 },
Point { x: 3, y: 3 }
);
}
```
The `add` method adds the `x` values of two `Point` instances and the `y` values of two `Point` instances to create a new `Point`.
The `Add` trait has an associated type named `Output` that determines the type returned from the `add` method.
The default generic type in this code is within the `Add` trait.
Here is its definition
```rust
trait Add<Rhs=Self> {
type Output;
fn add(self, rhs: Rhs) -> Self::Output;
}
```
This should look generally familiar: a trait with one method and an associated type.
The new part is `Rhs=Self`: this syntax is called *default type parameters*.
The `Rhs` generic type parameter (short for "right hand side") defines the type of the `rhs` parameter in the `add` method.
If we didn't specify a concrete type for `Rhs` when we implement the `Add` trait, the type of `Rhs` will default to `Self`, which will be the type we are implementing `Add` on.
When we implemented `Add` for `Point`, we used the default for `Rhs` because we wanted to add two `Point` instances.
Now lets look at an example of implementing the `Add` trait where we want to customize the `Rhs` type rather than using the default.
Here we want two structs `Millimeters` and `MEters`, which hold values in different units.
This thin wrapping of an existing type in another struct is known as the *newtype pattern*, which will be described in more detail in the ["Using the Newtype Pattern to Implement External Traits on External Types"]() section.
We want to add values in millimeters to values in meters and have the implementation of `Add` do the conversion correctly.
We can implement `Add` for `Millimeters` with `Meters` as the `Rhs`.
```rust
use std::ops::Add;
struct Millimeters(u32);
struct Meters(u32);
impl Add<Meters> for Millimeters {
type Output = Millimeters;
fn add(self, other: Meters) -> Millimeters {
Millimeters(self.0 + (other.0 * 1000))
}
}
```
To add `Millimeters` and `Meters`, we specify `impl Add<Meters>` to set the value of the `Rhs` type parameter instead of using the default of `Self`.
You will use default type parameters in two main ways:
- To extend a type without breaking existing code
- To allow customization in specific cases most users won't need
The std library's `Add` trait is an example of the second purpose.
Usually, you will add two like types, but the `Add` trait provides the ability to customize beyond that.
Using a default type parameter in the `Add` trait definition means you don't have to specify the extra parameter most of the time.
A bit of implementation boilerplate isn't needed, making it easier to use the trait.
The first purpose is similar to the second but in reverse.
If you want to add a type parameter to an existing trait, you can give it a default to allow extension of the functionality of the trait without breaking the existing implementation code.
## Fully Qualified Syntax for Disambiguation: Calling Methods with the Same Name
Nothing in Rust prevents a trait from having a method with the same name as another trait's methods.
Nor does Rust prevent you from implementing both traits on one type.
It is also possible to implement a method directly on the type with the same name as methods form traits.
When calling methods with the same name, you need to specify to Rust which one you want to use.
Consider this code where we have defined two traits, `Pilot` and `Wizard`, that both have a method called `fly`.
Then implement both traits on a type `Human` that already has a method named `fly` implemented on it.
Each `fly` method does something different.
```rust
trait Pilot {
fn fly(&self);
}
trait Wizard {
fn fly(&self);
}
struct Human;
impl Pilot for Human {
fn fly(&self) {
println!("This is your captain speaking.");
}
}
impl Wizard for Human {
fn fly(&self) {
println!("Up!");
}
}
impl Human {
fn fly(&self) {
println!("*waving arms furiously*");
}
}
```
When we call `fly` on an instance of `Human`, the compiler defaults to calling the method that is directly implemented on the type.
```rust
fn main() {
let person = Human;
person.fly();
}
```
The output of this code will print `*waving arms furiously*`, showing that Rust called the `fly` method implemented on `Human` directly.
To call the `fly` methods from either the `Pilot` trait or the `Wizard` trait, we need to use more specific syntax to specify which `fly` method we mean.
Here is a demonstration of this syntax,
```rust
fn main() {
let person = Human;
Pilot::fly(&person);
Wizard::fly(&person);
person.fly();
}
```
Specifying the trait name before the method name clarifies to Rust and Us which implementation of `fly` we want to call.
We could also write `Human::fly(&person)` but that us the same as `person.fly()`.
This is also a bit longer to write if we don't need to disambiguate.
Output
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.46s
Running `target/debug/traits-example`
This is your captain speaking.
Up!
*waving arms furiously*
```
Because `fly` takes a `self` parameter, if we had two *types* that both implement one *trait*, Rust would be able to figure out which implementation of a `trait` to use based on the type of `self`.
Associated function that are not methods do not have a `self` parameter.
When there are multiple types of traits that define non-method functions with the same function name, Rust doesn't always know which type you mean unless you use *fully qualified syntax*.
For example, we here we create a trait for an animal shelter that wants to name all baby dogs *Spot*.
We make an `Animal` trait with an associated non-method function `baby_name`.
The `Animal` trait is implemented for the struct `Dog`, which we also provide an associated non-method function `baby_name` directly.
```rust
trait Animal {
fn baby_name() -> String;
}
struct Dog;
impl Dog {
fn baby_name() -> String {
String::from("Spot")
}
}
impl Animal for Dog {
fn baby_name() -> String {
String::from("puppy")
}
}
fn main() {
println!("A baby dog is called a {}", Dog::baby_name());
}
```
We implement the code for naming all puppies `Spot` in the `baby_name` associated function that is defined on `Dog`.
The `Dog` type also implements the trait `Animal`, which describes characteristics that all animals have.
Baby dogs are called puppies, and that is expressed in the implementation of the `Animal` trait on `Dog` in the `baby_name` function associated with the `Animal` trait.
In `main` we call the `Dog::baby_name` function, which calls the associated function defined on `Dog` directly.
This outputs
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.54s
Running `target/debug/traits-example`
A baby dog is called a Spot
```
This isn't thew output we wanted.
We want to call the `baby_name` function that is part of the `Animal` trait that we implemented on `Dog` so that it prints `A baby dog is called a puppy`.
The technique of specifying the trait name that we used here doesn't help here.
If we changed `main` to the code below, we get a compiler error.
```rust
fn main() {
println!("A baby dog is called a {}", Animal::baby_name());
}
```
Because `Animal::baby_name` doesn't have a `self` parameter and there could be other types implements the `Animal` trait, Rust can't figure out which implementation of `Animal::baby_name` we want.
We get this compiler error
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
error[E0790]: cannot call associated function on trait without specifying the corresponding `impl` type
--> src/main.rs:20:43
|
2 | fn baby_name() -> String;
| ------------------------- `Animal::baby_name` defined here
...
20 | println!("A baby dog is called a {}", Animal::baby_name());
| ^^^^^^^^^^^^^^^^^^^ cannot call associated function of trait
|
help: use the fully-qualified path to the only available implementation
|
20 | println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
| +++++++ +
For more information about this error, try `rustc --explain E0790`.
error: could not compile `traits-example` (bin "traits-example") due to 1 previous error
```
To disambiguate and tell Rust that we want to use the implementation of `Animal` for `Dog` as opposed to the implementation of `Animal` for some other type.
We need to use fully qualified syntax.
Here demonstrates how to use fully qualified syntax
```rust
fn main() {
println!("A baby dog is called a {}", <Dog as Animal>::baby_name());
}
```
Here we provide Rust with a type annotation within the angle brackets.
This indicates we want to call the `baby_name` method from the `Animal` trait as implementation on `Dog` by saying that we want to treat the `Dog` type as an `Animal` for this function call.
Here is the new output
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.48s
Running `target/debug/traits-example`
A baby dog is called a puppy
```
Here us a fully qualified syntax is defined as follows
```
<Type as Trait>::function(receiver_if_method, next_arg, ...);
```
For associated function that aren't methods, there would not be a `receiver`: there would only be the list of other arguments.
You could use fully qualified syntax everywhere that you call functions or methods.
You are allowed to omit any part of this syntax that Rust can figure out from other information in the program.
You only need to use this this more verbose syntax in cases where there are multiple implementations that use the same name and Rust needs help to identify which implementation you want to call.
## Using Supertraits to Require One Trait's Functionality Within Another Trait
Sometimes you might write a trait definition that depends on another trait.
For a type to implement the first trait, you want to require that type to also implement the second trait.
You would do this so that your trait definition can make use of the associated items of the second trait.
The trait your trait definition is relying on is called a *supertrait* of your trait.
Lets say we want to make an `OutlinePrint` trait with an `outline_print` method that will print a given value formatted so that it is framed in asterisks.
Given that a `Point` struct that implements the std library trait `Display` to result in `(x, y)`.
When we call `outline_print` on a `Point` instance that has `1` for `x` and `3` for `y`, it should print the following
```
**********
* *
* (1, 3) *
* *
**********
```
The implementation of the `outline_print` method we want to use the `Display` trait's functionality.
Therefore we need to specify that the `OutlinePrint` trait will work only for types that also implement `Display` and provide the functionality that `OutlinePrint` needs.
We can do this in the trait definition by specifying `OutlinePrint: Display`.
This technique is similar to adding a trait bound to the trait.
Here shows an implementation of the `OutlinePrint` trait
```rust
use std::fmt;
trait OutlinePrint: fmt::Display {
fn outline_print(&self) {
let output = self.to_string();
let len = output.len();
println!("{}", "*".repeat(len + 4));
println!("*{}*", " ".repeat(len + 2));
println!("* {output} *");
println!("*{}*", " ".repeat(len + 2));
println!("{}", "*".repeat(len + 4));
}
}
```
Because we specified that `OutlinePrint` requires the `Display` trait.
We can use the `to_string` function that is automatically implemented for any type that implements `Display`.
If we attempted to use `to_string` without adding a color and specifying the `Display` trait after the trait name, we would get an error saying that no method named `to_string` was found for the type `&Self` in the current scope.
Lets see what happens when we try to implement `OutlinePrint` on a type that doesn't implement `Display`, such as the `Point` struct
```rust
struct Point {
x: i32,
y: i32,
}
impl OutlinePrint for Point {}
```
We still get an error saying that `Display` is required but not implemented
```
$ cargo run
Compiling traits-example v0.1.0 (file:///projects/traits-example)
error[E0277]: `Point` doesn't implement `std::fmt::Display`
--> src/main.rs:20:23
|
20 | impl OutlinePrint for Point {}
| ^^^^^ `Point` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `OutlinePrint`
--> src/main.rs:3:21
|
3 | trait OutlinePrint: fmt::Display {
| ^^^^^^^^^^^^ required by this bound in `OutlinePrint`
error[E0277]: `Point` doesn't implement `std::fmt::Display`
--> src/main.rs:24:7
|
24 | p.outline_print();
| ^^^^^^^^^^^^^ `Point` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `Point`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
note: required by a bound in `OutlinePrint::outline_print`
--> src/main.rs:3:21
|
3 | trait OutlinePrint: fmt::Display {
| ^^^^^^^^^^^^ required by this bound in `OutlinePrint::outline_print`
4 | fn outline_print(&self) {
| ------------- required by a bound in this associated function
For more information about this error, try `rustc --explain E0277`.
error: could not compile `traits-example` (bin "traits-example") due to 2 previous errors
```
In order to fix this, we implement `Display` on `Point` and satisfy the constraint that `OutlinePrint` requires.
Like this
```rust
use std::fmt;
impl fmt::Display for Point {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "({}, {})", self.x, self.y)
}
}
```
Now implementing the `OutlinePrint` trait on `Point` will compile successfully.
We can call `outline_print` on a `Point` instance to display it within an outline of asterisks.
## Using the Newtype Pattern to Implement Traits on External Types
Previously we mentioned the orphan rule that states we are only allowed to implement a trait on a type if either the trait or the type are local to our crate.
It is possible to get around this restriction using the *newtype pattern*.
This involves creating a new type in a tuple struct.
The tuple struct will have one field and be a thin wrapper around the type we want to implement a trait for.
Then the wrapper type is local to our crate, and we can implement the trait on the wrapper.
*Newtype* is a term that originates from the Haskell programming language.
There is no runtime performance penalty for using this pattern, and wrapper type is elided at compile time.
For example let's say we want to implement `Display` on `Vec<T>`, which the orphan rule prevents us from doing directly because the `Display` trait and the `Vec<T>` type are defined outside our crate.
We can make a `Wrapper` struct that holds an instance of `Vec<T>`.
Next we can implement `Display` on `Wrapper` and use the `Vec<T>` value.
```rust
use std::fmt;
struct Wrapper(Vec<String>);
impl fmt::Display for Wrapper {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.0.join(", "))
}
}
fn main() {
let w = Wrapper(vec![String::from("hello"), String::from("world")]);
println!("w = {w}");
}
```
The implementation of `Display` uses `self.0` to access the inner `Vec<T>`.
Because `Wrapper` is a tuple is a tuple struct and `Vec<T>` is the item at index 0 in the tuple.
Then we can use the functionality of the `Display` trait on `Wrapper`.
The downside of this technique is that `Wrapper` is a new type, so it doesn't have the methods of the value it is holding.
We would need to implement all the methods of `Vec<T>` directly on `Wrapper` such that the methods delegate to `self.0`, which would allows us to treat `Wrapper` exactly like a `Vec<T>`.
If we wanted the new type to have every method the inner type has, implementing the `Deref` trait on the `Wrapper` to return the inner type would be a solution.
If we didn't want the `Wrapper` type to have all the methods of the inner type.
For example, to restrict the `Wrapper` type's behavior we would have to implement just the methods we do want manually.
This newtype pattern is useful even when traits are not involved.

333
Advanced Types.md Normal file
View File

@ -0,0 +1,333 @@
# Advanced Types
The Rust type system has some features that we have mentioned so far but haven't gone into detail.
To start we will go into the newtypes in general as we examine why newtypes are useful as types.
Then we will go onto type aliases, a feature similar to newtypes but slightly different semantics.
As well we will discuss the `!` and dynamically sized types.
## Using the Newtype Pattern for Type Safety and Abstraction
The newtype pattern are also useful for tasks beyond those discussed already.
This includes statically enforcing that values are never confused and indicating the units of a value.
Before we saw an example of using newtypes to indicate units: recall that the `Millimeters` and `Meters` structs wrapped `u32` values in a newtype.
If we wrote a function with a parameter of type `Millimeters`, we couldn't compile a program that accidentally tired to call function with a value of type `Meters` or a plain `u32`.
We can also use the newtype pattern to abstract away some implementation details of a type.
The new type can expose a public API that is different form the API of the private inner type.
Newtypes can also hide internal implementation.
Lets say we could provide a `People` type to wrap a `HashMap<i32, String>` that store a person's ID associated with their name.
Code using `People` would only interact with the public API we provide.
Like a method to add a name string to the `People` collect: this code wouldn't need to know that we assign an `i32` ID to names internally.
The newtype pattern is a lightweight way to achieve encapsulation to hide implementation details, which we discussed before in [Ch18](./Characteristics%20of%20OO%20Languages.md#encapsulation-that-hides-implementation-details).
## Creating Type Synonyms with Type Aliases
Rust provides the ability to declare a *type alias* to give an existing type another name.
We need to use the `type` keyword to do this.
For example we can create the alias `Kilometers` to `i32` like this.
```rust
type Kilometers = i32;
```
The alias `Kilometers` is a *synonym* for `i32`.
Unlike the `Millimeters` and `Meters` types we created before.
`Kilometers` is not a separate, new type.
Values that have the type `Kilometers` will be treated the same as values of type `i32`.
```rust
type Kilometers = i32;
let x: i32 = 5;
let y: Kilometers = 5;
println!("x + y = {}", x + y);
```
Because `Kilometers` and `i32` are the same type, we can add values of both types and we can pass `Kilometers` values to functions that take `i32` parameters.
However using this method, we don't get the type checking benefits that we get from the newtype pattern discussed earlier.
In other words, if we mix up `Kilometers` and `i32` values somewhere, the compiler will not give us an error.
The main use for type synonyms is to reduce repetition.
As an example, we might have a lengthy type like this.
```rust
Box<dyn Fn() + Send + 'static>
```
Writing this lengthy type function signatures and as type annotations all over the code can be tiresome and error prone.
Just image a project full of code like this.
```rust
let f: Box<dyn Fn() + Send + 'static> = Box::new(|| println!("hi"));
fn takes_long_type(f: Box<dyn Fn() + Send + 'static>) {
// --snip--
}
fn returns_long_type() -> Box<dyn Fn() + Send + 'static> {
// --snip--
}
```
A type alias makes this code more manageable by reducing the amount of repetition.
Here we have introduced an alias named `Thunk` for the verbose type and can replace all uses of the type with the shorter alias `Thunk`.
```rust
type Thunk = Box<dyn Fn() + Send + 'static>;
let f: Thunk = Box::new(|| println!("hi"));
fn takes_long_type(f: Thunk) {
// --snip--
}
fn returns_long_type() -> Thunk {
// --snip--
}
```
This is much easier to read and write.
Choosing a meaningful name for a type alias can help communicate your intent as well.
*Thunk* is a word for code to be evaluated at a later time, this is an appropriate name for a closure that gets stored.
Type aliases are also commonly used with the `Result<T, E>` type for repetition.
Consider the `std::io` module in the std library.
I/O operations often return a `Result<T, E>` to handle situations when operations fail to work.
This library has a `std::io::Error` struct that represents all possible I/O errors.
Many of the functions in `std::io` will be returning `Result<T, E>` where the `E` is `std::io::Error`, such as these functions in `Write` trait:
```rust
use std::fmt;
use std::io::Error;
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize, Error>;
fn flush(&mut self) -> Result<(), Error>;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Error>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<(), Error>;
}
```
The `Result<..., Error>` is repeated a lot.
Therefore `std::io` has this type alias declaration
```rust
type Result<T> = std::result::Result<T, std::io::Error>;
```
Due to this declaration is in the `std::io` module, we can use the fully qualified alias `std::io::Result<T>`.
That is a `Result<T, E>` with the `E` filled in as `std::io::Error`.
The `Write` trait function signatures end up looking like this.
```rust
pub trait Write {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn flush(&mut self) -> Result<()>;
fn write_all(&mut self, buf: &[u8]) -> Result<()>;
fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()>;
}
```
This type alias helps in two ways:
- It makes code easier to write.
- *And*
- It gives us a consistent interface across all of `std::io`
Due to it being an alias, it is just another `Result<T, E>`, this means we can use any methods that work on `Result<T, E>` with it, as well as special syntax like the `?` operator.
## The Never Type that Never Returns
Rust has a special type named `!` that is known in type theory lingo as the *empty type* because it has no values.
We prefer to call it the *never type* because it stands in the place of the return type when a function will never return.
Here is an example in use.
```rust
fn bar() -> ! {
// --snip--
}
```
This code should be read as "the function `bar` returns never."
Functions that return never are called *diverging functions*.
We can't create values of the type `!` so `bar` can never possibly return.
What is the use of a type you can never create values for?
Recall the code from Ch2, part of the number guessing game.
Here is a sample of that code
```rust
let guess: u32 = match guess.trim().parse() {
Ok(num) => num,
Err(_) => continue,
};
```
Before we skipped over some details about this code.
In ch6 we discussed that `match` arms must all return the same type.
For example this code will not compile.
```rust
let guess = match guess.trim().parse() {
Ok(_) => 5,
Err(_) => "hello",
};
```
The type of `guess` in this code would have to be an integer *and* a string, and Rust requires that `guess` have only one type.
So what does `continue` return?
How are we allowed to return a `u32` from one arm and have another arm that ends with `continue`?
`continue` has a `!` value.
That is, when Rust computes the type of `guess`, it looks at both match arms, the former with a value of `u32` and the latter with a `!` value.
Because `!` can never have a value, Rust decides that the type of `guess` is `u32`.
The formal way to describe this behavior is that expressions of type `!` can be coerced into any other type.
We are allowed to end this `match` arm with `continue` because `continue` doesn't return a value.
Instead it moves control back to the top of the loop, so in the `Err` case, we never assign a value to `guess`.
The never type is useful with the `panic!` macro as well.
Remember the `unwrap` function that we call on `Option<T>` values to produce a value or panic with this definition:
```rust
impl<T> Option<T> {
pub fn unwrap(self) -> T {
match self {
Some(val) => val,
None => panic!("called `Option::unwrap()` on a `None` value"),
}
}
}
```
Here, the same thing happens as in the `match` case form before.
Rust sees that `val` has the type `T` and `panic!` has the type `!`, so the result of the overall `match` expression is `T`.
This works because `panic!` doesn't produce a value, it ends the program.
In the `None` case, we will not be returning a value form `unwarp` so this code is valid.
One final expression that has the type `!` is a `loop`.
```rust
print!("forever ");
loop {
print!("and ever ");
}
```
This loop never ends, so `!` is the value of the expression.
However, this wouldn't be true if we included a `break`, because the loop would terminate when it got to the `break`.
## Dynamically Sized Types and the `Sized` Trait
Rust must know certain details about its types, such as how much space to allocate for a value of a particular type.
This leaves one corner of its type system a little confusing at first: the concept of *dynamically sized types*.
Sometimes referred to as *DSTs* or *unsized types*, these types let us write code using values whose size we can know only at runtime.
Lets look into the details of a dynamically sized type called `str`, which we have been using throughout.
This does not include `&str`, but `str` on its own, is a DST.
We can't know how long the string is until runtime, meaning we can't create a variable of type `str`, nor can we make that argument of type `str`.
Consider this code, which will not compile.
```rust
let s1: str = "Hello there!";
let s2: str = "How's it going?";
```
Rust needs to know how much memory to allocate for any value of a particular type, and all values of a type must use the same amount of memory.
If Rust allowed use to write this code, these two `str` values would need to take up the same amount of memory.
These two have different lengths:
- `s1` needs 12 bytes of storage.
- `s2` needs 15.
This is why it is not possible to create a variable holding a dynamically sized type.
So what should we do?
We should make the types of `s1` and `s2` a `&str` rather than a `str`.
Recall from the "String Slice" section from Ch4, that the slice data structure just stores the starting position and the length of the slice.
Even though a `&T` is a single value that stores the memory address of where the `T` is located, a `&str` is *two* values.
The address of the `str` and its length.
We can know the size of a `&str` value at compile time: it's twice the length of a `usize`.
This means we always know the size of a `&str`, no matter how long the string it refers to is.
Generally this is the way in which dynamically sized types are used in Rust, they have an extra but of metadata that stores the size of the dynamic information.
The golden rule of dynamically sized types is that we must always put values of dynamically sized types behind a pointer of some kind.
We can combine `str` with all kinds of pointers.
For example `Box<str>` or `Rc<str>`.
In fact we have seen this before but with a different dynamically sized type: traits.
Every trait is a dynamically sized type we can refer to by using the name of the trait.
In Ch18 in ["Using Trait Objects That Allow for Values of Different Types"](./Characteristics%20of%20OO%20Languages.md#encapsulation-that-hides-implementation-details), we mentioned that to use trait as trait objects, we must put them behind a pointer, such as `&dyn Trait` or `Box<dyn Trait>` (`Rc<dyn Trait>` would work as well).
To work with DSTs, Rust provides the `Sized` trait to determine whether or not a type's size is known at compile time.
This trait is automatically implemented for everything whose size is known at compile time.
Additionally Rust implicitly adds a bound on `Sized` to every generic function.
That is, a generic function definition like this:
```rust
fn generic<T>(t: T) {
// --snip--
}
```
This is actually treated as though we had written this:
```rust
fn generic<T: Sized>(t: T) {
// --snip--
}
```
By default, generic functions will work only on types that have a known size at compile time.
However, you can use the following special syntax to relax this restriction.
```rust
fn generic<T: ?Sized>(t: &T) {
// --snip--
}
```
A trait bound on `?Sized` means "`T` may or may not be `Sized`".
This notation overrides the default that generic types must have a known size at compile time.
The `?Trait` syntax with this meaning is only available for `Sized`, not any other traits.
Note that we switched the type of the `t` parameter from `T` to `&T`.
Because the type might not be `Sized`, we need to use it behind some kind of pointer.
Here we have chosen to use a reference.

765
Any Number of Futures.md Normal file
View File

@ -0,0 +1,765 @@
# Working with Any Number of Futures
When we switched form using `join` to using `join3`.
This would be very annoying every time we changed the number of futures we wanted to join.
We have a macro instead to do this for us, which we can pass an arbitrary number of arguments.
This also handles awaiting the futures itself.
We could rewrite the code to use `join!` instead of `join3`
```rust
trpl::join!(tx1_fut, tx_fut, rx_fut);
```
This is an improvement because we do not need to swap between `join`, `join3`, `join4`, etc.
Even though this macro form only when we know the number of futures ahead of time.
In the real world Rust, pushing futures into a collection and then waiting on some or all the futures of them to complete is a common pattern.
To check all the futures in a collection, we need to iterate over and join *all* of them.
The `trpl::join_all` function any type that implements the `Iterator` trait.
Here is an example of putting all our futures in a vector and replacing `join!` with `join_all`.
```rust
let futures = vec![tx1_fut, rx_fut, tx_fut];
trpl::join_all(futures).await;
```
This will not compile, instead we get this error.
```
error[E0308]: mismatched types
--> src/main.rs:45:37
|
10 | let tx1_fut = async move {
| ---------- the expected `async` block
...
24 | let rx_fut = async {
| ----- the found `async` block
...
45 | let futures = vec![tx1_fut, rx_fut, tx_fut];
| ^^^^^^ expected `async` block, found a
different `async` block
|
= note: expected `async` block `{async block@src/main.rs:10:23: 10:33}`
found `async` block `{async block@src/main.rs:24:22: 24:27}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
```
This may be surprising.
This after all, none of the async blocks return anything, so each one produces a `Future<Output = ()>`.
Remember that `Future` is a trait, and that the compiler creates a unique enum for each async block.
You can't put two different hand-written structs in a `Vec`.
This rule also applies to the different enums generated by the compiler.
In order to make this work we need to use *trait objects*, just like we did in ["Returning Errors from the `run` function"]() (improving error handling and modularity)
Using trait objects lets us treat each of the anonymous futures produced by these types as the same type, because all of them implement the `Future` trait.
Note we discussed another way to include multiple types in a `Vec`
Using an enum to represent each type that can appear in the vector.
We are unable to do this here.
For one thing we have no way to name the different types because they are anonymous.
Another reason, we reach for a vector and `join_all` in the first place was to be able to work with a dynamic collection of futures where we only care that they have the same output.
We will try this by wrapping each future in the `vec!` in a `Box::new`
```rust
let futures =
vec![Box::new(tx1_fut), Box::new(rx_fut), Box::new(tx_fut)];
trpl::join_all(futures).await;
```
As expected this code will not compile.
We get the same basic error we got before for both the second and third `Box::new` calls, as well get get new errors referring to the `Unpin` trait.
We will fix this on the `Box::new` calls by explicitly annotating the tpye of the `futures` variable
```rust
let futures: Vec<Box<dyn Future<Output = ()>>> =
vec![Box::new(tx1_fut), Box::new(rx_fut), Box::new(tx_fut)];
```
We will walk through this type declaration through the use of a ordered list
1. The innermost type is the future itself.
1. Note we need to explicitly that the output of the future is the unit type `()` by writing `Future<Output = ()>`
2. We annotate the trait with `dyn` to mark it as dynamic
3. The entire trait reference is wrapped in a `Box`
4. We state explicitly that `futures` is a `Vec` containing these items
This has already made a big difference.
Now we only get the errors mentioning `Unpin`.
Although there are three of them and their contents are very similar.
Here is the compiler error
```
error[E0308]: mismatched types
--> src/main.rs:46:46
|
10 | let tx1_fut = async move {
| ---------- the expected `async` block
...
24 | let rx_fut = async {
| ----- the found `async` block
...
46 | vec![Box::new(tx1_fut), Box::new(rx_fut), Box::new(tx_fut)];
| -------- ^^^^^^ expected `async` block, found a different `async` block
| |
| arguments to this function are incorrect
|
= note: expected `async` block `{async block@src/main.rs:10:23: 10:33}`
found `async` block `{async block@src/main.rs:24:22: 24:27}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
note: associated function defined here
--> file:///home/.rustup/toolchains/1.82/lib/rustlib/src/rust/library/alloc/src/boxed.rs:255:12
|
255 | pub fn new(x: T) -> Self {
| ^^^
error[E0308]: mismatched types
--> src/main.rs:46:64
|
10 | let tx1_fut = async move {
| ---------- the expected `async` block
...
30 | let tx_fut = async move {
| ---------- the found `async` block
...
46 | vec![Box::new(tx1_fut), Box::new(rx_fut), Box::new(tx_fut)];
| -------- ^^^^^^ expected `async` block, found a different `async` block
| |
| arguments to this function are incorrect
|
= note: expected `async` block `{async block@src/main.rs:10:23: 10:33}`
found `async` block `{async block@src/main.rs:30:22: 30:32}`
= note: no two async blocks, even if identical, have the same type
= help: consider pinning your async block and casting it to a trait object
note: associated function defined here
--> file:///home/.rustup/toolchains/1.82/lib/rustlib/src/rust/library/alloc/src/boxed.rs:255:12
|
255 | pub fn new(x: T) -> Self {
| ^^^
error[E0277]: `{async block@src/main.rs:10:23: 10:33}` cannot be unpinned
--> src/main.rs:48:24
|
48 | trpl::join_all(futures).await;
| -------------- ^^^^^^^ the trait `Unpin` is not implemented for `{async block@src/main.rs:10:23: 10:33}`, which is required by `Box<{async block@src/main.rs:10:23: 10:33}>: Future`
| |
| required by a bound introduced by this call
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
= note: required for `Box<{async block@src/main.rs:10:23: 10:33}>` to implement `Future`
note: required by a bound in `join_all`
--> file:///home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.30/src/future/join_all.rs:105:14
|
102 | pub fn join_all<I>(iter: I) -> JoinAll<I::Item>
| -------- required by a bound in this function
...
105 | I::Item: Future,
| ^^^^^^ required by this bound in `join_all`
error[E0277]: `{async block@src/main.rs:10:23: 10:33}` cannot be unpinned
--> src/main.rs:48:9
|
48 | trpl::join_all(futures).await;
| ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unpin` is not implemented for `{async block@src/main.rs:10:23: 10:33}`, which is required by `Box<{async block@src/main.rs:10:23: 10:33}>: Future`
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
= note: required for `Box<{async block@src/main.rs:10:23: 10:33}>` to implement `Future`
note: required by a bound in `futures_util::future::join_all::JoinAll`
--> file:///home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.30/src/future/join_all.rs:29:8
|
27 | pub struct JoinAll<F>
| ------- required by a bound in this struct
28 | where
29 | F: Future,
| ^^^^^^ required by this bound in `JoinAll`
error[E0277]: `{async block@src/main.rs:10:23: 10:33}` cannot be unpinned
--> src/main.rs:48:33
|
48 | trpl::join_all(futures).await;
| ^^^^^ the trait `Unpin` is not implemented for `{async block@src/main.rs:10:23: 10:33}`, which is required by `Box<{async block@src/main.rs:10:23: 10:33}>: Future`
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
= note: required for `Box<{async block@src/main.rs:10:23: 10:33}>` to implement `Future`
note: required by a bound in `futures_util::future::join_all::JoinAll`
--> file:///home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.30/src/future/join_all.rs:29:8
|
27 | pub struct JoinAll<F>
| ------- required by a bound in this struct
28 | where
29 | F: Future,
| ^^^^^^ required by this bound in `JoinAll`
```
The first part of the message tells us that the first async block (`scr/main.rs:8:20: 20:10`) doesn't implement the `Unpin` trait.
It also suggests using `pin!` or `Box::pin` to resolve it.
We will dig into this later about the `Pin` and `Unpin`.
For now, we can just follow the compiler's advice to get unstuck.
We will start by updating the type annotation for `futures`, with a `Pin` wrapping each `Box`
Next we will use `Box::pin` to pin the futures themselves.
```rust
let futures: Vec<Pin<Box<dyn Future<Output = ()>>>> =
vec![Box::pin(tx1_fut), Box::pin(rx_fut), Box::pin(tx_fut)];
```
Now if we compile and run this we get this output
```
received 'hi'
received 'more'
received 'from'
received 'messages'
received 'the'
received 'for'
received 'future'
received 'you'
```
Using `Pin<Box<T>>` adds a small amount of overhead from putting these futures on the heap with `Box`.
We are only doing that to get the types to line up.
We don't actually *need* the heap allocation.
These futures are local to this particular function.
`Pin` is itself a wrapper type, so we can get the benefit of having a single type in the `Vec`.
This was the original reason we tried using `Box`.
Now without the heap allocation we can use `Pin` directly with each future, using the `std::pin::pin` macro.
We still must be explicit about the type of the pinned reference.
Without this Rust will still not know how to interpret these as dynamic trait objects, which is what we need them to be in the `Vec`.
We therefore `pin!` each future when we define it and define `futures` as a `Vec` containing pinned mutable references to the dynamic future type.
```rust
let tx1_fut = pin!(async move {
// --snip--
});
let rx_fut = pin!(async {
// --snip--
});
let tx_fut = pin!(async move {
// --snip--
});
let futures: Vec<Pin<&mut dyn Future<Output = ()>>> =
vec![tx1_fut, rx_fut, tx_fut];
```
Whole code, ignore it.
```rust
extern crate trpl; // required for mdbook test
use std::{
future::Future,
pin::{pin, Pin},
time::Duration,
};
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let tx1 = tx.clone();
let tx1_fut = pin!(async move {
// --snip--
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("future"),
];
for val in vals {
tx1.send(val).unwrap();
trpl::sleep(Duration::from_secs(1)).await;
}
});
let rx_fut = pin!(async {
// --snip--
while let Some(value) = rx.recv().await {
println!("received '{value}'");
}
});
let tx_fut = pin!(async move {
// --snip--
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap();
trpl::sleep(Duration::from_secs(1)).await;
}
});
let futures: Vec<Pin<&mut dyn Future<Output = ()>>> =
vec![tx1_fut, rx_fut, tx_fut];
trpl::join_all(futures).await;
});
}
```
So far we got to this point by ignoring the fact that we might have different `Output` types.
Here is an example of this.
- The anonymous future for `a` implements `Future<Output = u32>`
- The anonymous future for `b` implements `Future<Output = &str>`
- The anonymous future for `c` implements `Future<Output = bool>`
```rust
let a = async { 1u32 };
let b = async { "Hello!" };
let c = async { true };
let (a_result, b_result, c_result) = trpl::join!(a, b, c);
println!("{a_result}, {b_result}, {c_result}");
```
We can use `trpl::join!` to await them because it allows us to pass in multiple future types and produces a tuple of those types.
We *cannot* use `trpl::join_all` because it requires all of the futures passed in to gave the same type.
This would bring us pack to the `Pin` trait.
This is a fundamental tradeoff.
We can either deal with a dynamic number of futures with `join_all`, as long as they are all the same type, or we can deal with a set number of futures with the `join` functions or the `join!` macro, even if they have different types.
This is the same scenario we have faced when working with any other types in Rust.
Futures have some nice syntax for working with them, but ultimately are not special.
## Racing Futures
When we join the futures with the `join` family of functions and macros, we require *all* of them to finish before we move on.
Sometimes we only need *some* future from a set to finish before we move on.
This is like racing one future against another.
Here we once again use `trpl::race` to run two futures, `slow` and `fast` against each other.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let slow = async {
println!("'slow' started.");
trpl::sleep(Duration::from_millis(100)).await;
println!("'slow' finished.");
};
let fast = async {
println!("'fast' started.");
trpl::sleep(Duration::from_millis(50)).await;
println!("'fast' finished.");
};
trpl::race(slow, fast).await;
});
}
```
Each future prints a message when it starts, it then pauses for some amount of time (calling and awaiting `sleep`) and then prints another message when it finishes.
Then we pass both `slow` and `dast` to `trpl::race` and wait for one of them to finish. (`fast` wins)
Unlike when we used `race` before we ignore the `Either` instance it returns here, because all of the interesting behavior happens in the body of the async blocks.
Other implementations *are* fair and will randomly choose which future to poll first.
Regardless of whether the implementation of race we are using is fair, *one* of the futures will run up to the first `await` in its body before another task can start.
Rust gives a runtime a chance to pause the task and switch to another one if the future being awaited isn't ready.
The invers is also true: Rust *only* pauses async blocks and hands control back to a runtime will run up to the first `await` in its body before another task can start.
This mean that if you do a bunch of work in an async block without an await point, that future will block any other futures form making progress.
You sometimes hear this referred to as one future *starving* other futures.
Some cases this may be a big problem.
However if you do some expensive setup or long-running work, or if you have a future that will keep doing some particular task indefinitely.
You will need to think about when and where to hand control back to the runtime.
If you have long-running blocking operations, async can be a useful tool for providing ways for different parts of the program to relate to each other.
*How* would you hand control back to the runtime in those cases?
## Yielding Control to the Runtime
Lets simulate a long running operation
```rust
fn slow(name: &str, ms: u64) {
thread::sleep(Duration::from_millis(ms));
println!("'{name}' ran for {ms}ms");
}
```
The code uses `std::thread::sleep` instead of `trpl::sleep` so that calling `slow` will block the current thread for a number of milliseconds.
We then can use `slow` to stand in for real-world operations that are both long running and blocking.
Here we use `slow` to emulate doing a CPU-bound work in a pair of futures
```rust
let a = async {
println!("'a' started.");
slow("a", 30);
slow("a", 10);
slow("a", 20);
trpl::sleep(Duration::from_millis(50)).await;
println!("'a' finished.");
};
let b = async {
println!("'b' started.");
slow("b", 75);
slow("b", 10);
slow("b", 15);
slow("b", 350);
trpl::sleep(Duration::from_millis(50)).await;
println!("'b' finished.");
};
trpl::race(a, b).await;
```
To begin, each future only hands control back to the runtime *after* carrying out a bunch of slow operations.
You see this output form this code
```
'a' started.
'a' ran for 30ms
'a' ran for 10ms
'a' ran for 20ms
'b' started.
'b' ran for 75ms
'b' ran for 10ms
'b' ran for 15ms
'b' ran for 350ms
'a' finished.
```
As with the earlier example, `race` still finishes as soon as `a` is done.
Notice that there is no interleaving between the two futures.
The `a` future does all of its work until the `trpl::sleep` is awaited, then the `b` future does all of its work until its `trpl::sleep` is awaited.
Finally the `a` future completes.
To allow both futures to make progress between their slow tasks we need to add await points so we can hand control back to the runtime.
This means we need something to await.
If we removed the `trpl::sleep` at the end of the `a` future, it would complete without the `b` future running *at all*.
Now we will try using `sleep` as a starting point for letting operations switch off making progress.
```rust
let one_ms = Duration::from_millis(1);
let a = async {
println!("'a' started.");
slow("a", 30);
trpl::sleep(one_ms).await;
slow("a", 10);
trpl::sleep(one_ms).await;
slow("a", 20);
trpl::sleep(one_ms).await;
println!("'a' finished.");
};
let b = async {
println!("'b' started.");
slow("b", 75);
trpl::sleep(one_ms).await;
slow("b", 10);
trpl::sleep(one_ms).await;
slow("b", 15);
trpl::sleep(one_ms).await;
slow("b", 35);
trpl::sleep(one_ms).await;
println!("'b' finished.");
};
```
Here we added `trpl::sleep` calls with await points between each call to `slow`.
Now thew futures' work is interleaved.
```
'a' started.
'a' ran for 30ms
'b' started.
'b' ran for 75ms
'a' ran for 10ms
'b' ran for 10ms
'a' ran for 20ms
'b' ran for 15ms
'a' finished.
```
Here the `a` future runs for a but before handing off control to `b` because it calls `slow` before ever calling `trpl::sleep`.
After that the futures swap back and forth each time one of them hits and await point.
In this case we do this after every call to slow, we could also break up the work in whatever way makes most sense to us.
We don't actually want to *sleep* here, but we want to switch control.
We want to make progress as fast as we can.
We need a way to hand control back to the runtime.
We can do this directly with the `yield_now` function.
In this example we replace all of the `sleep` calls with `yield_now`
```rust
let a = async {
println!("'a' started.");
slow("a", 30);
trpl::yield_now().await;
slow("a", 10);
trpl::yield_now().await;
slow("a", 20);
trpl::yield_now().await;
println!("'a' finished.");
};
let b = async {
println!("'b' started.");
slow("b", 75);
trpl::yield_now().await;
slow("b", 10);
trpl::yield_now().await;
slow("b", 15);
trpl::yield_now().await;
slow("b", 35);
trpl::yield_now().await;
println!("'b' finished.");
};
```
This is now much clearer about the intent and can be significantly faster than using `sleep`.
Due to timers such as the one used by `sleep` often have limits on how granular they can be.
The version of `sleep` we use for example we always sleep for at least a millisecond, even if we pass it a `Duration` of one nanosecond.
Modern computers are *fast*, and they can do a lot in one millisecond.
This will be demonstrated by setting up a little benchmark.
Note: This isnt an especially rigorous way to do performance testing, but it suffices to show the difference here.
```rust
extern crate trpl; // required for mdbook test
use std::time::{Duration, Instant};
fn main() {
trpl::run(async {
let one_ns = Duration::from_nanos(1);
let start = Instant::now();
async {
for _ in 1..1000 {
trpl::sleep(one_ns).await;
}
}
.await;
let time = Instant::now() - start;
println!(
"'sleep' version finished after {} seconds.",
time.as_secs_f32()
);
let start = Instant::now();
async {
for _ in 1..1000 {
trpl::yield_now().await;
}
}
.await;
let time = Instant::now() - start;
println!(
"'yield' version finished after {} seconds.",
time.as_secs_f32()
);
});
}
```
Here we skip all of the status printing, pass a one-nanosecond `Duration` to `trpl::sleep` and then let each future run by itself without switching between futures.
Then we run for 1,000 iterations and see how long the future using `trpl::sleep` takes compared to the future using `trpl::yield_now` takes
The version using `yeild_now` is *way* faster.
This means that async can be useful even for CPU bound tasks (depending on what your program does/doing).
This 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 the power to determine when it hands control over via await points.
This also means that each future 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 apps, you usually won't be alternating function calls with await points on ever single line.
While yielding control in this way is relatively inexpensive, it is not free.
In many cases trying to break up a compute bound task might make it significantly slower.
Sometimes it is better for the *overall* performance to let an operation briefly.
You can always measure to see what your code's actual performance bottlenecks are.
The underlying dynamic is important to keep in mind.
If you *are* seeing a lot of work happening in serial that you expected to happen in happen concurrently
## Building Our Own Async Abstractions
We can also compose futures together to create new patterns.
For example we can build a `timeout` function with async building blocks we already have.
When we are done, the result will be another building block we could use to create still more async abstractions.
This shows how we would expect this `timeout` to work with a slow future.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let slow = async {
trpl::sleep(Duration::from_millis(100)).await;
"I finished!"
};
match timeout(slow, Duration::from_millis(10)).await {
Ok(message) => println!("Succeeded with '{message}'"),
Err(duration) => {
println!("Failed after {} seconds", duration.as_secs())
}
}
});
}
```
To implement this we will think about the API for `timeout`:
- It needs to be an async function itself so we can await it
- Its first parameter should be a future to run
- We can make it generic to allow it to work with any future
- The second parameter will be the maximum time to wait.
- If we use a `Duration`, this will make it easy to pass along to `trpl::sleep`
- It should return a `Result`
- If the future completes successfully, the `Result` will be `Ok` with the value produced by the future.
- If the timeout elapses first the `Result` will be `Err` with the duration that the timeout waited for.
Here is a declaration of this function
```rust
async fn timeout<F: Future>(
future_to_try: F,
max_time: Duration,
) -> Result<F::Output, Duration> {
// Here is where our implementation will go!
}
```
This satisfies the goals of our types.
Now we will focus on the *behavior* we need.
We want to race the future passed in against the duration.
We can will use `trpl::sleep` to make a timer future form the duration, and use `trpl::race` to run that timer with the future the caller passes in.
We know that `race` is not fair, polling arguments in the order which they are passed.
We pass `future_to_try` to `race` fist so it gets a chance to complete even if `max_time` is a very short duration.
If `future_to_try` finishes first, `race` will return `Left` with the output from `future_to_try`.
If `timer` finishes first, `race` will return `Right` with the timer's output of `()`.
Here we match on the result of awaiting `trpl::race`
```rust
extern crate trpl; // required for mdbook test
use std::{future::Future, time::Duration};
use trpl::Either;
// --snip--
fn main() {
trpl::run(async {
let slow = async {
trpl::sleep(Duration::from_secs(5)).await;
"Finally finished"
};
match timeout(slow, Duration::from_secs(2)).await {
Ok(message) => println!("Succeeded with '{message}'"),
Err(duration) => {
println!("Failed after {} seconds", duration.as_secs())
}
}
});
}
async fn timeout<F: Future>(
future_to_try: F,
max_time: Duration,
) -> Result<F::Output, Duration> {
match trpl::race(future_to_try, trpl::sleep(max_time)).await {
Either::Left(output) => Ok(output),
Either::Right(_) => Err(max_time),
}
}
```
If the `future_to_try` succeeds and we get a `Left(output)`, we return `Ok(output)`
If the sleep timer elapses we get a `Right(())`, we ignore the `()` with `_` and return `Err(max_time)` instead.
With this we have a working `timeout` built out of two other async helpers.
If we run the code, it will print the failure mode after the timeout
```
Failed after 2 seconds
```
Because futures compose with other futures, you can build really powerful tools suing smaller async blocks.
One example of this is the same approach to combine timeout with retries, and in turn use those with operations such as network calls (thus is one of the examples form the beginning of the chapter).
In practice, you usually work directly with `async` and `await` and secondarily with functions and macros like `join`, `join_all`, `race` and so on.
You only need to reach for `pin` to use futures with those APIs.
Some things to consider:
- We used a `Vec` with `join_all` to wait for all of the futures in some group to finish. How could you use a `Vec` to process a group of futures in sequence instead? What are the tradeoffs of doing that?
- Take a look at the `futures::stream::FuturesUnordered` type from the `futures` crate. How would using it be different from using a `Vec`? (Dont worry about the fact that its from the `stream` part of the crate; it works just fine with any collection of futures.)
Next we will look at working with multiple futures in a sequence over time with `streams`

559
Applying Async.md Normal file
View File

@ -0,0 +1,559 @@
# Applying Concurrency with Async
This section will mostly focus on what the difference between threads and futures.
In many cases, the APIs for working with concurrency using async are very similar to those for using threads.
In other cases, they are very different.
Even in the cases where the APIs _look_ similar between threads and async, they often have different behavior, and they nearly always have different performance characteristics.
## Creating a New Task with `spawn_task`
First we will try to do count up using two threads, but instead using async.
The `trpl` crate supplies a `spawn_task` function that looks very similar to the `thread::spawn` API, and a `sleep` function that us an async version of the `thread::sleep` API.
Here we can use these together to implement the counting example.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
trpl::spawn_task(async {
for i in 1..10 {
println!("hi number {i} from the first task!");
trpl::sleep(Duration::from_millis(500)).await;
}
});
for i in 1..5 {
println!("hi number {i} from the second task!");
trpl::sleep(Duration::from_millis(500)).await;
}
});
}
```
As the starting point we set up the `main` function with `trpl::run` so that our top-level function can be async.
Note that from this point forward in this chapter, every example will include this exact same wrapping code with `trpl::run` in `main`.
So we will often skip it as we do with `main`.
Don't forget this in your code.
Next we wrote two loops within that block, each containing a `trpl::sleep` call, which waits for a a second (500 milliseconds) before sending the next message.
Here we put one loop in the body of a `trpl::spawn_task` and the other in a top-level `for` loop.
We also add an `await` after the `sleep` calls.
This code behaves similarly to the thread-based implementation.
This includes the fact that you may see the messages appear in a different order in yor own terminal when you run it.
```
hi number 1 from the second task!
hi number 1 from the first task!
hi number 2 from the first task!
hi number 2 from the second task!
hi number 3 from the first task!
hi number 3 from the second task!
hi number 4 from the first task!
hi number 4 from the second task!
hi number 5 from the first task!
```
This version stops as soon as the `for` loop in the bod of th main async block finishes, due to the task spawned by `spawn_task` is shut down when the `main` function ends.
If you want it to run all the way to the end of completition, you will need to use a join handle to wait for the first task to complete.
With threads, we used the `join` method to "block" unitl the thread was done running.
In this next example we can use `await` to do the same thing, becuase the task handle itself is a future.
Here the `Output` type is a `Result`, so we also unwrap it after awaiting it.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let handle = trpl::spawn_task(async {
for i in 1..10 {
println!("hi number {i} from the first task!");
trpl::sleep(Duration::from_millis(500)).await;
}
});
for i in 1..5 {
println!("hi number {i} from the second task!");
trpl::sleep(Duration::from_millis(500)).await;
}
handle.await.unwrap();
});
}
```
This is the updated output
```
hi number 1 from the second task!
hi number 1 from the first task!
hi number 2 from the first task!
hi number 2 from the second task!
hi number 3 from the first task!
hi number 3 from the second task!
hi number 4 from the first task!
hi number 4 from the second task!
hi number 5 from the first task!
hi number 6 from the first task!
hi number 7 from the first task!
hi number 8 from the first task!
hi number 9 from the first task!
```
It now looks like async and threads give us the same basic outcomes.
This just with different syntax using `await` instead of calling `join` on the join handle, and awaiting the `sleep` calls.
The biggest difference is that we didn't need spawn another operating system thread to do this.
In pack we don't even need to spawn a task here.
This is due to the way async block compiles to anonymous futures, we can put each loop in an async block and have the runtime run them both to completion using the `trpl::join` function.
In the section [Waiting for All Threads to Finishing Using `join` Handles](./Simultaneous%20Code%20Running.md#waiting-for-all-threads-to-finish-using-join-handles), we shows how to use the `join` method on the `JoinHandle` tpe returned when youcall `std::thread::spawn`.
Here the `trpl::join` function is similarbut for futures.
When you give it two futures, it produces a single new future whose output is a tuple cointaing the output of aech future ou passed in once they _both_ complete.
In this next example we use `trlp::join` to wait for both `fut1` and `fut2` to finish.
Here we do _not_ await `fut1` and `fut2` but instead the new future produced by `trpl::join`.
Here we ignore the output, becuase it is just a tuple containing two unit values.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let fut1 = async {
for i in 1..10 {
println!("hi number {i} from the first task!");
trpl::sleep(Duration::from_millis(500)).await;
}
};
let fut2 = async {
for i in 1..5 {
println!("hi number {i} from the second task!");
trpl::sleep(Duration::from_millis(500)).await;
}
};
trpl::join(fut1, fut2).await;
});
}
```
Here we get this output, we see both futures run to completion
```
hi number 1 from the first task!
hi number 1 from the second task!
hi number 2 from the first task!
hi number 2 from the second task!
hi number 3 from the first task!
hi number 3 from the second task!
hi number 4 from the first task!
hi number 4 from the second task!
hi number 5 from the first task!
hi number 6 from the first task!
hi number 7 from the first task!
hi number 8 from the first task!
hi number 9 from the first task!
```
This will produce the exact same order every time, this is very different from what we saw with threads.
This is because the `trpl::join` function is _fair_
This mean that it checks each future equally often, alternating between them, and never lets one race ahead if the other is ready.
Wth threads, the operating system decides which thread to check and how long to let it run.
With async Rust, the runtime might decides which taks to check.
An async runtime might use OS theads under the good as how it manages concurrency.
Runtimes dont have to gurarntee fairness for any given operation, and they often offer different APIs to let you choose whether or not you want fairness.
We will try some of these variantion on awaiting the futures and see what they do:
- Remove the async block form around either or both of the loops
- Await each async block immediately after defining it
- Wrap only the first loop in an async block and await the resulting future after the body ofthe second loop
## Counting Up on Two Tasks Using Message Passing
Sharing data between futures will also be familiar.
We will use message passing again, but this time we will use async version of the tpyes and functions.
We will take a slightly different path than we did in the [Using Message Passing to Transfer Data Between Threads](./Passing%20Data%20Between%20Threads.md#message-passing) to illustrate some of the differences between thread-based and futures-based concurrency.
Here we will begin with just a single async block, _not_ spawning a separate task as we spawned a speerate thread.
```rust
extern crate trpl; // required for mdbook test
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let val = String::from("hi");
tx.send(val).unwrap();
let received = rx.recv().await.unwrap();
println!("Got: {received}");
});
}
```
We use ``trpl::channel`, an async version of the multiple-producer, single-consumer chanel API that we used before.
The async version of the API is a little different.
It uses a mutable rather than an immuatable reciever `rx` and its `recv` method produces a future we need to awiat rather than producing the value directly.
Notice that we don't have to sparate thread or even a task, we merly need to await the `rx.recv` call.
The sychronous `Receiver::recv` method in `std::mpsc::channel` blocks until it receives a message.
The `trpl::Receiver::recv` method does not, because it is async.
Instead of blocking, it hands control bakc to the runtime until either a message is received or the send side of the channel closes.
This by contrast, we don't await the `send` call, because it doesn't block.
It doesnt need ot becuase the channle we are senfing it ot is unbounded.
Note that due to all of this async code runs in a async block in a `trpl::run` call, everything within it can avoid blocking.
The code _outside_ it will block on the `run` function returning.
The whole point of the `trpl::run` function is that it lets you _choose_ where to block on some set of async code.
This is where to transition between sync and async code.
In most async runtimes, `run` is actually named `block_on` for this reason.
Notice two things about this example.
The message will arrive right away.
Although we use a future here, there's no concurrency yet.
Everything in the listing happens in sequence, just as it would if there were no futures involved.
In this next example we will address the first example by sending a series of messages and sleeping in between them.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("future"),
];
for val in vals {
tx.send(val).unwrap();
trpl::sleep(Duration::from_millis(500)).await;
}
while let Some(value) = rx.recv().await {
println!("received '{value}'");
}
});
}
```
Now in addition to sending messages, we need to receive them.
This case we know how many massages are coming in, we could do that manually by calling `rx.recv().await` four times.
In the really world, we generally be waiting on some _unknown_ number of messages, so we need to keep waiting until we determine that there are no more messages.
Before, we used a `for` loop to process all the items received form a synchronous channel.
Rust doesn't yet have a way to write a `for` loop over an _asynchronous_ series of items.
Instead we need to use a loop we haven't seen before, a `while let` conditonal loop.
This is the loop version of the `if let` construct we saw back in the [Concise Control Flow with `if let` and `let else`](./data_types.md#concise-flow-control-with-if-let).
This loop will continue executing as long as the pattern specified continues to match the value.
The `rx.recv` call produces a future, which will be avaited for.
The runtime will pause the future until it is ready.
Once the message arrives, the future will resolve to `Some(message)` as man times as the message arrives.
When the channel closes, regradless of whether _any_ messages have arrived, the future will instead reslove to `None`.
This indicates that there are no more values and thus we should stop polling, that is, stop awaiting.
The `while let` loops does all of this together.
If the result of calling `rx.recv().await` is `Some(message)`, we get access to the message and we can then use it in the loop body, just as we could with `if let`.
If the result is `None`, the loop ends.
Every time the loop completes, it hits the awiat point again, so the runtime pauses again until another message arrives.
Now the code sucessfully sends and receives.
This still has some problems.
One thing, the messages do not arrive at half-second intervals.
They arrive all at once, 2 (2,000 milliseconds) after we start the program.
Another thing is that this program never exits, instead it waits forever for a new messages.
You need to manually shut donw the runtime using ctrl-c.
Lets see why the messages come in all at once after the full delay rather than coming in with delays between each one.
Within a given async block, the order in which `await` keywords appear in the code is also the order in which they are executed whne the program runs.
In the previous example everything in the async block runs linearly.
There is still no concurrency.
All the `tx.send` calls happen, interspersed with all of the `trpl::sleep` calls and their associated await points.
Only then does the `while let` loop get to go through any of the `await` points on the `recv` calls.
To get the intended behavior, where the sleep delay happens between each message.
We just need to put the `tx` and `rx` operations in thier own async blocks.
Thne the runtime can execute each of them spearately using `trpl::join`, just as in the counting example.
We will once again await the result of calling `trpl::join`, not the individual futures.
If we awaited the individual futres in sequence, we would just end up bakc in a sequential flow exactly what we are trying _not_ to do.
Here is an example of this
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let tx_fut = async {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("future"),
];
for val in vals {
tx.send(val).unwrap();
trpl::sleep(Duration::from_millis(500)).await;
}
};
let rx_fut = async {
while let Some(value) = rx.recv().await {
println!("received '{value}'");
}
};
trpl::join(tx_fut, rx_fut).await;
});
}
```
Here we updated the code so that the messages get printed at 500-milliseconds intervals rather than all in a rush after 2 seconds.
The program still never exits, because of the way `while let` loop interacts with `trpl::join`
- The future reutrned from `trpl::join` completes only once _both_ futures passed to it have completed
- The `tx` future completes once it finishes sleeping after sending the last message in `vals`
- The `rx` future won't complete until the `while let` loop ends
- The `while let` loop won't end until awaiting `rx.recv` produces `None`
- Awaiting `rx.recv` will return `None` only once the other end of the channel is closed
- The channel will close only if we call `rx.close` or when the sender side, `tx`, is dropped
- We don't call `rx.close` anywhere and `tx` will not be dropped until the outermost async block passed to `trpl::run` ends
- The block can't end because it is blocked on `trpl::join` completing, which takes us back to the top of this list
We could manually close `rx` by calling `rx.close` somewhere, but this doesn't make much snese.
Stopping after handling some arbitrary number of messages.
This does not make much sense.
Stopping after some arbitrary nubmer of messages would ake the program shut down, but we could miss messages.
We need a different way to ensure that `tx` gets dropped _before_ the end of the function.
We async block where send the messages doesn't require ownerhip, but if we could move `tx` into that async block, it would be dropped once that block ends.
The same basic dynamics apply o async blocks, so the `move` keyword works with async blocks just as it does with closures.
In this next example we change the block used to send messages from `async` to `async move`.
Now when we run _this_ version, it shuts down gracefully after the last message is send and received
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let tx_fut = async move {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("future"),
];
for val in vals {
tx.send(val).unwrap();
trpl::sleep(Duration::from_millis(500)).await;
}
};
let rx_fut = async {
while let Some(value) = rx.recv().await {
println!("received '{value}'");
}
};
trpl::join(tx_fut, rx_fut).await;
});
}
```
This async channel is also a multiple-producer channel, so if we call `clone` on `tx` if we want to send messages from the multiple futures.
Thi is shown below.
```rust
extern crate trpl; // required for mdbook test
use std::time::Duration;
fn main() {
trpl::run(async {
let (tx, mut rx) = trpl::channel();
let tx1 = tx.clone();
let tx1_fut = async move {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("future"),
];
for val in vals {
tx1.send(val).unwrap();
trpl::sleep(Duration::from_millis(500)).await;
}
};
let rx_fut = async {
while let Some(value) = rx.recv().await {
println!("received '{value}'");
}
};
let tx_fut = async move {
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap();
trpl::sleep(Duration::from_millis(1500)).await;
}
};
trpl::join3(tx1_fut, tx_fut, rx_fut).await;
});
}
```
Now we clone `tx`, creating `tx1` outside the first async block.
Next we move `tx1` into that block just like we idd before `tx`.
Then we move the original `tx` into a _new_ async block, wher we send more messages on a slightly slower delay.
We happen to put this new async block after the async block for receiving messages, but it also could go before as well.
The key is the order in which futures are awaited, not in which they are created.
Both of the async blocks for sending messages need to be `async move` blocks so that both `tx` and `tx1` get dropped when those blocks finish.
If not we would end up back in the same infinite loop we started out in.
Finally, we switch form `trpl::join` to `trpl::join3` to handle the additional future.
In this out we can see all the messages form both sneidng futures, and because the sending futures use slightly differnt delays after sending.
The messages are also received at those different intervals.
```
received 'hi'
received 'more'
received 'from'
received 'the'
received 'messages'
received 'future'
received 'for'
received 'you'
```
This is a start, but it limits us to just a handful of futures.
Two with `join` or three with `join3`
Next we will look into working with more futures.
[Next ection Link Here](./Any%20Number%20of%20Futures.md)

View File

@ -0,0 +1,139 @@
# Fundamentals of Asynchronous Programming: Async, Await, Futures, and Streams
Many of the operations we ask computers to do can take a while to finish.
While waiting for that task it would be nice to do something else while we are waiting for those long-running processes to complete.
Modern computers offer two techniques while working on more than one operation at a time:
- Parallelism
- Concurrency
Once we start writing programs that involve parallel or concurrent operations, we quickly encounter new challenges inherit to _asynchronous programming_.
This is where operations may not finish sequentially in the order they were started.
This section builds on the use of threads for parallelism and concurrency by introducing an alternative approach to asynchronous programming.
Rust's Futures, Streams, the `async` and `await` syntax that supports them and the tools for managing and coordinating between asynchronous operations.
We will consider this example.
Say you are exporting a video you created of a family celebration, an operation that could take anywhere from minutes to hours.
The video export will use as many resources as available on the GPU and CPU.
If you only had one CPU core and your operating system didn't pause that export until it completed (it executed _synchronously_), you wouldn't be able to do anything else on the computer while that task was running.
This would be incredibly frustrating experience.
Fortunately, your computer's operating system can, and does, interrupt the export often enough to let you get other work done simultaneously.
In another scenario, say you are downloading a video from somewhere else, which can also take a while but does not take up as much CPU time.
In this case the CPU has to wait for data to arrive from the network.
While you can start reading the data once it starts to arrive, it may take some time for all of it to show up.
Even once the data us all present, if the video is quite large, it could take at least a second or two to load it all.
The video export is an example of a _CPU-bound_ or _compute-bound_ operation.
It is limited by the computer's potential data processing speed within the CPU or GPU, and how much speed it can dedicate to the operation.
The video download is an example of a _IO-bound_ operation because it is limited by the speed of the computer's _input and output_; it can only go as fast as the data can be sent across the network.
In both of these examples, the operating system's invisible interrupts provide a form of concurrency.
This concurrency happens only at the level of the entire program: the operating system interrupts one program to let other programs get work done.
In many cases, because we understand our programs at a much more granular level than the OS does, we can spot opportunities for concurrency that the operating system can't see.
Lets say we are building a tool to manage file downloads, we should be able to write our program so that starting one download won't lock up the UI, and users should be able to start multiple downloads at the same time.
Many operating system API's for interacting with the network are _blocking_; that is they block the program's progress until the data they are processing is completely ready.
Note: This is how _most_ functions calls work.
However, the term _blocking_ is usually reserved for function calls that interact with files, the network, or other computer resources.
Due to these cases where an individual program would benefit from the operation being _non_-blocking.
We could avoid blocking our main thread by spawning a dedicated thread to download each file.
The overhead of those threads would eventually become a problem.
It would be preferable if the call didn't block it in the first place, it would be better if we could write in the same style we use in blocking code.
This would be a similar case/code
```rust
let data = fetch_data_from(url).await;
println!("{data}");
```
This is example what Rust's async (short for _asynchronous_) abstraction gives us.
This chapter we will learn about:
- Futures and Async Syntax [Section Link Here](./Futures%20and%20Async.md)
- How to use Rust's `async` and `await` syntax [Section Link Here](./Applying%20Async.md)
- How to use the async model to solve some of the same challenges we looked at in Ch 16 [Section Link Here]()
- How multithreading and async provide complementary solutions, that you can combine in many cases [Section Link Here]()
Before jumping into how async works in practice, we need o take a short detour to discuss the differences between parallelism and concurrency.
## Parallelism and Concurrency
So far we treated parallelism and concurrency as mostly interchangeable so far.
Now we need to distinguish between them more precisely, because the differences will now start to show up.
Consider the different ways a team could split up work on a software project.
You could assign a single member multiple tasks assign each member one task or use a mix of the two approaches.
When an individual works on several different tasks before any of them is complete, this is _concurrency_.
Or maybe you have two different projects checked out on your computer and when you get bored or stuck on one project, you switch to the other.
As one person, so you can't make progress on both tasks at the exact same time, but you can multi-task, making progress on one at a time by switching between them.
Here is a picture of this
<img src="https://doc.rust-lang.org/book/img/trpl17-01.svg" />
When the team instead splits up a group of tasks by having each member take one task and work on it alone, this is _parallelism_
Each person on the team can make progress at the exact same time.
<img src="https://doc.rust-lang.org/book/img/trpl17-02.svg" />
In both of these workflows, you might have to coordinate between different tasks.
Maybe it was _thought_ that the task was totally independent from every other.
It actually requires another person on the team to finish their task first..
Some of this work can be done in parallel, but some of it actually was _serial_: it could only happen in a series, one task after another.
Here is a diagram of this
<img src="https://doc.rust-lang.org/book/img/trpl17-03.svg" />
Likewise, you may realize that one of your own tasks depends on another of your tasks.
Now your concurrent work has also become serial.
Parallelism and concurrency can intersect with each other as well.
If you learn that colleague is stuck until you finish one of your tasks, you will probably focus all your efforts to "unblock" you colleague.
You and your coworkers are no longer able to work in parallel, and you are also no longer able to work concurrently on the task assigned.
The same dynamics come into play with software and hardware.
On a CPU core, the CPU can perform only one operation at a time but it can still work concurrently.
Using tools such as threads, processes and async, the computer can pasue one set of calculations and switch to others before cycling back to that first set of calculations again.
One a machine with multiple CPU cores, it can also do work in parallel.
One core can be performing one task while another core performs a completely unrelated one, and those operations actually happen at the same time.
When working with async in Rust, we are always dealing with concurrency.
Depending on the hardware, OS and the async runtime we use (more on async runtimes shortly), that concurrency many also use parallelism under the hood.

319
Cargo Workspaces.md Normal file
View File

@ -0,0 +1,319 @@
# Cargo Workspaces
As our project developsm you might find that the library crate continues to get bigger and you want to split your package further into multiple library crates.
Cargo offers a feature called *workspaces* that can help manage related packages that are developed at the same time
## Creating a Workspace
A *workspace* is a set of packages that share the same *Cargo.lock* and output directory.
Lets explore this by a making a project using a workspace
Here we will use trivial code so that the focus is on the structure of the workspace.
There are mulitple ways to structure a workspace, here we will just show one common way.
Here we will have a workspace containing a binary and two libraries.
The binary will provide the main functionality, will depend on the two libraries.
One lib will provide an `add_one` function
Another lib will provide an `add_two` function
These three crates will be part of the same workspace.
We will start by creating a new directory for the workspace
```
$ mkdir add
$ cd add
```
Now in the *add* directory, we create the *Cargo.toml* file that will config the entire workspace.
This file wont have a `[package]` section, instead it will start with a `[workspace]` section.
This allows us to add members to the workspace.
We also make it a point to use the latest and greatest version of Cargo's resolver algorithm in our workspace by setting the `resolver` to `"2"`
Here is the written out version of the toml file until this point
```toml
[workspace]
resolver = "2"
```
Next we will create the `adder` binary crate
We do this by running `cargo new` within the *add* directory
```
$ cargo new adder
Creating binary (application) `adder` package
Adding `adder` as member of workspace at `file:///projects/add`
```
By running the `cargo new` command inside a workspace it automatically adds the newly created package to the `members` key in the `[workspace]` definition in the workspace `Cargo.toml`
It will look like this
```toml
[workspace]
resolver = "2"
members = ["adder"]
```
Now at this point we can build the workspace by rnning `cargo build`
The files in the *add* directory should now look like this
```
├── Cargo.lock
├── Cargo.toml
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
```
The workspace has one *target* directory at the top level that compled artifacts will be placed into
The `adder` package doesn't have its own *target* directory.
Even if we were to run `cargo build` from inside the *addre* dir, the compiled artifacts would still end up in *add/target* rather than *add/adder/target*
Cargo structs the *target* directory in a workspace like this because the crates in a workspace are meant to depend on each other.
Without this we would have to repeat compiled artifacts and this would cause unnecessary rebuilding.
So we share one *target* directory to avoid this.
## Creating the Second Package in the Wrokspace
Now lets add another package to the workspace, we will call it
First we will change the top level *Cargo.toml* to specify the *add_one* path in the `members` list
Here is the updated toml
```toml
[workspace]
resolver = "2"
members = ["adder", "add_one"]
```
Now lets generate a new library crate named `add_one`
```
$ cargo new add_one --lib
Creating library `add_one` package
Adding `add_one` as member of workspace at `file:///projects/add`
```
Now the *add* directory should look like this
```
├── Cargo.lock
├── Cargo.toml
├── add_one
│ ├── Cargo.toml
│ └── src
│ └── lib.rs
├── adder
│ ├── Cargo.toml
│ └── src
│ └── main.rs
└── target
```
In *add_one/src/lib.rs* lets add the `add_one` function
```rust
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
Now we need to have the `adder` package with our binary depend on the `add_one` package that has our library.
We need to add a path dependency on `add_one` to *adder/Cargo.toml*
```toml
[dependencies]
add_one = { path = "../add_one" }
```
Cargo doesnt assume that crates in a workspace will depend on each other.
We must explicit about the dependency relationships.
Now lets use the `add_one` function in the `adder` crate.
You modify the *adder/src/main.rs* file and change the `main` function to call the `add_one` function
Here is the updated `main` function in the binary crate
```rust
fn main() {
let num = 10;
println!("Hello, world! {num} plus one is {}!", add_one::add_one(num));
}
```
Now we can build the workspace from the top-level *add* directory
```
$ cargo build
Compiling add_one v0.1.0 (file:///projects/add/add_one)
Compiling adder v0.1.0 (file:///projects/add/adder)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.22s
```
In order to run the binary crate from the *add* directory have have to specify which package in the workspace we want to run.
We do this by using the `-p` argument and the package name with `cargo run`
```
$ cargo run -p adder
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
Running `target/debug/adder`
Hello, world! 10 plus one is 11!
```
This runs the `main` function in *adder/src/main.rs*, which depends on the `add_one` crate
### Depending on an External Package in a Wrokspace
Notice that the workspace only has one *Cargo.lock* file at the top level.
This ensure that all crates are using the same version of all dependencies.
If we add the `rand` package to the *adder/Cargo.toml* and *add_one/Cargo.toml* files
Cargo will resolve both of thos to one version of `rand` and record that in the one *Cargo.lock*.
This ensures that all the crates in the workspace use the same dependencies, this also ensures that all crates will always be compatible with each other.
Lets demonstrate how to add the `rand` crate to the `[dependencies]` section in the *add_one/Cargo.toml* file so we can use the `rand` crate in the `add_one` crate
```toml
[dependencies]
rand = "0.8.5"
```
Now we can add `use rand;` to the *add_one/src/lib.rs* file.
Then build the whole workspace in the *add* directory will bring in and compile the `rand` crate.
We will get a warning about a unused `rand` becasue we dont refer to it after we bring it into scope
```
$ cargo build
Updating crates.io index
Downloaded rand v0.8.5
--snip--
Compiling rand v0.8.5
Compiling add_one v0.1.0 (file:///projects/add/add_one)
warning: unused import: `rand`
--> add_one/src/lib.rs:1:5
|
1 | use rand;
| ^^^^
|
= note: `#[warn(unused_imports)]` on by default
warning: `add_one` (lib) generated 1 warning (run `cargo fix --lib -p add_one` to apply 1 suggestion)
Compiling adder v0.1.0 (file:///projects/add/adder)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.95s
```
Now the top level *Cargo.lock* now contains info about the dependency of `add_one` on `rand`
However, even though `rand` is used somewhere in the workspace, we can't use it in other crates in the workspace unless we add `rand` to thier *Cargo.toml* files as well
For example if we add `use rand;` to the *adder/src/main.rs* file for the `adder` package we would get an error
```
$ cargo build
--snip--
Compiling adder v0.1.0 (file:///projects/add/adder)
error[E0432]: unresolved import `rand`
--> adder/src/main.rs:2:5
|
2 | use rand;
| ^^^^ no external crate `rand`
```
In order to fix this we need to edit the *Cargo.toml* file for the `adder` package and indicate that `rand` is a dependency for it as well.
Rebuilding the `adder` package with the eidt will now add the `rand` crate to the list of dependencies for `adder` in *Cargo.lock*.
No additional copies of `rand` will be downloaded.
Cargo will ensure that every crate in every package in the workspace using the `rand` package will be using the same version as log as they specify compatible versions of `rand`.
This saves us space and ensures that the crates in the workspace will be compatible with each other.
If crates in the workspace specify incompatible verions of the same dependency, Cargo will attempt to resolve each of them but it will still try to resolve it with as few versions as possible
### Adding a Test to a Workspace
For another enchancement lets add a test of the `add)one::add_one` function within the `add_one` crate
Here is the updated *add_one/src/lib.rs*
```rust
pub fn add_one(x: i32) -> i32 {
x + 1
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
assert_eq!(3, add_one(2));
}
}
```
Now if we run `cargo test` in the top level *add* directory in a workspace structured like thisone will run the tests for all the crates in the workspace.
Here is what the output will look like this
```
$ cargo test
Compiling add_one v0.1.0 (file:///projects/add/add_one)
Compiling adder v0.1.0 (file:///projects/add/adder)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.20s
Running unittests src/lib.rs (target/debug/deps/add_one-f0253159197f7841)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Running unittests src/main.rs (target/debug/deps/adder-49979ff40686fa8e)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests add_one
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
The first section shows that the `it_works` test in the `add_one` crate pased
The next section shows that zero tests were found in the `adder` crate.
Thhe last section shows zero documentation tests were found in the `add_one` crate.
We can also run tests for a particular crate in a workspace from the top-level directory.
We do this by adding the `-p` flag and specifying th name of the crate we want to test.
Here is an example of this
```
$ cargo test -p add_one
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.00s
Running unittests src/lib.rs (target/debug/deps/add_one-b3235fea9a156f74)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests add_one
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
This shows that `cargo test` only ran tests for the `add_one` crate and didn't run the `adder` crate tests.
If you publish the crates in the workspace to [crates.io](https://crates.io), each crate in the workspace will need to be published separately.
Just like `cargo test`, you can publish a particular crate in the workspace by using the `-p` flag and specifying the name of the crate we want to publish.
As your project grows, consider using a workspace.
It makes it easier to understand smaller, individual components than one big blog of code.
Also by keeping the crates in a workspace can make coordination between crates easier if they are often changed at the same time.

16
Cargo and Cratesio.md Normal file
View File

@ -0,0 +1,16 @@
# More About Cargo and Crates.io
Previously Cargo has only been used to do basic features of Cargo, like build, run, and test the code.
Cargo can do so much more
This chapter will go over some more advanced features like:
- [Customize your build](./Custome%20Build%20Profiles.md) through release profiles
- [Publish libraries](./Publishing%20libraries.md) on [crates.io](https://crates.io/)
- Organize large projects with [workspaces](./Cargo%20Workspaces.md)
- [Install binaries](./Install%20Binaries.md) from [crates.io](https://crates.io/)
- [Extend Cargo](./Extending%20Cargo.md) using custom commands
Cargo can do even more than what will be covered.
You can chack [the documentation](https://doc.rust-lang.org/cargo/) for a full explanation of all its features.

View File

@ -0,0 +1,177 @@
# Characteristics of Object-Oriented Languages
There is no consensus about what features a language must have to be considered object-oriented.
Rust is influenced by many programming paradigms, including OOP.
Arguably, OOP languages share certain common characteristics, namely objects, encapsulations and ingeritance.
Lets see what each of those means and whether Rust supports it.
## Object Contain Data and Behavior
The book _Design Patterns: Elements of Reusable Object-Oriented Software_ by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides (Addison-Wesley Professional, 1994).
This is colloquially referred to as _The Gang of Four_ book, is a catalog of object-oriented design patters.
It defines OOP as this:
Object-oriented programs are made up of objects.
An _object_ packages both data and the procedures that operate on that data.
The procedures are typically called _methods_ or _operations_.
Using this definition, Rust is object-oriented: structs and enumbs have data, and `impl` blocks provide methods on structs and enums.
Even though structs and enums with methods aren't _called_ obejcts, they provide the same functionaliy accound to the Gang of Four's definition of objects.
## Encapsulation that Hides Implementation Details
An aspect commonly associated with OOP is the idea of _encapsulation_.
This means that the implementation details of an object aren't accessible to code using that object.
Therefore, the only way to interact with an object is through its public API.
Code using the object shouldn't be able to reach into the object's internals and change data or behaviro directly.
This enables the programmer to change and refactor an object's internals without needing to change the code that uses the object.
We discussed previously how to control encapsulation in Ch7.
We can use the `pub` keyword to decide which modules, types, function and methods in our code should be public .
By default everything else is private.
For example, if we defined a struct `AveragedCollection` that has a field containing a vector of `i32` values.
The struct can also have a field that contains the average of te vlaues in the vector, meaning the average doesn't have to be computed on demand whenever anyone needs it.
In other words, `AveragedCollection` will cache the calculated average of the values in the vector.
Meaning the average doesn't have to be computed on demand whenever it is needed.
`AveragedCollection` will cache the calculated average for us.
Here is the definition of the `AveragedCollection` struct
```rust
pub struct AveragedCollection {
list: Vec<i32>,
average: f64,
}
```
This struct is marked `pub` os that other code can use it.
The fields within the struct remain private.
This is improtant becuase we want to ensure that whenever a value is added or removed from the lust, the average is also updated.
We accomplish this by implementing `add`, `remove` and `average` methods on the struct.
This is shown here
```rust
impl AveragedCollection {
pub fn add(&mut self, value: i32) {
self.list.push(value);
self.update_average();
}
pub fn remove(&mut self) -> Option<i32> {
let result = self.list.pop();
match result {
Some(value) => {
self.update_average();
Some(value)
}
None => None,
}
}
pub fn average(&self) -> f64 {
self.average
}
fn update_average(&mut self) {
let total: i32 = self.list.iter().sum();
self.average = total as f64 / self.list.len() as f64;
}
}
```
The public methods, `add`, `remove` and `average` are the only ways to access or modify data in any instance of `AverageCollection`.
When an item is added or removed to `list`, using the associated method, the implementations of each call the private `update_average` method that handles updating the `average` field as well.
We leave the `list` and `average` fields private, so that there is no way for external code to add or remove items to or form the `list` field directly.
The `average` method returns the value in the `average` field, this allows for external code to read the `average` but not modify it.
Because we have encapsulated the impleentation details of `AveragedCollection`.
We can easily change aspects, such as the data structure, in the future.
For example, we could use a `HashSet<i32>` instead of a `Vec<i32>` for the `list` field.
As long as the signatures of the `add`, `remove`, and `average` public methods stay the same.
Code using `AveragedCollection` wouldn't need to change to order to compile.
If we made `list` public instead, this wouldn't necessarily be the case
`HashSet<i32>` and `Vec<i32>` have different methods for adding and removing items, so the external code would likely have to change if it were modifying `list` directly.
If encapsulation is a required aspect for a language to be considered object-oriented, then Rust meets that requirement.
The option to use `pub` or not for different parts of code enbalbes encapsulation of implementation details
## Inheritance as a type System and as Code Sharing
_Inheritance_ is a mechanism whereby an object can inherit elements from another obejct's definition, thus gaining the parent object's data and behavior without you having to define them again.
If a language must have inheritance to be an obejct-oriented, then Rust is not one.
There is no way to define a struct that inherits the parent struct fields and method implementations without using a macro.
However, if you are use to having this tool available, you cna use other solutions in Rust, depending on your reason for reaching for inheritance.
Yuo choose inheritance for main reasons.
Resue of code: you can implement particular behavior for one type, and ingeritance enables ou to reuse that implementation for a different type.
You can do this in a limited way in Rust ocde using default trait method implementations.
We saw this before with the default implemetnation of the `summarize` method on the `Summary` trait.
Any type implementing the `Summary` trait would have the `summarize` method available on it without any further code.
This is similar to a parent class having an implementation of the `summarize` method when we `implement` the `Summary` trait, which is similar to a child class overriding the implementation of a method inherited form a parent class.
The other resaon to use ingeritance relates to the type system: to enable a child to be used in the same place as the parent type.
This has another name _polymorphism_, which means that you can substitute multiple objects for each other at runtime if they share certain characteristics.
### Polymorphism
To many this is synonymous with inheritance.
But it is actually a more general concept that refers to code that can work with data of multiple tpyes.
For inheritance, those types are generally subclasses.
Rust instead use generics to abstract over different possible types and trait bounds to impose constraints on what those tpyes must provide.
This is sometimes called *bounded parametric polymorphism*.
Inheritance has recently fallen out of favor as a programming deisgn solution, becuase it is often at risk of sharing more code than necessary.
Subclasses shouldn't always share all characteristics of thier parent class but will do so with inheritance.
This can make a program's design less flexible.
This also introduces the possibility of calling methods on subclasses that don't make sense or that cause errors because the methods don't apply to the subclass.
Additionally some languages will only allow single inheritance, meaning a subclass can only inherit from one class, thus further restricting the flexibility of a program's design.
These reasons are why Rust takes the different approach of using trait objects instead of inheritance.
Next lets see how trait obejcts enable polymorphism in Rust. [Here](./Trait%20Objects%20that%20allow%20for%20Values%20of%20Different%20Types.md)

49
Concurrency.md Normal file
View File

@ -0,0 +1,49 @@
# Fearless Concurrency
Another one of Rust's major goals is handling concurrent programming safely and efficiently.
*Concurrent programming* is where different parts of a program execute independently.
*Parallel programming* is where different parts of a program execute at the same time.
These are becoming increasingly important as more computers take adantage of thier multiple processors.
Historically programming in these contexts has been difficult and error prone, which Rust hops to change this fact.
Intially this was though of as two seperate challenges by the Rust team.
Over time though the team discovered that ownership and type systems are a powerful set of tools to help manage memory safety *and* concurrency problems.
By usng these systems, many concurrency erros are compile-tme erros in Rust rather than runime erros.
This therefore, instead of making you spend lots of time trying to repoduce the exact circumstances under wihch a runtime concurrency buh occurs.
The inccorect code will be refused at compile time and present an error that explains the problem.
This results that you can fix your code while you are working on it rather than potentailly after it has been integrated into production.
This has been nicknamed this aspect of Rust *fearless concurrency*.
Fearless concurrency allows you to write code that is free of subtle bugs and is easy to refactor without introducing new bugs.
Note that we will simplify and refer to many of the problems as *concurrent* rather than being more precise by saying *concurrent and/or parallel*.
If this book were about concurrency and/or parallelism then the book would be more specific.
For this chapter a mental substitution of *concurrent and/or parallel* should be made whenever the use of *concurrent* is made.
Many lnaguages are dogmatic about the solutions they offer for handling concurrent problems.
An example of this is is in Erlang. This has elegant functionality for message-passing concurrency but has only obscure ways to share state between threads.
This supporting only a subset of possible solutions is a reasonable stategy for giher-level languages, because a higher-level language promises benefits from giving up some control to gain abstractions.
However, lower-level languages are expected to provide the solution with the best performance in any given situation and have fewer abstractions over the hardware.
This means that Rust offers a variety of tools for modeling problems in whatever way is appropriate for the situation and requirements.
Here are the topics that will be covered in this section:
- How to create threads to run multiple pieces of code at the same time [Section Link Here](./Simultaneous%20Code%20Running.md)
- *Message-passing* concurrency, where channels send messages between threads [Section Link Here](./Passing%20Data%20Between%20Threads.md)
- *Shared-state* concurrency, where multiple threads have access to some piece of data [Section Link Here](./Shared%20State%20Concurrency.md)
- The `Sync` and `Send` traits, which extend Rust's concurrency guarantees to use-defined types as well as types provided by the std library [Section Link Here](./Sync%20and%20Send.md)

68
Custome Build Profiles.md Normal file
View File

@ -0,0 +1,68 @@
# Customizing Builds with Release Profiles
Rust has *release profiles* which are predefined and customizable profiles with different configuations that allow a programmer to have more control over various options for compiling code.
Each profile is configured independently of others.
Cargo has two main profiles
- the `dev` profile, Cargo uses this when you run `cargo build`
- the `release` profile, Cargo uses this when you run `cargo build --release`
The `dev` profile is defined with good defaults for development
The `release` profile has good defaults for release builds
These profile names are present and fimilar from the output of builds
```
$ cargo build
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.00s
$ cargo build --release
Finished `release` profile [optimized] target(s) in 0.32s
```
Cargo has default seeting for each of the profiles that apply when you havent specified any `[profile.*]` sections in the project's *Cargo.toml* file
By adding `[profile.*]` sections you want to customize, you override any subset of the default settings
For example here are the default values for the `opt-level` setting for the `dev` and `release` profiles
```toml
[profile.dev]
opt-level = 0
[profile.release]
opt-level = 3
```
The `opt-level` setting controlsthe nubmer of optimizations the Rust compiler will apply to your code
This has a range of 0 - 3
Applying more optimizations extends the compiling time.
If you are compiling your code often and want fewer optimizations to compile even if the resulting executable runs slower.
This then makes the default `opt-level` for `dev` `0` becasue you want to spend less time compiling.
When you are ready to realse your code it is best to spend more time compiling.
You will only optimize the compilation and spend mroe time because you will run that optimized program many times, so release mode trades longer compile time for code tha runs faster.
The default `opt-level` for `release` is therefore `3` because of that fact.
You can override a default seeting by adding a different value for it in *Cargo.toml*
For example if we wanted to use the optimization level 1 in the `dev` profile
We can add these lines to the project's *Cargo.toml* file
```toml
[profile.dev]
opt-level = 1
```
This overrides the defualt setting of `0`
Now when you run `cargo build` cargo will use the defaults for the `dev` profile and our customization to the `opt-level`
This is because of the specifiaction we set to the `opt-level`.
In this customization Cargo will apply more optimization than the default, but still not as many compaired to the release build.
For the full list of config options nad defaults for each profile, see [Cargo's documentation](https://doc.rust-lang.org/cargo/reference/profiles.html).

321
Deref Trait.md Normal file
View File

@ -0,0 +1,321 @@
# Treating Smart Pointers Like Regular References with the `Deref` Trait
Implmenting the `Deref` trait allows you to customize the behavior of the *dereference operator* `*`.
This is not the multiplication or glob operator
Implementing `Deref` in a way such that a smart pointer can be treated like a regular reference.
You can wirte code that operators on references and use that code with smart pointers as well.
Now lets look at the dereference operator works with regualr references.
Next we will try to define a custom type that behaves like `Box<T>`.
Then we will see why the dereference operator doesnt work like a reference on our newly behaves lik `Box<T>`.
We will explore how implementing the `Deref` trait makes it possible for smart pointers to work in a way that is simialr to references.
Finally we will lokk at Rust's *deref coercion* feature and how it let us work with either references or smart pointers.
Note: The big difference between the `MyBox<T>` type, the custom type we are about to build and the real `Box<T>`.
Our version will not store its data on the heap.
We are focusing on the `Deref` trait, so where the data is actualy stored is less improtant than the pointer-like behavior.
## Following the Pointer to the Value
A regular reference is a type of pointer.
One way to think about a pointer is, an arrow to a value stored somewhere else.
In this example we create a reference to an `i32` value.
We then use the dereference operator to follwo the reference to the value.
```rust
fn main() {
let x = 5;
let y = &x;
assert_eq!(5, x);
assert_eq!(5, *y);
}
```
The variable `x` holds a `5` (`i32`) value.
We then set `y` equal to a refernce to `x`.
We assert that `x` is equal to `5`.
If we want to make an assertion about the value in `y`, we have touse `*y` to follow the reference to the value it's pointing to.
Hence the need for a *dereference*.
Once we dereference `y` we havce access to the integer value `y` is pointing to so that we can compare with `5`
If we tired to use `assert_eq!(5, t);` instead we woul get the compiler error
```
$ cargo run
Compiling deref-example v0.1.0 (file:///projects/deref-example)
error[E0277]: can't compare `{integer}` with `&{integer}`
--> src/main.rs:6:5
|
6 | assert_eq!(5, y);
| ^^^^^^^^^^^^^^^^ no implementation for `{integer} == &{integer}`
|
= help: the trait `PartialEq<&{integer}>` is not implemented for `{integer}`
= note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider dereferencing here
--> file:///home/.rustup/toolchains/1.82/lib/rustlib/src/rust/library/core/src/macros/mod.rs:46:35
|
46| if !(*left_val == **right_val) {
| +
For more information about this error, try `rustc --explain E0277`.
error: could not compile `deref-example` (bin "deref-example") due to 1 previous error
```
Comparing a number to a reference is not allowed because they are differnect types.
We must ue the dereference operator to follow the reference to the value they are pointing at.
## Using `Box<T>` Like Reference
We can rewrite the code from the example to use a `Box<T>` instead of a reference.
Here dereference operator using on the `Box<T>` functions the same way as the dereference operator used on the reference (from before).
```rust
fn main() {
let x = 5;
let y = Box::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
```
The main difference between the two eamples is that we ext `y` to be an instance of a `Box<T>` pointing to a copied value of `x` rather than a reference pointing to the value of `x`
In the last assertion we can use the dereference operator to following the pointer of the `Box<T>` in the way as we deferenced `y` when it was a reference.
## Defining Our Own Smart Pointer
Here we will bouild a smart pointer simialr to the `Box<T>` type provided by the std library.
This is in order to explain fully how smart pointers behave differently from references by defualt.
Then we will look into how to add the ability to use the dereference operator.
The `Box<T>` type is defined as a tuple struct with one element.
In this example we defined `MyBox<T>` type in the same way.
We will aslo define a `new` function to match the `new` function defined in `Box<T>`
```rust
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> MyBox<T> {
MyBox(x)
}
}
```
Here we defined a struct named `MyBox` and declarce a generic paramter `T` beucause we want our type to hold values of any type.
The `MyBox` type is a tuple struct with one element of type `T`.
The `MyBox::new` function takes one parameter of type `T` and returns a `MyBox` instance that holds the value passed in.
If we try adding the `main` function from above to our preivous examples.
We will change it to use `MyBox<T>` type we defined instead of `Box<T>`.
The code will not compie because Rust doesn't know how to dereference `MyBox`
```rust
fn main() {
let x = 5;
let y = MyBox::new(x);
assert_eq!(5, x);
assert_eq!(5, *y);
}
```
Here is the resulting compilation error
```
$ cargo run
Compiling deref-example v0.1.0 (file:///projects/deref-example)
error[E0614]: type `MyBox<{integer}>` cannot be dereferenced
--> src/main.rs:14:19
|
14 | assert_eq!(5, *y);
| ^^
For more information about this error, try `rustc --explain E0614`.
error: could not compile `deref-example` (bin "deref-example") due to 1 previous error
```
The `MyBox<T>` type cant be dereferenced because we havn't implemented the ability to on our type.
To enable dereferencing with the `*` operator, we need to implemented the `Deref` trait.
## Treating a Type Like a Reference by Implementing the `Deref` Trait
As discussed before to implement a trait we need to provide implementations for the trait's required methods.
Here the `Deref` trait, provided by the std library, requires us to implement one method named `deref` that borrows `self` and returns a refernce to the inner data.
Here is th implementation of the `Deref` to add to the definition of `MyBox`
```rust
use std::ops::Deref;
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
```
The `type Target = T;` syntax defines an associated type for the `Deref` trait to use.
Associated types are a slightly different way of declaring a generic paramter, we will cover them later in ch20.
We fill in the body of the `deref` method with `&self.0` so `deref` returns a reference to the vbalue we want to access with the `*` operator.
Recall that using a "Tuple Struct without a Named Filed to Create Different Types" section.
We use `.0` accesses the first value in a tuple struct.
The `main` function from the example before will now compile and the assertions will pass now with thuis implementation.
Without the `Deref` trait, the compiler can only dereference `&` references.
The `deref` method gives the compiler the ability to take a value of any type that implements `Deref` and call the `deref` method to get a `&` reference that it knows how to deference.
When we write `*y`.
Behind the scenes Rust actually ran this code
```rust
*(y.deref())
```
Rust substitues the `*` operator with a call to `deref` method.
Then a plain derefence so we dont have to think about whether or not we need to call the `deref` method.
This Rust feature lets us write code that functions identically regardless of if we have a regular reference or a type that implements `Deref`
The reason that the `deref` method reutnrs a reference to a value, and that the plain dereferncee outside the parentheses in `*(y.deref())` is still necessary, is to do with the ownership system.
If the `deref` method retuned the value directly instead of a refernece to the value, the value would be moved out of `self`.
We dont want to take ownership of the inner value insid `MyBox<T>` in this case or in most cases where we use the dereference oerator.
Note: the `*` operator is replaced with a call to the `deref` method and then a call to trhe `*` operator just once.
Each time we use a `*` in our code.
Due to the substituation of the `*` operator doesn't recurse infinitely we end up with data of type `i32`.
This then matches the `5` in `assert_eq!`
## Implicit Deref Coercions iwth Functions and Methods
*Deref coercion* converts a reference to a type that implements the `Deref` trait into a reference to another type.
For example a deref coercion can convert `&String` to `&str` because `String` implemented the `Deref` trait such that it returns `&str`.
Deref coercion is a convenience that Rust perfomrs on args to functions and methods.
This only works on tpyes that implement the `Deref` trait.
It happens automatically when we pass a reference to a particular type's value as an arg to a function or method that doesn't match the parameter type in the function or method definition.
A sequence of calls to the `deref` method converts the type we provided into the type the parameter needs.
Deref coercion was added to Rust so that rogrammers writing function and method calls don't need to add as many explicit references and dereferences with `&` and `*`.
This feature also lets us write more code that can code that can work for either references or smart pointers.
To see deref coercion in action we will use `MyBox<T>` type defined previously with the implementation of `Deref` as well.
This example shows the definition of a function that has a string slice parameter
```rust
fn hello(name: &str) {
println!("Hello, {name}!");
}
```
We can call the `hello` function with a string slice as an arg.
Such as `hello("Rust");` as an example.
With Deref coercion makes it possible to call `hello` with a reference to a value of type `MyBox<String>`
Here is an example of this
```rust
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&m);
}
```
Here we call the `hello` function with the arg `&m`, which is a reference to a `MyBox<String>` value.
Due to us implementing the `Deref` trait on `MyBox<T>`, Rust can turn `&MyBox<String>` into a `&String` by calling deref.
The std library then proves an implementation of `Deref` on `String` that reutnrs a string slice.
This is in the API docs for `Deref`.
Rust then calls `deref` again to turn the `&String` into `&str`. This matches the `hello` function definition.
If Rust didn't implement deref coercion we would have to wrtie does like this instead to call `hello` with a value of type `&MyBox<String>`
```rust
fn main() {
let m = MyBox::new(String::from("Rust"));
hello(&(*m)[..]);
}
```
The `(*m)` dereferences the `MyBox<String>` into a `String`.
The `&` and `[..]` takes a string slice of the `String` that is equal to the whole string to match the signature of `hello`.
This code without deref coercions is much harder to read, wrtie and understand, escpially with all of the symbols involved.
Deref coercion allows Rusts to handle all of these conversions automatically.
When the `Deref` trait is defined for the types involved.
Rust will analyze the types and use `Deref::deref` as many times as necessary to get a reference to match the param type.
The number of times that `Deref::deref` needs to be inserted is resolved at compile time.
There is no runtime penalty for taking advantage of deref coercion.
## How Deref Coercion Interacts with Mutability
Similar to how you would use `Deref` to override the `*` operator on immutable references, you can use the `DerefMut` trait to override the `*` operator on mutable references.
Rust does deref coercion when it finds tpyes and trait implelemtations in there cases
- From `&T` to `&U` when `T: Deref<Target=U>`
- From `&mut T` to `&mut U` when `T: DerefMut<Target=U>`
- From `&mut T` to `&U` when `T: Deref<Target=U>`
The fist two cases are the same expect that the second implements mutablility.
The first one states that if you have a `&T` and `T` implements `Deref` to some type `U` you can get a `&U` transparently
The second states that the smae deref coercion happens for mutable references.
The third one is tricker.
Rust will also coerce a mutable reference to an immutable one.
The reverse is *not* possible: immutable references will never coerce to mutable refernces.
This is due to the borrowing rules, if you have a mutable reference, that mutable reference must be the only reference to that data.
(The program will not compile if otherwise)
Converting one mutable reference to one immutable reference will never break the borrowing rules.
Converting an immutable reference to a mutable reference would require that the intial immutable reference is the only immutable reference to that data.
Borrowing rukes don't gaurantee that.
Therefore Rust can't make that assumption that converting an immutable reference to a mutable reference is possible.

218
Drop Trait.md Normal file
View File

@ -0,0 +1,218 @@
# Running Code on Cleanup with the `Drop` Trait
The second trait improtant to the smart pointer pattern is `Drop`
This lets you customize what happens when a values is about to go out of scope.
You can provide an implementation for the `Drop` trait on any type and that code can be used to release resources like files or network connections.
`Drop` traits are almost always used when implementing a smart pointer but it is also useful in other cases/types.
For example when a `Box<T>` is dropped it will deallocate the space on the heap that the box points to.
In some languages the programmer must call code to free emory or resources when they finished using an instance of those types.
Some examples include file handles, sockets, or locks.
If they forget, the system might become overloaded and crash.
In Rust you can specify that a particluar bit of code that will run whenever a value gos out of scope.
The compler will insert this code automatically.
This results that you don't need to be careful about placing cleanup code everywhere in a program that an instance of a paritcular type is finished with.
You still won't leak resources.
The code that you want to run when a value goes out of scope goes in the implementation of the `Drop` trait.
The `Drop` trait requires you to implement one method named `drop` that takes a mutable refernce to `self`
to see when Rust calls `drop` we will implement `drop` with `println!` statements.
In this example it shows a `CustomSmartPoionter` struct whose only custom functionality is that it will print `Dropping CustomSmartPointer!` when the instance goes out of scope.
This is in order to show when Rust runs the `drop` function.
```rust
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
}
```
The Drop Trait is included in the prelude so we don't need to bring it into scope.
Here we implemented the `Drop` trait on `CustomSmartPointer` and provide an implementation for the `drop` method that calls `println!`.
Here the body of the `drop` function is where you would place any logic that you wanted to run when an instance of your type goes out of cope.
We print some text here to demonstrate visually when Rust will call `drop`.
In `main` we create two instances of `CustomSmartPointer` and then print `CustomSmartPointers created`
At the end of `main` when the insatnces of `CustomSmartPointer` go out of scope.
Rust will call the code we put in the `drop` method.
This printed our final message.
Notice that we didn't need to call the `drop` method explicity.
Here is the output from that code
```
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.60s
Running `target/debug/drop-example`
CustomSmartPointers created.
Dropping CustomSmartPointer with data `other stuff`!
Dropping CustomSmartPointer with data `my stuff`!
```
Rust will automatically call `drop` for us when our instances go out of scope, calling the code speicifed by `drop`.
Varialbes are dropped in the reverse order they we created.
Here it means that `d` was dropped before `c`
This examples gives a visual guide on how the `drop` method works.
Usually you would specify the cleanup oe that your type needs to run rather than a print message.
## Dropping a Valu Early with `std::mem::drop`
This is not straightforward to to disable the automatic `drop` functionality.
This is usually unnecessary to disable `drop`.
The whole point of the `Drop` trait is that it is taken care of automatically.
Very rarely you might want to clean up a value early.
One example us when using smart pointers that manage your locks.
Here you may want to force the `drop` method that releases the lock so that other code in the same scope can aquire the lock.
Rust doesnt let you call the `Drop` trait `drop` method manually.
Here you would instead call the `std::mem::drop` fnction provided by te std library if you want to force a value to be dropped before the end of a scope.
If we try to call the `drop` method manually.
In this case we would get a compiler error
```rust
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
c.drop();
println!("CustomSmartPointer dropped before the end of main.");
}
```
Here is the error output
```
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
error[E0040]: explicit use of destructor method
--> src/main.rs:16:7
|
16 | c.drop();
| ^^^^ explicit destructor calls not allowed
|
help: consider using `drop` function
|
16 | drop(c);
| +++++ ~
For more information about this error, try `rustc --explain E0040`.
error: could not compile `drop-example` (bin "drop-example") due to 1 previous error
```
This error message states that we are not allowed to explicitly call `drop`.
The error mesage uses the term *destructor*, this is a general programming term for a function that cleans up an instance.
A *destructor* is analogous to a *constructor*, this creates an instance.
The `drop` function in Rust is one particular destructor.
Rust doesn't let us call `drop` explicity because Rust would still automatically call `drop` on the value at the end of `main`.
This would cause a *double free* error because Rust would be trying to clean up the same value twice.
We can't disable this automatic insertion of `drop` when a value goes out of scope.
We also can't call the `drop` method explicitly.
If we need to force a value to be cleaned up early, then we use the `std::mem::drop` function.
The `std::mem::drop` function is different from the `drop` method in the `Drop` trait.
We call this by passing the value we want to force to drop as an argument.
Here is the updated version with the function being in the prelude.
```rust
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data `{}`!", self.data);
}
}
fn main() {
let c = CustomSmartPointer {
data: String::from("some data"),
};
println!("CustomSmartPointer created.");
drop(c);
println!("CustomSmartPointer dropped before the end of main.");
}
```
Here we get this output
```
$ cargo run
Compiling drop-example v0.1.0 (file:///projects/drop-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.73s
Running `target/debug/drop-example`
CustomSmartPointer created.
Dropping CustomSmartPointer with data `some data`!
CustomSmartPointer dropped before the end of main.
```
The tet `Dropping CustomSmartPointer with data 'some data'!` is printed between the `CustomSmartPointer created.` and `CustomSmartPointer dropped before the end of main.` text.
This indicates that the `drop` method code is called to drop `c` at that point.
You can then use the code specified in a `Drop` trait implementation in many ways to make cleanup convenient and safe.
For instance, you could use it to create your own memory allocator.
With the `Drop` trait and Rust's ownership system you dont have to remember to clean up because Rust will do it automatically.
You also dont have to worry about problems resulting from accidentally cleaning up valuess still in use.
The ownership system will ensure that references are always valid, also enusreing that `drop` gets called only once when the value is no longer being used.

8
Extending Cargo.md Normal file
View File

@ -0,0 +1,8 @@
# Extending Cargo with Custom Commnads
The design of Cargo is such that you can extend it with new subcommands without having to modify Cargo.
If a binary in your `$PATH` is named `cargo-somethig`, you can run it as if it was a Cargo subcommand by running `cargo something`.
Custom commands like this are also listed when you run `cargo --list`
Using `cargo install` to install extensions and then run them just like built-in Cargo tools is a very convenient benefit of Cargo's design.

69
For later baja.md Normal file
View File

@ -0,0 +1,69 @@
Not happy with this
Rust is a very unique language and a great guiding book.
You can learn more [here](https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html) about Rust's Documentation for publishing packages.
The goal of this is to passively train you how to produce comments and code worthy of being open source and industry level.
Due to the language's interesting module seperating when creating a large program. All members will be involved in the creation of all functions and how they should be seperated into their groups of related ideas.
First off the file tree structure will look like this example
```
src/
├── lib.rs
├── front_of_house.rs
└── front_of_house/
├── a_different_mod.rs
└── other_module_linked_in_modrs.rs
```
These are all related functions in front of house, for small modules do not make a sub directory only large or major functions should be seperated
Where *`front_of_house.rs`* is like this
```rust
//! Describes what front_of_house module provides
//! All functionality in other files this serves as a connector
//! Main idea and a run should be in this file
//! re exports go here as well
pub mod a_different_mod;
// only split if a different losely related idea is needed (the sub idea more relates to itself than to the parent)
pub mod other_module_linked_in_modrs;
```
Also where *`other_module_linked_in_modrs.rs`* looks like this
```rust
/// What the function does
///
/// ### Params
///
/// - input_var - Description of what the input should be.
/// - b - Description of the second input parameter.
///
/// ### Returns
///
/// - Description of the return value.
///
/// ### Example Usage
///
/// ```rust
/// // how a user would use this function, replace ex_crate with actual path to use function
/// // this is how a public but internal module would be used by an outside user (ex_crate needs to be changed)
/// let result = crate::front_of_house::other_module_linked_in_modrs::example_funct(5, 10);
/// assert_eq!(result, 15);
/// ```
/// ### Author (s)
///
/// - Name <semiperminant@exmaplemail.com>
/// - Another Example <different@examplemail.com>
/// semi-permanent email, do not need to respond but try to be a good alumni
pub fn example_funct(input_var: i32, b: i32) -> i32 {
// example variable can be anything not just an integer
let var_example = 0;
// example function does nothing significant
var_example + input_var + b
}
```
One all of the main modules have been decided upon a senior member or lead will be assigned to that module will then be responsible and will break the module into sub components to assign out to implement.
The team will then come other for a final time to ensure that all sub modules make sense and thier ideas make sense and are appropriately assigned out.

417
Futures and Async.md Normal file
View File

@ -0,0 +1,417 @@
# Futures and the Async Syntax
The key parts of asynchronous programming in Rust are _futures_ and Rust's `async` and `await` keywords
A _future_ or a promise is a value that may not be ready now but will become ready at some point in the future
In other languages the same concept shows up under other names such as _task_ or _promise_.
Rust provides a `Future` trait as a building block so that different async operations can be implemented with different data structures but with a common interface.
Rust futures are types that implement the `Future` trait.
Each future holds its own information about the progress that has been made and what "ready" means.
You can apply the `async` keyword to blocks and functions to specify that they can be interrupted and resumed.
Within an async block or async function, you can use the `await` keyword to _await a future_ (that is, wait for it to become ready).
Any point where you await a future within an async or function is a potential spot for that async block or function to pause and resume.
The process of checking with a future to see if its value is available yet is called _polling_.
Some other languages, such as C# and JavaScript, that also use `async` and `await` keywords for async programming.
There are some significant differences in how Rust does things, including how it handles the syntax.
When writing async Rust, we use the `async` and `await` keywords most of the time.
Rust compiles them into equivalent code using the `Future` trait, much as it compiles `for` loops into equivalent code using the `Iterator` trait.
Due to Rust providing the `Future` trait, this means that you can also implement it for your own data types you need to.
Many of the functions that we will see have return types with their own implementations of `Future`.
We will return to the definition of the trait at the end of the chapter and dig into more of how it works.
This may all feel a bit abstract so we will go into our first program: a little web scraper.
We will pass in two URLs form the command line, fetch both of them concurrently and return the result of whichever one finishes first.
This will have a fair bit of new syntax.
## Our First Async Program
To keep focus on learning async rather than juggling parts of the ecosystem, we created the `trpl` crate (this is sort for "The Rust Programming Language").
This re-exports all the types, traits, and functions you will need, primarily form the [`futures`](https://crates.io/crates/futures) and [`tokio`](https://tokio.rs/) crates.
The `futures` crate is an official home for Rust experimentation for async code, and it is where the `Future` trait was orignially designed.
Tokio is the most widely used `async` runtime in Rust today, especially for web applications.
Here we the `tokio` crate under the hood for `trpl` becuase it is well tested and widly used.
In some cases `trpl` also renames or wraps the original APIs to keep us focused on the details relevant to this chapter.
If you want to understand in depth of what the crate does, check out [its source code](https://github.com/rust-lang/book/tree/main/packages/trpl).
You will then be able to see what crate each re-export comes from, and we have left extensive comments explaining what the crate does.
First we will start by building a little command line tools that fetches two we pages, pulls the `<title>` element from each and print out the title of whichever page finishes that whole process first.
## Defining the `page_title` Function
First we will start by writing a function that takes one page URL as a parameter
```rust
extern crate trpl; // required for mdbook test
fn main() {
// TODO: we'll add this next!
}
use trpl::Html;
async fn page_title(url: &str) -> Option<String> {
let response = trpl::get(url).await;
let response_text = response.text().await;
Html::parse(&response_text)
.select_first("title")
.map(|title_element| title_element.inner_html())
}
```
Fist we define a fnction named `page_title` and mark it with the `async` keyword.
We then ise the `trpl::get` function to fetch whatever URL is passed in and add the `await` keyword to await the response.
To get the response, we call its `text` method, and once again await it with the `await` keyword.
Both of these steps are asynchronous.
For the `get` function, we have to wait for the server to send back the first part of its response. This will include HTTP header, cookies and so on, and can be delivered separately from the response body.
Especially if the body is very large, it can take some time for it all to arrive.
If we have to wait for the _entirety_ of the response to arrive, the `text` method is also aync.
Here we have to explicity await both of these future, because futures in Rust are _lazy_
Futures will not do anthing until you ask them to with the `await` keyword. (Rust will show a compiler warning if you don't use a future)
This might remind you of iterators in the section [Processing a Series of Items With Iteraors](./Iterators.md).
Iterators do nothing unless you call their `next` method whether directly or by using `for` loops or methods such as `map` that use `next` under the hood.
Likewise, futures do nothing unless you explicitly ask them to.
This laziness allows Rust ot avoid running async code until its actually needed.
This is differnt from the behavoir we say before when unsing `thread::spawn` in [Creating a New Thread with `spawn`](./Simultaneous%20Code%20Running.md#creating-a-new-thread-with-spawn), where the closure we passed to another thead started running immediately.
This is also different from how many other languages approach async.
This is improtant for Rust and we will see why later.
Once we have `response_text`, we can then parse it into an intance of the `Html` type using `Html::parse`.
Instead of a raw string, we now have a data type we can work with the HTML as a richer data structure.
In particular, we can use the `select_first` method to find the first instace of a given CSS selector.
By passing the string `"title"`, we get the first `<title>` element in the document, if there is one.
Becuase there may not be any matching element, `select_first` returns an `Option<ElementRef>`.
Lastly we use the `Option::map` method, this lets us work with the item in the `Option` if it is present and do nothing if it isn't.
We could also use a `match` expression, but `map` is more idiomatic.
In the body of the function we supply to `map`, we call `inner_html` on `title_element` to get its content, which is a `String`.
When it is all done we have an `Option<String>`
Note that Rust's `await` kword goes _after_ the expression you are awaiting, not before it.
It is a _postfix_ keyword.
This may differ from what you may have used `async` in other languages, but in Rust it makes chains of methods much nice to work with.
This results that we can change the body of `page_url_for` to chain the `trpl::get` and `text` function calls together with `await` between them.
```rust
let response_text = trpl::get(url).await.text().await;
```
With this we have successfully written our first async function.
Befor we add some code in `main` to call it. We will dive even deep into what we have written and what it means.
When Rust sees a block mared with the `async` keyword, it compiles it into a unique, anonymous data tpye that implements the `Future` trait.
When Rust sees a function marked with `async`, it compiles it not a non-async function whose body is an async block.
An async function's return type is the type of the anonymous data type the compiler creates for that async block.
Writing `async fn` is equivalent to writing a function that returns a _future_ of the return type.
To the compiler, a function definition such as the `async fn page_title` is equivalent ot a non-async function defined like this:
```rust
use std::future::Future;
use trpl::Html;
fn page_title(url: &str) -> impl Future<Output = Option<String>> + '_ {
async move {
let text = trpl::get(url).await.text().await;
Html::parse(&text)
.select_first("title")
.map(|title| title.inner_html())
}
}
```
Lets see go through each part of the transformed version:
- It uses the `impl Trait` syntax we discussed in Ch 10 in the ["Traits as Parameters"](./Traits.md#traits-as-parameters) section
- The returned trait is a `Future` with an associated type of `Output`.
- Note that the `Output` type is `Option<String>`, which is the same as the original return type from the `async fn` version of `page_title`.
- This async block produces a value with the type `Option<String>`.
- That value matches he `Output` type in the return type.
- This is just like other blocks you have seen.
- All of the code called in the body of the original function is wrapped in an `async move` block.
- Blocks are expressions.
- This whole block is the expression returned from the function.
- That value matches the Output type in the return type.
- The new function body is an `async move` block because of how it uses the `url` parameter.
- We will go into `async` versus `async move` later.
- The new version of the function has a kind of lifetime we haven't seen before in the output type: `'_`
- This is due to the function reutrns a future that refers to a reference, in this case, the reference form the `url` parameter.
- Here we need to tell Rust that we want that reference to be included.
- We don't have to name the lifetime here because Rust is smart enough to know there is only reference that could be involved, but we _do_ have to be explicit that the resulting future is bound by that lifetime.
## Determining a Single Page's Title
To start, we will just get a single page.
Here we follow the same pattern as we yused in Ch 12 to get command line arguments.
Then we pass the first pass the first URL `page_title` and await the resutl.
Due to the value produced by the future is an `Option<String>`, we use a `match` epxression to print different messages to account for whether the page has a `<title>`
```rust
extern crate trpl; // required for mdbook test
use trpl::Html;
async fn main() {
let args: Vec<String> = std::env::args().collect();
let url = &args[1];
match page_title(url).await {
Some(title) => println!("The title for {url} was {title}"),
None => println!("{url} had no title"),
}
}
async fn page_title(url: &str) -> Option<String> {
let response_text = trpl::get(url).await.text().await;
Html::parse(&response_text)
.select_first("title")
.map(|title_element| title_element.inner_html())
}
```
This will not compile.
The only place we can use the `await` keyowrd is in async functions or blocks.
Rust will not let us akr the special `main` function as `async`
We will get this error
```
error[E0752]: `main` function is not allowed to be `async`
--> src/main.rs:6:1
|
6 | async fn main() {
| ^^^^^^^^^^^^^^^ `main` function is not allowed to be `async`
```
The reason that `main` can't be marked `async` is that async code needs a *runtime*
A Rust crate that manages the details of executing asynchronous code.
A program's `main` function can *initialize* a runtime but it is not a runtime *itself*.
(We will see why this is the case in a bit)
Every Rust program that executes async has at least one place where it sets up a runtime that executes the futures.
Most languages that support async bundle a runtime, but Rust doesn't.
Instead, there are many different async runtimes available, each of which makes different tradeoffs suitable to the use case it targets.
An example fo this is a high-throughput web server with many CPU cores and a large amount of RAM has very has very differnt needs than a microcontroller with a ingle core, a samll amount of RAM, and no heap allocation ability.
The crates that provide those runtimes also often supply async versions of ocmmon functionality such as file or network I/O.
Throughout the rest of this chapter, we will use the `run` function from the `trpl` crate, which takes a futures as an argument and runs ti to completion.
Behind the scenes, calling `run` sets up a runtime that's is used to run the future passed in.
Once this completes, `run` returns whatever value the future produced.
We could have passed the future returned by `page_title` directly to `run`, and oce it compelted could match on the resulting `Option<String>` like as we did before.
However, for most of the examples in the chapter (and most async ocde in the real world), we'll be doing more than just one async function call.
Instead we will pass an `async` block and explicity await the result of the `parge_title` call.
Here is the updated version
```rust
fn main() {
let args: Vec<String> = std::env::args().collect();
trpl::run(async {
let url = &args[1];
match page_title(url).await {
Some(title) => println!("The title for {url} was {title}"),
None => println!("{url} had no title"),
}
})
}
```
Now when we run this code we get the behavior we expected initially
```
$ cargo run -- https://www.rust-lang.org
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.05s
Running `target/debug/async_await 'https://www.rust-lang.org'`
The title for https://www.rust-lang.org was
Rust Programming Language
```
Now we funally have some working async code.
Bt befoer we add the code to race the two site against each other we will breifly turn back to how futures work.
Each *await point*, every place where the code uses the `await` keyword, represents a plcae where control is handed back to the runtime.
To make this work, Rust needs to keep track of the state involved in the async block so that the runtime can kick off some other owrk and then come back when it is ready to try advancing the first one agian.
This is an invisible state machine, as if you had written an enum lie this to save the current state at each await point
```rust
enum PageTitleFuture<'a> {
Initial { url: &'a str },
GetAwaitPoint { url: &'a str },
TextAwaitPoint { response: trpl::Response },
}
```
Writing the code to transition between each state by hand would be tedious and error-prone.
However, especially when you need to add more functionality and mroe states to the code later.
The Rust compiler creates and manages the statemachine data structures for async code automatically.
The normal borrowing and ownership rules around data structurs all still apply.
The compiler also handls checking those for us and provides useful error messages.
Ultimately, something has to execute this state machine, and that something is a runtime.
(This is why you may come across references to *executors* when looking into runtimes: an executor is the part od a runtime responsible for executing the async code)
You can now see why the compiler stopped us from making `main` itself an async function back.
If `main` were an async function, something else would need to manage the state machine for whatever future `main` returned, but `main` is the starting point for the program.
Instead we call the `trpl::run` function in `main` to set up a runtime and run the future returned by the `async` block until it retunrs `Ready`.
Note: Some runtimes provide macros so you *are* able to write an async `main` function.
These macros rewrite `async fn main() { ... }` to be a normal `fn main`.
This does the same thing as we did by hand before.
Call a function that runs a future to completion the way `trpl::run` does.
Now we can put these pieces tohether and see how we can write concurrent code.
## Racing Our Two URLs Against Each Other
Here we will call `page_title` with tow different URLs passed in from th comand line and race them.
```rust
use trpl::{Either, Html};
fn main() {
let args: Vec<String> = std::env::args().collect();
trpl::run(async {
let title_fut_1 = page_title(&args[1]);
let title_fut_2 = page_title(&args[2]);
let (url, maybe_title) =
match trpl::race(title_fut_1, title_fut_2).await {
Either::Left(left) => left,
Either::Right(right) => right,
};
println!("{url} returned first");
match maybe_title {
Some(title) => println!("Its page title is: '{title}'"),
None => println!("Its title could not be parsed."),
}
})
}
async fn page_title(url: &str) -> (&str, Option<String>) {
let text = trpl::get(url).await.text().await;
let title = Html::parse(&text)
.select_first("title")
.map(|title| title.inner_html());
(url, title)
}
```
Here we start off by calling `page_title` for each of the user-supplied URLs.
We save the resulting futures as `title_fut_1` and `title_fut_2`.
Now remember these don't do anything yet, this is due to futures being lazy we haven't awaited them.
Next we pass the futures to `trpl::race`, which returns a value to indicate which of the futures passed to it finishes first.
Note that under the hood, `race` is built on a more general function, `select`, which you will encounter more often in real-world Rust code.
A `select` function can do a lot of thinfs that `trpl::race` function can't, but it also has some additional complexity that we can kip over for now.
Either future can legitimately "win", so it doesn't make sense to return a `Result`.
Instead, `race` returns a `trpl::Either`.
This `Either` type is somewhat similar to a `Result` in that it has two cases.
Unlike `Result`, there is no notion of sucess or failure baked into `Either`.
Instead it uses `Left` and `Right` to indicate "one or the other"
```rust
enum Either<A, B> {
Left(A),
Right(B),
}
```
The `race` function returns `Left` with that future's output if the first argument wins and `Right` with the second future argument's output if *that* one wins.
This matches the order the arguments appear in when callign the function: the first argument is to the left of the second argument.
We also upadte `page_title` to return the same URL passed in.
Now if the page that returns first does not have a `<title>` we can resolve, we can still print a meaninful message.
With that information available, we wrap up by aupdating our `println!` output to indicate both which URL finished first and what, if any, the `<title>` is for the web page at that URL.
Here we have built a small working web scraper.
Now you can pcik a couple URLs and run the command line tool.
Some site are consistently faster than others, while in other cases the faster site varies form run to run.
This is the basics of working with futures, so now we can dig deeper into what we can do with async.

572
Futures in Sequence.md Normal file
View File

@ -0,0 +1,572 @@
# Streams: Futures in Sequence
So far we have limited ourselves to individual features.
There has been one exception was the async channel.
The async `recv` method produces a sequence of items over time.
This is an instance of a much more general pattern known as a *stream*.
Earlier we saw a sequence of items, the `Iterator` trait, there are tow differences between iterators and the async channel receiver.
The first difference is time: iterators are synchronous, while the channel receiver is asynchronous.
The second is the API.
When working directly with `Iterator`, we call its synchronous `next` method.
With the `trpl::Receiver` stream in particular, we called an asynchronous `recv` method instead.
Otherwise, the APIs feel very similar, and this isn't similarity isn't coincidence.
A stream is like an asynchronous form of iteration.
The `trpl::Receiver` on the other side specifically waits to receive messages, the general-purpose stream API is much broader.
It provides the next item the way `Iterator` does, but asynchronously.
The similarity between iterators and streams in Rust means we can actually create a stream from any iterator.
With any iterator, we can work with a stream by calling its `next` method then awaiting the output.
Here is an example of this
```rust
let values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let iter = values.iter().map(|n| n * 2);
let mut stream = trpl::stream_from_iter(iter);
while let Some(value) = stream.next().await {
println!("The value was: {value}");
}
```
Here we start with an array of numbers, which we then convert into an iterator and then call `map` on to double all the values.
We then convert the iterator into a stream using the `trpl::stream_from_iter` function.
Next, we loop over the items in the stream as they arrive with the `while let` loop.
This does not compile but instead it reports that there is no `next` method available.
```
error[E0599]: no method named `next` found for struct `Iter` in the current scope
--> src/main.rs:10:40
|
10 | while let Some(value) = stream.next().await {
| ^^^^
|
= note: the full type name has been written to 'file:///projects/async_await/target/debug/deps/async_await-9de943556a6001b8.long-type-1281356139287206597.txt'
= note: consider using `--verbose` to print the full type name to the console
= help: items from traits can only be used if the trait is in scope
help: the following traits which provide `next` are implemented but not in scope; perhaps you want to import one of them
|
1 + use crate::trpl::StreamExt;
|
1 + use futures_util::stream::stream::StreamExt;
|
1 + use std::iter::Iterator;
|
1 + use std::str::pattern::Searcher;
|
help: there is a method `try_next` with a similar name
|
10 | while let Some(value) = stream.try_next().await {
| ~~~~~~~~
```
This output explains, the reason for the compiler error is that we need the right trait in scope to be able to use the `next` method.
You may expect that trait to be in `Stream`, but it is actually in `StreamExt`.
This is short for *extension*, `Ext` is a common pattern in the Rust community for extending one trait with another.
We will explain the `Stream` and `StreamExt` traits in a bit more detail at the end of the chapter.
For now know that the `Stream` trait defines a low-level interface that effectively combines the `Iterator` and `Future` traits.
`StreamExt` supplies a higher level set of APIs on top of `Stream`, including the `next` method as well as other utility methods similar to the ones provided by the `Iterator` trait.
`Stream` and `StreamExt` are not yet part of Rust's std library but most crates use the same definition.
The fix for this is to add a `use` statement for `trpl::StreamExt`.
```rust
extern crate trpl; // required for mdbook test
use trpl::StreamExt;
fn main() {
trpl::run(async {
let values = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let iter = values.iter().map(|n| n * 2);
let mut stream = trpl::stream_from_iter(iter);
while let Some(value) = stream.next().await {
println!("The value was: {value}");
}
});
}
```
Now with all of the pieces put together, the code works the way we want.
Now that we have `StreamExt` in scope, we can use all of its utility methods, just as with iterators.
Here is an example of this, here we use the `filter` method to filter out everything but multiples of three and five.
```rust
extern crate trpl; // required for mdbook test
use trpl::StreamExt;
fn main() {
trpl::run(async {
let values = 1..101;
let iter = values.map(|n| n * 2);
let stream = trpl::stream_from_iter(iter);
let mut filtered =
stream.filter(|value| value % 3 == 0 || value % 5 == 0);
while let Some(value) = filtered.next().await {
println!("The value was: {value}");
}
});
}
```
This isn't very interesting, since we could do the same with normal iterators and without any async at all.
Now looks look at what *is* unique to streams
## Composing Streams
Many concepts are naturally represented as streams.
Items become available in a queue, chunks of data being pulled incrementally from the filesystem when the full data set is too large for the computer's, or data arriving over the network over time.
An example of this is batching up events to avoid triggering too many network calls, set timeouts on sequences of long-running operations, or throttle user interface events to avoid doing needless work.
To start we will build a little stream of messages as a stand-in for a stream of data we might see from a WebSocket, or another real-time communication protocol.
Here is an example of this.
```rust
extern crate trpl; // required for mdbook test
use trpl::{ReceiverStream, Stream, StreamExt};
fn main() {
trpl::run(async {
let mut messages = get_messages();
while let Some(message) = messages.next().await {
println!("{message}");
}
});
}
fn get_messages() -> impl Stream<Item = String> {
let (tx, rx) = trpl::channel();
let messages = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
for message in messages {
tx.send(format!("Message: '{message}'")).unwrap();
}
ReceiverStream::new(rx)
}
```
Here we first create a function called `get_messages` that returns `impl Stream<Item = String>`.
This implementation, we create a async channel, loop over the first 10 letters of the alphabet and send them across the channel.
Now we use a new type `ReceiverStream`.
This converts the `rx` receiver from `trpl::channel` into a `Stream` with a `next` method.
In `main`, we use a `while let` loop to print all the messages form the stream.
When we run this code we get this output, as expected.
```
Message: 'a'
Message: 'b'
Message: 'c'
Message: 'd'
Message: 'e'
Message: 'f'
Message: 'g'
Message: 'h'
Message: 'i'
Message: 'j'
```
We could have done this with the regular `Receiver` API or even the regular `Iterator` API so lets add a feature that requires streams.
Adding a timeout that applies to every item in the stream, and a delay on the items we emit.
This is shown here
```rust
extern crate trpl; // required for mdbook test
use std::{pin::pin, time::Duration};
use trpl::{ReceiverStream, Stream, StreamExt};
fn main() {
trpl::run(async {
let mut messages =
pin!(get_messages().timeout(Duration::from_millis(200)));
while let Some(result) = messages.next().await {
match result {
Ok(message) => println!("{message}"),
Err(reason) => eprintln!("Problem: {reason:?}"),
}
}
})
}
fn get_messages() -> impl Stream<Item = String> {
let (tx, rx) = trpl::channel();
let messages = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
for message in messages {
tx.send(format!("Message: '{message}'")).unwrap();
}
ReceiverStream::new(rx)
}
```
Here we add a timeout to the stream with the `timeout` method.
This comes form the `StreamExt` trait.
Next we update the body of the `while let` loop, because the stream now returns a `Result`.
The `Ok` variant indicates a message arrived in time.
The `Err` variant indicates that the timeout elapsed before any message arrived.
We `match` this result and either print the message we receive it successfully or print a notice about the timeout.
Notice that we pin the messages after applying the timeout to them, because the timeout helper produces a stream that needs to be pinned to be polled.
Because there are no delays between messages, the timeout does not change the behavior of the program.
Now lets add a variable delay to the messages we send
```rust
extern crate trpl; // required for mdbook test
use std::{pin::pin, time::Duration};
use trpl::{ReceiverStream, Stream, StreamExt};
fn main() {
trpl::run(async {
let mut messages =
pin!(get_messages().timeout(Duration::from_millis(200)));
while let Some(result) = messages.next().await {
match result {
Ok(message) => println!("{message}"),
Err(reason) => eprintln!("Problem: {reason:?}"),
}
}
})
}
fn get_messages() -> impl Stream<Item = String> {
let (tx, rx) = trpl::channel();
trpl::spawn_task(async move {
let messages = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
for (index, message) in messages.into_iter().enumerate() {
let time_to_sleep = if index % 2 == 0 { 100 } else { 300 };
trpl::sleep(Duration::from_millis(time_to_sleep)).await;
tx.send(format!("Message: '{message}'")).unwrap();
}
});
ReceiverStream::new(rx)
}
```
In `get_messages` we use the `enumerate` iterator method with the `messages` array.
This is so that we can get the index of each item we are sending along with the item itself.
Next we apply a 100-millisecond delay to even-index items and a 300-millisecond delay to odd-index items to simulate the different days we may see from a stream of messages in the real world.
Because our timeout is for 200 milliseconds, this should affect half of the messages.
To sleep between messages in the `get_messages` function without blocking, we need to use async.
However, we cant make `get_messages` itself into an async function, because then we would return a `Future<Output = Stream<Item = String>>` instead of a `Stream<Item = String>>`/
The caller would need to await `get_messages` itself to get access to the stream.
Remember everything in a given future happens linearly; concurrency happens *between* futures.
Awaiting `get_messages` would require it to send all the messages, including the sleep delay between each message, before returning the receiver stream
This would make the timeout useless.
There would be no delays in the stream itself; they would happen before the stream was even available.
instead, we leave `get_messages` as a regular function that returns a stream, and we spawn a task to handle the async `sleep` calls.
Note that calling `spawn_task` in this way works because we already set up our runtime.
If we had not it would cause a panic.
Other implementations choose different tradeoffs.
They may spawn a new runtime and avoid the panic but end up with a but of extra overhead, or they may simply not provide a standalone way to spawn tasks without reference to a runtime.
Make sure you know what tradeoff you runtime has chosen and write your code accordingly.
This makes our code have a much more interesting result.
Between every other pair of messages, a `Problem:: Elapsed(())` error.
```
Message: 'a'
Problem: Elapsed(())
Message: 'b'
Message: 'c'
Problem: Elapsed(())
Message: 'd'
Message: 'e'
Problem: Elapsed(())
Message: 'f'
Message: 'g'
Problem: Elapsed(())
Message: 'h'
Message: 'i'
Problem: Elapsed(())
Message: 'j'
```
The timeout doesn't prevent the messages form arriving in the end.
We still get all of the original messages, because our channel is *unbounded*.
It can hold as messages as we can fit in memory.
If the message doesn't arrive before the timeout, our stream handler will account for that, but when it polls the stream again, the message many now have arrived.
You can get different behavior if needed by using other kinds of channels or other kinds of streams more generally.
Lets see this by combining a stream of time intervals with this stream of messages.
## Merging Streams
We will start by creating another stream, this will emit and item every millisecond if we let it run directly.
For simplicity we will use the `sleep` function to send a message on a delay and combine it with the same approach we used in `get_messages` of creating a stream from a channel.
The difference is that we are going to send back the count of intervals that have happened.
This means the return type will be `impl Stream<Item = u32>`, and we can call the function `get_intervals`
```rust
fn get_intervals() -> impl Stream<Item = u32> {
let (tx, rx) = trpl::channel();
trpl::spawn_task(async move {
let mut count = 0;
loop {
trpl::sleep(Duration::from_millis(1)).await;
count += 1;
tx.send(count).unwrap();
}
});
ReceiverStream::new(rx)
}
```
Here we start by defining a `count` in the task.
We could have defined it outside of the task, but it is clearer to limit the scope of any given variable.
Then we create an infinite loop.
Each iteration of the loop asynchronously sleeps for one millisecond, increments the count, and then sends it over the channel.
This is all wrapped in the task created by `spawn_task`, all of it including the infinite loop will get cleaned up with the runtime.
This kind of infinite loop, ends only when the whole runtime gets torn down.
This is a fairly common in async Rust: many programs needs to keep running indefinitely.
With async, this doesn't block anything else, as long as there is at least one await point in each iteration through the loop.
Back in our main function's async block, we can attempt to merge the `messages` and `intervals` streams
```rust
let messages = get_messages().timeout(Duration::from_millis(200));
let intervals = get_intervals();
let merged = messages.merge(intervals);
```
We start by calling `get_intervals`.
We then merge the `messages` and `intervals` streams with the `merge` method, which combines multiple streams into one stream that produces items from any of the source streams as soon as the items are available, without any particular ordering.
Finally, we loop over that combined stream instead of over `messages`.
At this point neither `messages` nor `intervals` need to be pinned or mutable, this is because both will be combined into the single `merged` stream.
This call to `merge` doesn't compile.
(Neither does the `next` call in the `wile let` loop, but we will come back to that).
This is because the two steams have different types.
The `messages` stream has the type `Timeout< impl Stream<Item = String>>`, where `Timeout` is the type that implements `Stream` for a `timeout` call.
The `intervals` stream has the type `impl Stream<Item = u32>`.
In order to merge these tow streams, we need to transform one of them to match the other.
We will rework the intervals stream, this is because messages is already in the basic format we want and has to handle timeout errors.
```rust
let messages = get_messages().timeout(Duration::from_millis(200));
let intervals = get_intervals()
.map(|count| format!("Interval: {count}"))
.timeout(Duration::from_secs(10));
let merged = messages.merge(intervals);
let mut stream = pin!(merged);
```
Here we will use the `map` helper method to transform `intervals` into a string.
Next we need to match the `Timeout` from `messages`
Due us not actually *want* a timeout for `intervals`, we can just create a timeout which is longer than the other durations that we are using.
Specifically we create a 10-second timeout with `Duration::from_sec(10)`
Lastly we need to make `stream` mutable, so that the `while let` loop's `next` calls can iterate through the stream and pin it so that it is safe to do so.
This gets us *almost* to where we need to be.
Everything type checks.
If you now run this there will be two problems.
It will never stop. (You need to stop it manually with ctrl-c).
The messages from the English alphabet will be buried in the midst of all the interval counter messages.
Here is a sample of the output
```
--snip--
Interval: 38
Interval: 39
Interval: 40
Message: 'a'
Interval: 41
Interval: 42
Interval: 43
--snip--
```
This is one of the ways to solve these last two problems
```rust
let messages = get_messages().timeout(Duration::from_millis(200));
let intervals = get_intervals()
.map(|count| format!("Interval: {count}"))
.throttle(Duration::from_millis(100))
.timeout(Duration::from_secs(10));
let merged = messages.merge(intervals).take(20);
let mut stream = pin!(merged);
```
Here we use `throttle` method on the `intervals` stream so that it doesn't overwhelm the `messages` stream.
*Throttling* is a way of limiting the rate at which a function will be called.
In this case, how often the stream will be polled.
Here it is once every 100 milliseconds should do, because this is roughly how often our messages arrive.
To limit the number of times we accept form a stream, we will apply the `take` method to the `merged` stream.
Because we want to limit the final output, and not just one stream or the other.
Now when we run it.
It stops after pulling 20 items form the stream and the intervals don't overwhelm the messages.
We also don't `Interval: 100` or `Interval: 200` or etc...
Instead we get `Interval: 1`, `Interval 2`, etc...
Even though we have a source stream that *can* produce an event every millisecond.
This is because the `throttle` call produces a new stream that wraps the original stream so that the original stream gets polled only at the throttle rate., and not its own "native" rate.
We also won't have a bunch of unhandled interval messages we are choose to ignore.
Instead we never produce those interval messages in the first place.
This is the inherent "laziness" of Rust's futures at work again.
This allows us to choose our performance characteristics.
```
Interval: 1
Message: 'a'
Interval: 2
Interval: 3
Problem: Elapsed(())
Interval: 4
Message: 'b'
Interval: 5
Message: 'c'
Interval: 6
Interval: 7
Problem: Elapsed(())
Interval: 8
Message: 'd'
Interval: 9
Message: 'e'
Interval: 10
Interval: 11
Problem: Elapsed(())
Interval: 12
```
The last thing is that we need to handle is errors.
With both of these channel-based streams, the `send` calls could fail when the other side of the channel closes and that is just a matter of how the runtime executes the futures that make up the stream.
Up until now, we have ignored this possibility by calling `unwrap`.
In a well behaved app, we should explicitly handle the error at minimum by ending the loop so we don't try to send any more messages.
Here is a simple error handling strategy; print the issue and then `break` form the loops
```rust
fn get_messages() -> impl Stream<Item = String> {
let (tx, rx) = trpl::channel();
trpl::spawn_task(async move {
let messages = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"];
for (index, message) in messages.into_iter().enumerate() {
let time_to_sleep = if index % 2 == 0 { 100 } else { 300 };
trpl::sleep(Duration::from_millis(time_to_sleep)).await;
if let Err(send_error) = tx.send(format!("Message: '{message}'")) {
eprintln!("Cannot send message '{message}': {send_error}");
break;
}
}
});
ReceiverStream::new(rx)
}
fn get_intervals() -> impl Stream<Item = u32> {
let (tx, rx) = trpl::channel();
trpl::spawn_task(async move {
let mut count = 0;
loop {
trpl::sleep(Duration::from_millis(1)).await;
count += 1;
if let Err(send_error) = tx.send(count) {
eprintln!("Could not send interval {count}: {send_error}");
break;
};
}
});
ReceiverStream::new(rx)
}
```
The correct way to handle a message send error will vary.
Just ensure you have a strategy.

View File

@ -0,0 +1,157 @@
# Putting It All Together: Futures, Tasks and Threads
As we saw [here](./Concurrency.md), threads provide one approach to concurrency.
Another approach was using async with futures and streams.
If you were wondering when to choose one over the other.
The answer is that it depends, and in many cases, the choice isn't threads *or* async but rather threads *and* async.
Many OS have supplied threading-based concurrency models for decades now, and many programming results support them as a result.
These models are not without their own tradeoffs.
On many OSes, they use a fair bit of memory, and they come with some overhead for starting up and shutting down.
Threads are also only an option when your OS and hardware support them.
Unlike a modern desktop and mobile computer, some embedded systems don't have an OS at all, so they also don't have threads.
The async model provides a different and complementary set of tradeoffs.
In the async model, concurrent operations don't require their own threads.
Instead, they can run on tasks (just like when we used `trpl::spawn_task`)m this kicks off work form a synchronous function in the streams section.
A task is similar to a thread, instead of being managed by the OS, it is managed by library-level code: the runtime
Previously, we saw that we could build a stream by using async channel and spawning an async task we could call from synchronous code.
We then can do this exact same thing with a thread.
Before we used `trpl::spawn_task` and `trpl::sleep`.
Here we replaced those with the `thread::spawn` and `thread::sleep` APIs from the std library in the `get_intervals` function.
```rust
fn get_intervals() -> impl Stream<Item = u32> {
let (tx, rx) = trpl::channel();
// This is *not* `trpl::spawn` but `std::thread::spawn`!
thread::spawn(move || {
let mut count = 0;
loop {
// Likewise, this is *not* `trpl::sleep` but `std::thread::sleep`!
thread::sleep(Duration::from_millis(1));
count += 1;
if let Err(send_error) = tx.send(count) {
eprintln!("Could not send interval {count}: {send_error}");
break;
};
}
});
ReceiverStream::new(rx)
}
```
If you run this code it will produce an identical output as the one before.
And notice how little changes here from the perspective of calling code.
What is more even though one of our functions spawned an async task on the runtime and the other spawned an OS thread.
The resulting streams were unaffected by the differences.
Despite their similarities, these two behave very differently, although we might have a hard time measuring it in this very simple example.
Alternatively we could spawn millions of async tasks on any modern personal computer.
If we tried to do that with threads, we would literally run out of memory.
There is a reason that these APIs are so similar.
Threads act as a boundary for sets of synchronous operations; concurrency is possible *between* threads.
Tasks act as a boundary for sets of *asynchronous* operations.
Concurrency is possible both *between* and *within* tasks, because a task can switch between futures in its body.
Finally, futures are Rust's most granular unit of concurrency, and each future may represent a tree of other futures.
The runtime (specifically, its executor) manages tasks and tasks manage futures.
In this regard, tasks are similar to lightweight, runtime-managed threads with added capabilities that come from being managed by a runtime instead of by the operating system.
This doesn't mean that async tasks are always better than threads (or vice versa).
Concurrency with threads is in some ways a simpler programming model than concurrency with `async`.
This can be either a strength or a weakness.
Threads are somewhat "fire and forget".
They have no native equivalent to a future, so they simply run to completion without being interrupted except by the OS itself.
That is they have no built-in support for *intratask concurrency* the way futures do.
Threads in Rust also have no mechanisms for cancellation (we haven't covered explicitly in this ch but was implied by the fact that whenever we ended a future, tis state got cleaned up correctly).
The limitations also make threads harder to compose than futures.
This is much more difficult.
For example, to use threads to build helpers such as the `timeout` and `throttle` methods that we built earlier.
The fact that futures are richer data structures means they can be composed together more naturally as we have seen.
Tasks, give us *additional* control over futures, allowing us to choose where and how to group them.
It turns out that threads and tasks often work very well together, because tasks (in some runtimes) can be moved around between threads.
In fact, under the hood, the runtime we have been using including the `spawn_blocking` and `spawn_task` functions is multithreaded by default.
Many runtimes use an approach called *work stealing* to transparently move tasks around between threads.
Based on how the threads are currently being utilized, to improve the system's overall performance.
This approach actually requires threads *and* tasks and therefore futures.
When thinking about which method to use when, consider these rules of thumb:
- If the work is *very parallelizable*, such as processing a bunch of data where each part cab be processed separately, threads are a better choice.
- If the work is *very concurrent*, such as handling message from a bunch of different sources that many come in at different intervals or different rates, async is a better choice.
If you need both concurrency and parallelism, you don't have to choose between threads and async.
You can use them together freely, letting each one play the part it is best at.
An example of this, below, shows a fairly common example of this kind of mix in real-world Rust code.
```rust
use std::{thread, time::Duration};
fn main() {
let (tx, mut rx) = trpl::channel();
thread::spawn(move || {
for i in 1..11 {
tx.send(i).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
trpl::run(async {
while let Some(message) = rx.recv().await {
println!("{message}");
}
});
}
```
Here we being by creating an async channel, then spawn a thread that takes ownership of the sender side of the channel.
Within the thread, we send the numbers 1-10, sleeping for a second between each.
Finally, we run a future created with an async block passed to `trpl::run` just as we have throughout the chapter.
In this future, we await those messages, just as in the other message-passing examples we have seen.
Returning to the scenario we opened the chapter with, imagine running a set of video encoding tasks using a dedicated thread (because video encoding is compute-bound) but notifying the UI that those operations are dont with an async channel.
There are countless examples of these kinds of combinations in real-world use cases.

View File

@ -0,0 +1,704 @@
# Implementing an Object-Oriented Design Pattern
The *state pattern* is an object-oriented design pattern.
The crux of the pattern is that we define a set of states a value can have internally.
The states are represented by a set of *state objects* and the value's behavior changes based on its state.
We are going to work through an example of a blog post struct that has aa filed to hold its state, this will be a state object form the set "draft", "review", or "published".
The sate objects share functionality. In Rust we use structs and traits rather than objects and inheritance.
Each state object is responsible for its own behavior and for governing when it should change into another state.
The value that holds a state object knows nothing about the different behavior of the states or when to transition between states.
The advantage of using this is that when the business requirements of the program change, we won't need to change the code of the value holding the state or the code that uses the value.
We will only need to update the code inside one of the state objects to change its rules or perhaps add more state objects.
We are going to implement the state pattern in a more tradition object-oriented way.
Next we will use an approach that is a bit more natural in Rust.
Lets start with incrementally implementing a blog post workflow using the state pattern.
The final functionality will look like this:
1. A blog post starts as an empty draft
2. When the draft is complete, a review of the post is requested
3. When the post is approved, it will be published
4. Only published blog posts return content to print, so unapproved posts can't be accidentally be published
Any other changes attempted on a post should have no effect.
An example of this is if we try to approve a draft blog post before we have requested a review, the post should remain an unpublished draft.
In this example, it shows the workflow in code form.
This is an example usage of the API, we will implement in a library crate named `blog`.
This will not compile yet because we haven't implemented the `blog` crate.
```rust
use blog::Post;
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
assert_eq!("", post.content());
post.request_review();
assert_eq!("", post.content());
post.approve();
assert_eq!("I ate a salad for lunch today", post.content());
}
```
We want to allow the user to create a new draft blog post with `Post::new`.
We also want to allow text to be added to be blog post.
If we try to get the post's content immediately, before approval, we shouldn't get any text because the post is still a draft.
We added `assert_eq!` for demonstration purposes.
An excellent unit test for this would be to assert that a draft post returns an empty string from the `content` method, but we are not going to write tests for this example.
Next, we want to enable a request for a review of the post and we want `content` to return an empty string while waiting for the review.
Then when the post receives approval, it should get published, meaning the text of the post will be returned when `content` is called.
Note that the only type we are interacting with from the crate s the Post type.
This type will use the state pattern and will hold a value that will be one of three state objects representing the various states a post can be in, draft, waiting for review or published.
Changing from one state change in response to the methods called by our library users on the `Post` instance.
They don't have to manage the state changes directly.
Users can't make a mistake with the states, like publishing a post before it is reviewed.
## Defining `Post` and Creating a New Instance in the Draft State
First we need a public `Post` struct that holds some content.
so we will start with the definition of the struct and the associated public `new` function to create an instance of `Post`.
This is shown below.
We will also make a private `State` trait that will define the behavior that all state objects for a `Post` must have.
`Post` will hold a trait object of `Box<dyn State>` inside an `Option<T>` in a private field named `state` to hold the state object.
You will see why the `Option<T>` is necessary.
```rust
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
}
trait State {}
struct Draft {}
impl State for Draft {}
```
The `State` trait defines the behavior shared by different post states.
The state objects are `Draft`, `PendingReview` and `Published`, and they will all implement the `State` trait.
For now the trait doesn't have any methods.
We will start by defining just the `Draft` state because that is the state we want a post to start in.
When we create a new `Post`, we set its `state` field to a `Some` value that holds a `Box`.
This `Box` points to aa new instance of the `Draft` struct.
This ensures whenever we create a new instance of `Post`, it will start out as a draft.
Due to the state field of `Post` being private, there is no way to create a `Psot` in any other state.
In the `Post::new` function, we set the `content` field to a new empty `String`.
## Storing the Text of the Post Content
Previously we saw that we wanted to be able to call a method named `add_test` and pass it a `&str` that is then added as the text content of the blog post.
We implemented this as a method, rather than exposing the `content` field as `pub`, so that later we can implement a method that will control how the `content` field's data is read.
The `add_text` method is fairly straightforward, so lets add the implementation below to the `impl Post` block.
```rust
impl Post {
// --snip--
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
}
```
The `add_text` method takes a mutable reference to `self`.
Because we changed the `Post` instance that we are calling `add_text` on.
We then can call `push_str` on the `String` in `content` and pass the `text` argument to add to the saved `content`.
This behavior doesn't depend on the state the post is in, so it is not part of the state pattern.
The `add_text` method doesn't interact with the `state` field at all, but it is part of the behavior we want to support.
## Ensuring the Content of a Draft Post Is Empty
Even after we called `add_text` and added some content to our post, we still want the `content` method to return an empty string slice because the post is still in the draft state.
For now we will implement the `content` method with the simplest thing that will fulfill this requirement.
Always returning an empty string slice.
We will change this late once we implement the ability to change a post's state so that it can be published.
Posts so far can only be in the draft state., so the post content should always be empty.
Here is a placeholder implementation:
```rust
impl Post {
// --snip--
pub fn content(&self) -> &str {
""
}
}
```
## Requesting a Review of the Post Changes Its State
Next we need to add functionality to request a review of a post, which should change its state from `Draft` to `PendingReview`
Here is the code that shows this
```rust
impl Post {
// --snip--
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
}
struct PendingReview {}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
}
```
Here `request_review` is a public method on the `Post` struct, this will take a mutable reference to `self`.
Then we call an internal `request_review` method on the current state of `Post`.
The second `request_review` method consumes the current state and returns a new state.
We add the `request_review` method to the `State` trait.
Now all types that implement the trait will now need to implement the `request_review` method.
Note, rather than having `self`, `&self` or `&mut self` as the first parameter of the method, we have `self: Box<Self>`.
This syntax means the method is only valid when called on a `Box` holding the type.
This syntax takes ownership of `Box<Self>`, invalidating the old state so the state value of the `Post` can transform into a new state.
In order to consume the old state, the `request_review` method needs to take ownership of the state value.
This is where the `Option` in the `state` filed of `Post` comes in.
We call the `take` method to take the `Some` value out of the `state` field and leave a `None` in its place, because Rust not allowing us to have unpopulated fields in structs.
This lets us move the `state` value out of `Post` rather than borrowing it.
Then we will set the post's `state` value to the result of this operation.
We need to set `state` to `None` temporarily rather than setting it directly with something like `self.state = self.state.request_review();` to get ownership of the `state` value.
This ensures that `Post` can't use the old `state` value after we transformed it into a new state.
The `request_review` method on `Draft` returns a new boxed instance of a new `PendingReview` struct.
This represents the state when a post is waiting for a review.
The `PendingReview` struct also implements the `request_review` method but doesn't do any transformations.
It instead returns itself, because when we request a review on a post already in the `PendingReview` state, it should stay in the `PendingReview` state.
Now the advantages of the state pattern are staring to be seen: the `request_review` method on `Post` is the same no matter its `state` value.
Each state is responsible for its own rules.
We leave the `content` method on `Post` as is, returning an empty string slice.
We can now have a `Post` in the `PendingReview` state as well as in the `Draft` state, but we want the same behavior in the `PendingReview` state.
## Adding `approve` to Change the Behavior of `content`
The `approve` method will be similar to the `request_review` method.
It will set `state` to the value that the current state says it should have when that state is approved.
Here is the new code
```rust
impl Post {
// --snip--
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
}
trait State {
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
}
struct Draft {}
impl State for Draft {
// --snip--
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
struct PendingReview {}
impl State for PendingReview {
// --snip--
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(Published {})
}
}
struct Published {}
impl State for Published {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
```
Here we added the `spprove` method to the `State` trait and add a new struct that implements `State`, the `Published` state.
Similar to how `request_review` on `PendingReview` works, if we call the `approve` method on a `Draft`, it will have no effect because `approve` will return `self`.
When we call `approve` on `PendingReview`, it returns a new boxed instance of the `Published` struct.
The `Published` struct implements the `State` trait, and for both the `request_review` method and the `approve` method, it returns itself, because the post should stay in the `Published` state in those cases.
We now need a way to update the `content` method on `Post`.
We want the value returned from `content` to depend on the current state of `Post`, so we are going to have the `Post` delegate to `cotnent` method defined on its `state`.
Here is the code for this
```rust
impl Post {
// --snip--
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
// --snip--
}
```
The goal is to keep all the rules inside the structs that implement `State`.
We call a `content` method on the value in `state` and pass the post instance (that is `self`) as an argument.
Then we return the value that is returned from using the `content` method on the `state` value.
As we call the `as_ref` method on the `Option` because we want a reference to the value inside the `Option` rather than ownership of the value.
Because `state` is an `Option<Box<dyn State>>`, when we call `as_ref`, an `Option<&Box<dyn State>>` is returned.
If we didn't call `as_ref`, we would get an error because we can't move `state` out of the borrowed `&self` of the function parameter.
Then we call the `unwrap` method, we know this will never panic.
We know the methods on `Post` ensure that `state` will always contain a `Some` value when those methods are done.
This is a case where we have more information than the compiler (previously discussed in [Ch 9](./Error%20Handling.md#cases-in-which-you-have-more-info-than-the-compiler)) when we know that a `None` value is never possible, even though the compiler isn't able to understand that.
Now at this point, when we call `content` on the `&Box<dyn State>`, deref coercion will take effect on the `&` and the `Box` so the `content` method will ultimately be called on the type that implements the `State` trait.
This means we need to add `content` to the `State` trait definition, and that is where we will put the logic for what content to return depending on which state we have.
Here is that addition
```rust
trait State {
// --snip--
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
// --snip--
struct Published {}
impl State for Published {
// --snip--
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
}
```
Here we added a default implementation for the `content` method that returns an empty string slice.
This means we don't need to implement `cotent` on the `Draft` and `PendingReview` structs.
The `Published` struct will override the `content` method and return the value in `post.content`.
Note that we need a lifetime annotation on this method.
Here we are taking a reference to a `post` as an argument and returning a reference to part of that `post`, so the lifetime of the returned reference is related to the lifetime of the `post` argument.
We have finally implemented the state pattern with the rules of the blog post workflow.
The logic related to the rules lives in the state objects rather than being scattered throughout `Post`.
Final Code:
```rust
pub struct Post {
state: Option<Box<dyn State>>,
content: String,
}
impl Post {
pub fn new() -> Post {
Post {
state: Some(Box::new(Draft {})),
content: String::new(),
}
}
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
pub fn content(&self) -> &str {
self.state.as_ref().unwrap().content(self)
}
pub fn request_review(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.request_review())
}
}
pub fn approve(&mut self) {
if let Some(s) = self.state.take() {
self.state = Some(s.approve())
}
}
}
trait State {
// --snip--
fn request_review(self: Box<Self>) -> Box<dyn State>;
fn approve(self: Box<Self>) -> Box<dyn State>;
fn content<'a>(&self, post: &'a Post) -> &'a str {
""
}
}
// --snip--
struct Draft {}
impl State for Draft {
fn request_review(self: Box<Self>) -> Box<dyn State> {
Box::new(PendingReview {})
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
}
struct PendingReview {}
impl State for PendingReview {
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
Box::new(Published {})
}
}
struct Published {}
impl State for Published {
// --snip--
fn request_review(self: Box<Self>) -> Box<dyn State> {
self
}
fn approve(self: Box<Self>) -> Box<dyn State> {
self
}
fn content<'a>(&self, post: &'a Post) -> &'a str {
&post.content
}
}
```
### Why Not An Enum?
You may wonder why we didn't use an `enum` with the different possible post states as variants.
This is a possible solution, you have to try it and compare the end results to see which is preferred.
One disadvantage of using an enum is every place that checks the value of the enum will need a `match` expression or similar to handle every possible variant.
This could get more repetitive than this trait object solution.
## Trade-offs of the State Pattern
Here we have shown that Rust is capable of implementing the object-oriented state pattern to encapsulate the different kinds of behavior a post should have in each state.
The methods on `Post` know nothing about the various behaviors.
The way in which code is organized, we have to look only in one place to know the different ways a published post can behave: the implementation of the `State` trait on the `Published` struct.
If we were to create an alternative implementation that didn't use the state pattern, we might instead use `match` expression in the `Post` or even in the `main` code.
This would check for the state of the post and changes behavior ion those places.
That means we would have to look in several places to understand all the implications of a post being in the published state.
This would only increase the more states we added: each of those `match` expressions would need another arm.
With the state pattern, the `Post` methods and the places we use `Post` don't need `match` expressions and to add a new state.
We would only need to add a new struct and implement the trait methods on that one struct.
The implementation using the state pattern is easy to extend to add more functionality.
To highlight the simplicity of maintaining code that uses the state pattern, try a few of these suggestions:
- Add a `reject` method that changes the post's state from `PendingReview` back to `Draft`.
- Require two calls to approve before the state can be changed to `Published`.
- Allow users to add text content only when a post is in the `Draft` state.
- Hint: have the state object responsible for what might change about the content but not responsible for modifying the `Post`.
One downside of the state pattern is that, because the states implement the transitions between states, some of the states are coupled to each other.
If we add another state between `PendingReview` and `Published`, such as `Scheduled`, we would have to change the code in `PendingReview` to transitioned to `Scheduled` instead.
It would be less work if `PendingReview` didn't need to change with the addition of a new state, but that would mean switching to another design pattern.
Another downside is that we have dupliced some logic.
In order to eliminate some of the duplication, we may try to make default implementations for the `request_review` and `approve` methods on the `State` trait that return `self`
However, this would not be dyn compatible.
This is because the trait doesn't know what the concrete `self` will be exactly.
We want to be able to use `State` as a trait object so we need its methods to be dyn compatible.
Other duplication includes the similar implementations of the `request_review` and `approve` methods on `Post`.
Both methods delegate to the implementation of the same method on the value in the `state` field of `Option` and set the new value of the `state` field to the result.
If we had a lot of methods on `Post` that followed this pattern, we may consider defining a macro to eliminate the repetition (This will be discussed in Ch20).
By implementing the state pattern exactly as it is defined for object-oriented languages, we are not taking full advantage of Rust's strengths as we could.
Now lets look at some changes to make the `blog` crate that can make invalid states and transitions into compile time errors.
## Encoding States and Behavior as Types
We will show how you can rethink the state pattern to get a different set of trade-offs.
Rather than encapsulating the states and transitions completely so outside code has no knowledge of them, we will encode the states into different types.
Rust's type checking system will prevent attempts to use draft posts where only published posts are allowed by issuing a compiler error.
Lets consider this first part of `main` from before
```rust
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
assert_eq!("", post.content());
}
```
We still need to enable the creation of new posts in the draft state using `Post::new` and the ability to add text to the post's content.
Instead of having a `content` method on a draft post that returns an empty string, we will make it so draft posts don't have the `content` method at all.
This way if we try to get a draft post's content, we will get a compiler error telling us the method doesn't exist.
This results in being impossible for us to accidentally display draft post content in production, because that code won't even compile.
Here is the definition of a `Post` struct and a `DraftPost` struct as well as methods on each.
```rust
pub struct Post {
content: String,
}
pub struct DraftPost {
content: String,
}
impl Post {
pub fn new() -> DraftPost {
DraftPost {
content: String::new(),
}
}
pub fn content(&self) -> &str {
&self.content
}
}
impl DraftPost {
pub fn add_text(&mut self, text: &str) {
self.content.push_str(text);
}
}
```
Both the `Post` and `DraftPost` structs have a private `content` field that stores the blog post text.
The structs no longer have the `state` field because we are moving the encoding of that state to the types of structs.
The `Post` struct will represent a published post, and it has a `content` method that returns the `content`.
We still have a `Post::new` function, but instead of returning an instance of `Post`, it returns an instance of `DraftPost`.
Due to `content` being private and there aren't any functions that return `Post`, it is not possible to create an instance of `Post` right now.
The `DraftPost` struct has an `add_text`method, so we can add text to `content` as before.
Note that `DraftPost` does not have a `content` method defined.
So now the program ensures all posts start as draft posts, and draft posts don't have their content available for display.
Any attempt to get around these constraints will result in a compiler error.
## Implementing Transitions as Transformations into Different Types
How do we get a published post?
We want to enforce the rule that a draft post has to be reviewed and approved before it can be published.
A post in the pending review state should still not display any content.
We will implement these constraints by adding another struct, `PendingReviewPost`.
We will define the `request_review` method on `DraftPost` to return a `PendingReviewPost`.
Finally we will define an `approve` method on `PendingReviewPost` to return a `Post`.
Here is the code implementation.
```rust
impl DraftPost {
// --snip--
pub fn request_review(self) -> PendingReviewPost {
PendingReviewPost {
content: self.content,
}
}
}
pub struct PendingReviewPost {
content: String,
}
impl PendingReviewPost {
pub fn approve(self) -> Post {
Post {
content: self.content,
}
}
}
```
Here the `request_review` and `approve` methods take ownership of `self`.
This thus consumes the `DraftPost` and `PendingReviewPost` instances and transforming them into a `PendingReviewPost` and a published `Post`.
This way we will not have any lingering `DraftPost` instances after we called `request_review` on them and so on.
The `PendingReviewPost` struct also doesn't have a `content` method defined on it.
Again attempting to read its content results in a compiler error.
Because the only way to get a published `Post` instance that does have a `content` method defined is to call the `approve` method on a `PendingReviewPost`, and the only way to get a `PendingReviewPost` is to call the `request_review` method on a `DraftPost`.
Now we have encoded the blog post workflow into the type system.
We also have to make some changes to `main`.
The `reequest_review` and `approve`methods return new instances rather than modifying the struct they are called on.
We need to add more `let post =` shadowing assignments to save the returned instances.
We also can't have assertions about the draft and pending review posts' contents being empty strings, nor do we need them.
We are unable to compile any code that tires to use the content of posts in those states any longer.
Here is the updated code in `main`
```rust
use blog::Post;
fn main() {
let mut post = Post::new();
post.add_text("I ate a salad for lunch today");
let post = post.request_review();
let post = post.approve();
assert_eq!("I ate a salad for lunch today", post.content());
}
```
The changes we need to make to `main` to reassign `post` mean that this implementation doesn't quite follow the object oriented state pattern anymore.
The transformations between the states are no longer encapsulated entirely within the `Post` implementation.
However our gain is that invalid states are now impossible because of the type system and the type checking that happens at compile time.
This enforces that certain bugs, such as display of the content of an unpublished post, will be discovered before they make it production.
Try the tasks suggested before on the `blog` crate as it is after to see what you think about the design of this version of the code.
Note that some of the tasks might be completed already in this design.
We have seen that even though Rust is capable of implementing object-oriented design patterns, other patterns such as encoding state into the type system, are also available in Rust.
These patterns have different trade0ffs.
While you may be very familiar with object-oriented patterns, rethinking the problem to take advantage of Rust's features can provide benefits, such as preventing some bugs due to certain features, like ownership, that object-oriented languages don't have.

212
Improving The IO Project.md Normal file
View File

@ -0,0 +1,212 @@
# Improving the I/O Project
Using this new info about iterators we can improve the minigrep project by using iterators to make places in the code clearer and more concise
Lets see how iterators can improve our implementation of the `Config::build` function and the `search` function
## Removing a `clone` Using an Iterator
In before, we added code that took a slice of `String` values and created an instance of the `Config` struct by indexing into the slice and cloning the values, allowing the `Config` struct to own those values.
Here we have reporduced the implementation fo te `Config::build` function as it was at the end of ch12
```rust
impl Config {
pub fn build(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments");
}
let query = args[1].clone();
let file_path = args[2].clone();
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
file_path,
ignore_case,
})
}
}
```
Before we said to not worry about the inefficient `clone` calls because we would remove them later.
Now we will fix that
We needed `clone` here because we have a slice with `String` elements in the parameter `args`, but the `build` function doesn't own `args`
To return ownership of a `Config` instance we has to clone the values from the `query` and `file_path` fields of `Config` so the `Config` instance can own its values.
Now with iterators we can chang the `build` function to take ownership of an iterator as its argument instad of borrowing a slice.
We will use the iterator functionality instead of the code that checks the length of the slice and indexes into specific locations.
This will clarify wat the `Config::build` function is doing because the iterator will access the values.
Once `Config::build` takes ownership of the iterator and stops using indexing operations that borrow.
We can then move the `String` values from the iterator into `Config` rather than calling `clone` and making a new allocation
### Using the Returned Iterator Directly
The main.rs should look like this
```rust
fn main() {
let args: Vec<String> = env::args().collect();
let config = Config::build(&args).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});
// --snip--
}
```
First we will change the start of `main` to use an iterator instead.
This won't compile until we update `Config::build` as well
```rust
fn main() {
let config = Config::build(env::args()).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});
// --snip--
}
```
The `env::args` fnction reutrns an iterator.
Rather than collecting the iterator values into a vector then passing that and then passing a slice to `Config::build`
Instead we pass ownership of the iterator returned from `env::args` to `Config::build` directly.
Now we need to update the definition of `Config::build`.
Here is how we update the signature of `Config::build`.
Note this still wont compile because we need to update the function body.
```rust
impl Config {
pub fn build(
mut args: impl Iterator<Item = String>,
) -> Result<Config, &'static str> {
// --snip--
```
The std library documentation for the `env::args` function sohws that the type of the iterator it returns is `std::env::Args` and that type implements the `Iterator` trait and returns `String` values.
Now we updated the `Config::build` signature so the paramter `args` has a generic type wioth the trait bounds `impl Iterator<Item = String>` instead of `&[String]`
This useage of the `impl Trait` syntax was discuess in the [Traits and Paramters](./Traits.md#traits-as-parameters).
This means that `args` can be any type that implements the `Iterator` trait and returns `String`
Because we take ownership of `args`, then we well will be mutating `args` by iterating over it.
We add the `mut` keyword into the sepcification of the `argsg` paramter to ensure it is mutable
### Using `Iterator` Trait Methods Instead of Indexing
Now we will fix the body of `Config::build`
Due to how `args` implements the `Iterator` trait, we know we can call the `next` method on it
Here is the update body
```rust
impl Config {
pub fn build(
mut args: impl Iterator<Item = String>,
) -> Result<Config, &'static str> {
args.next();
let query = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a query string"),
};
let file_path = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a file path"),
};
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config {
query,
file_path,
ignore_case,
})
}
}
```
Remember that the first value in the return value of `env::args` is the name of the program
We want to ignore that, we first call `next` and do nothing with the return value to consume it from the iterator.
Next we call `net` to get the value we want to put in the `query field` of `Config`
If `next` returns a `Some`, we use a `match` to extract the value.
If it returns `None`, it means not enough arguments were given and we return early with an `Err` value.
We do the same thing for the `file_path` value.
## Making Code Clearer with Iterator Adapters
We can also take advantage of iterators in the `search` function in the I/O project.
Here is the old version of the `search` function
```rust
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
results.push(line);
}
}
results
}
```
To rewrite this code in a more concise way by using adapter methods.
This helps us avoid having a mutable intermediate `results` vector.
The functional programming style prefers to minimize the amount of mutable state to make code clearer.
Removing the mutable state might enable a future enhancement to make searching happen in parallel, because we wouldn't have to manage concurrent access to the `results` vector
Here is the new change
```rust
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}
```
The purpose of the `search` function is to return all lines in `contents` that contain the `query`.
Similar to the filter example form before, this code uses the `filter` adapter to keep only the lines that `line.contains(query)` returns `true`.
We collect the matching lines into another vector with `collect`.
This is much simpler.
You can also make the change to use iterator methods in `search_case_insensitive` function as well.
## Choosing Between Loops or Iterators
The next question is which sytle you should choose in your own code and why
The original implementation of minigrep verses using iterators.
Most Rust programmers prefer to use the iterator style.
It is a bit tougher to get the hand of at first, once you get the feel for the various iterator adaptor and what they do.
Iterators can be easier to understand.
Instead of fiddling with various bits of looping and building new vectors, the code focuses on high-level objective of the loop.
This abraction takes away some of the commonplace code so it is easier to see the concepts that are unique to this code, such as the filtering condition each element in the iteraor must pass.
You may think that the low level low will be but lets talk about performance [here](./The%20Performance%20Closures%20and%20Iterators.md).

45
Install Binaries.md Normal file
View File

@ -0,0 +1,45 @@
# Installing Binaries with `cargo install`
This is a commnad that allows you to install and use binary crates locally.
This is not a replacement for system packages.
It should be instead intended to be a convenient way for Rust devs to install tools that others have shared on [crates.io](https://crates.io)
Note that you can only install packages that have binary targets
A *binary target* is the runnable program that is created if the crate has a *src/main.rs* file or anthoer file specified as a binary.
This is unlike a binary target that isnt unnable on its own but is suitable for including within other programs.
Usucally crates have information in the *README* file about whether a crate is a library, has a binary target, or both.
All binaries installed with `cargo install` are saved in the installation root's *bin* folder.
If you installed Rust using *rustup.rs* and dont have any custom configs.
This file would be *$HOME/.cargo/bin*.
To be able to run programs you installed with `cargo install`, you must ensure that this directory is in your `$PATH`
For example to install `ripgrep` (Rust's implementation of the `grep` tool) which searches files.
To install this run the following
```
$ cargo install ripgrep
Updating crates.io index
Downloaded ripgrep v13.0.0
Downloaded 1 crate (243.3 KB) in 0.88s
Installing ripgrep v13.0.0
--snip--
Compiling ripgrep v13.0.0
Finished `release` profile [optimized + debuginfo] target(s) in 10.64s
Installing ~/.cargo/bin/rg
Installed package `ripgrep v13.0.0` (executable `rg`)
```
The second last line of shows the location and the name of the installed binary.
In the case of `ripgrep` is `rg`.
As long as the install directory is in the `$PATH`, you can then run `rg --help`.
Then you can start using a faster, rustier tool for searching files!

View File

@ -11,10 +11,21 @@ It will discuss some features of Rust that are similar to features in many langu
It will cover:
- [*Closures*](./Closures.md) - a function-like construct you can store in a variable
- *Iterators* - a way of processing a series of elements
- How to use colsure and iterators to improve the I/O project (minigrep)
- The preformance of closures and iterators (Spoiler alert: they are faster than you might think!)
- [*Iterators*](./Iterators.md) - a way of processing a series of elements
- How to use colsure and iterators to [improve the I/O project (minigrep)](./Improving%20The%20IO%20Project.md)
- [The preformance of closures and iterators](./The%20Performance%20Closures%20and%20Iterators.md) (Spoiler alert: they are faster than you might think!)
We have already covered some other Rust freatures, such as pattern matchin and enums, that are also influenced by the functional style.
Mastering closures and iterators is an improtant part of wiritng idiomatic, fast Rust code.
Mastering closures and iterators is an improtant part of wiritng idiomatic, fast Rust code.
## Summary
Closures and iterators are Rust features inspired by functional programming language ideas.
They contribute to the capability to express high-level ideas at low-level preformance.
The implementations of closures and iterators are such that runtime performance is not affected.
This is part of Rust's goal to strive to provide zero-cost abstractions.

275
Iterators.md Normal file
View File

@ -0,0 +1,275 @@
# Processing a Series of Items with Iterators
Iterator patterns allow you to perform some task on a sequence of items in turn.
An iterator is responsibl for the logic of iterating over each item and determining when the sequence has finished.
When you use iterators, you don't have to reimplement that logic yourself again.
Rust's iterators are *lasy*, meaning they have no effect until yo call methods that consume the iterator to use it up
In this example the code creates an iterator over the items in the vecotr `v1` by calling the `iter` method defined on `Vec<T>`
This code does nothing useful.
```rust
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
```
The iterator is stored in the `v1_iter` variable.
Once an iterator is created, we can use it in a variety of ways.
Before we iterator over an array using a `for` loop to execute some code on each of its items.
Under the hood this implicitly created and then consumed an iterator, but we glossed over how exactly that works until now.
In this example, we separate the creation of the iterator from the use of the iterator in the `for` loop.
When the `for` loop is called using th iterator in `v1_iter`, each element in the iterator is used in one iteration of the loop which prints out each value.
```rust
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
for val in v1_iter {
println!("Got: {val}");
}
```
In languages that don't have iterators provided by their std libraries, you would likely wirte this same functionality by starting at index 0.
Using that variable to index into th vector to get a value and incrememting the variable in a loop until it reached the total number of items in the vector.
Iterators handle all that logic for you, removing repetitive code that you could mess up.
Iterators gives mroe flexibility to use the same logic with many different kinds of sequences, not just data structs you can index into (vectors for example).
## The `Iterator` Trait and the `next` Method
All iterators implement a trait named `Iterator` that is defined in the std library
The defintion of the `Iterator` trait looks like this:
```rust
pub trait Iterator {
type Item;
fn next(&mut self) -> Option<Self::Item>;
// methods with default implementations elided
}
```
Note this definition uses some new syntax, `type Item` and `Self::Item`, which are defining an *associated type* with this trait
Associated types will be discussed in ch20 (Advanced Features)
For now know that this code says implementing the `Iterator` trait requires you also defined an `Item` type.
This `Item` type is usd in the return in the return type of the `next` method.
The `Item` tpye ill be the type returned form the iterator.
The `Iterator` trait only requires implmentors to define one method; `next` method which returns one item of the iterator at a time wrapped in `Some` and when the iteration is over, returns `None`.
We can call the `next` method on iterators directly
This example demonstrates what values are returned from repeated calls to `next` on the iterator created from the vector.
```rust
#[test]
fn iterator_demonstration() {
let v1 = vec![1, 2, 3];
let mut v1_iter = v1.iter();
assert_eq!(v1_iter.next(), Some(&1));
assert_eq!(v1_iter.next(), Some(&2));
assert_eq!(v1_iter.next(), Some(&3));
assert_eq!(v1_iter.next(), None);
}
```
Notice that we need to make `v1_iter` mutable.
Calling the `next` method on an iterator changes internal state that the iterator uses to keep track of where it is in the sequence.
It could also be said that the code *consumes*, or uses up, the iterator.
Each call to `next` comsumes an item form the iterator.
We didn't need to make `v1_iter` mutable when we used a `for` loop because the loop took ownership of `v1_iter` and made it mutable under the hood.
Note as well the values that we get from the `next` are immutable reference to the values in the vector.
The `iter` mthod produces an iterator over immutable references.
If we want to create an iterator that takes ownership of `v1` and returns owned values, we can call `into_iter`.
If you want to iterate over mutalbe references, you can call `iter_mut`
## Methods that Consume the Iterator
The `Iterator` trait has a number of different methods with default implementations provided by the std library.
You can find out about these by looking the std library API documentation for the `Iterator` trait.
Some these methods call the `next` method in their definition, which is why you are required to implement the `Iterator` trait.
Methods that call `next` are called *consuming adapters*, becaise calling them uses up the iterator.
One example is the `sum` metod which takes ownership of the iterator and iterates through the items by repeatedly calling `next` thus consuming the iterator.
As it iterates through it adds each item to a running total, this comsumes the iterator.
When it is complete it return the total
Here is a test illustrating a use of the `sum` method
```rust
#[test]
fn iterator_sum() {
let v1 = vec![1, 2, 3];
let v1_iter = v1.iter();
let total: i32 = v1_iter.sum();
assert_eq!(total, 6);
}
```
We aren't allowed to use `v1_iter` after the call to `sum because it takes ownership of the iterator we call it on.
## Methods that Produce Other Iterators
*Iterator adapters* are methods defined on the `Iterator` trait that don't consume the iterator.
Instead, they produce different iterators by changing some aspect of the original iterator.
This example shows calling an iterator adapter method `map`, which takes a closure to call on each item as the items are iterated through.
The `map` method returns a new iterator that produces the modified items.
The closure here creates a new iterator in which each item from the vector will be incremeted by 1
```rust
let v1: Vec<i32> = vec![1, 2, 3];
v1.iter().map(|x| x + 1);
```
But this code produces a warning
```
$ cargo run
Compiling iterators v0.1.0 (file:///projects/iterators)
warning: unused `Map` that must be used
--> src/main.rs:4:5
|
4 | v1.iter().map(|x| x + 1);
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: iterators are lazy and do nothing unless consumed
= note: `#[warn(unused_must_use)]` on by default
help: use `let _ = ...` to ignore the resulting value
|
4 | let _ = v1.iter().map(|x| x + 1);
| +++++++
warning: `iterators` (bin "iterators") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.47s
Running `target/debug/iterators`
```
This doesnt do anything. The closure we sepcified never gets called. The warning reminds us why: iterator adapters are lazy and we need to consume the iterator here.
To fix this warning and consume the iterator, we will use the `collect` method, which we used in Ch 12 with `env::args`.
This method consumes the iterator and collects the resulting values into a collection data type.
In this next example we collect the results of the iterating over the iterator that is returned form the call to `map` into a vector.
This vector will end up containing each item form the original vector incremeted by 1.
```rust
let v1: Vec<i32> = vec![1, 2, 3];
let v2: Vec<_> = v1.iter().map(|x| x + 1).collect();
assert_eq!(v2, vec![2, 3, 4]);
```
Because `map` takes a closure, we can specify any operation we want to perform on each item.
This is a good eample of how closures let you do custome behavior while reusing the iteration behavior that the `Iterator` trait provides.
You can chain mutliple calls to iterator adapters to perform compex action is a readable way.
Due to all iterators being lasy, you have to call one of the consuming adapter methods to get results ffrom calls to iterator adapters.
## Using Closures that Capture Their Environment
Many iterator adapters take closures as args and commonly the closures we will specify as ags to iterator adapters will be closures that capture their environment.
In this example we use the `filter` method that takes a closure.
The closure get an item form the iterator and returns a `bool`
If the closure returns `true`, the value will be included in the iteration produced by `filter`.
If the closure returns `false`, the value won't be included.
Here we use `filer` with a closure that captures the `shoe_size` variable from its environment to iterate over a collection of `Shoe` struct instances.
It will return only shoes that are the specified size.
```rust
#[derive(PartialEq, Debug)]
struct Shoe {
size: u32,
style: String,
}
fn shoes_in_size(shoes: Vec<Shoe>, shoe_size: u32) -> Vec<Shoe> {
shoes.into_iter().filter(|s| s.size == shoe_size).collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn filters_by_size() {
let shoes = vec![
Shoe {
size: 10,
style: String::from("sneaker"),
},
Shoe {
size: 13,
style: String::from("sandal"),
},
Shoe {
size: 10,
style: String::from("boot"),
},
];
let in_my_size = shoes_in_size(shoes, 10);
assert_eq!(
in_my_size,
vec![
Shoe {
size: 10,
style: String::from("sneaker")
},
Shoe {
size: 10,
style: String::from("boot")
},
]
);
}
}
```
The `shoes_in_size` function takes ownership of a vector of shoes and a shoe size parameters.
It returns a vector containing only shoes of the specified size.
In the body of `shoes_in_size` we call `into_iter` to create an iterator that takes ownership of the vector.
We then call `filter` to adapt that iterator into a new iterator that only contains elements for which the closure returns `true`.
The closure captures the `shoe_size` parameter from the environment and compares the value with each shoe's size, keeping only shoes of the size specified.
Calling `collect` finally gathers the values returned by the adapted iterator into a vector that is returned by the function.
This test shows that when we call `shoes_in_size`, we get back only shoes that have the same size as te value specified.

390
Leaky Reference Cycles.md Normal file
View File

@ -0,0 +1,390 @@
# Reference Cycles Can Leak Memory
It is not impossible but difficult to accidentally create memory that is never cleaned up (known as a *memory leak*). This is despite Rust's memory safety guarantees.
Preventing memory leaks is entirely is not one of Rust's guarantees.
This means that memory leaks are memory safe in Rust.
Rusts allows for memory leaks by using `Rc<T>` and `RefCell<T>`.
These two make it possible to create references where items refer to each other other in aa cycle.
This will create a memory leak because the reference count of e4ach item in the cycle will never get to 0 and the values will not be dropped.
## Creating a Reference Cycle
Lets look into how a reference cycle could happen and how to prevent it.
We will start with the definition of the `List` enum and a `tail` method.
```rust
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
enum List {
Cons(i32, RefCell<Rc<List>>),
Nil,
}
impl List {
fn tail(&self) -> Option<&RefCell<Rc<List>>> {
match self {
Cons(_, item) => Some(item),
Nil => None,
}
}
}
fn main() {}
```
Here the second element in the `Cons` variant is now `RefCell<Rc<List>>` means that instead of having the ability to modify the `i32` value as we did before.
We instead want to modify the `List` value a `Cons` variant is pointing to.
Here we also add a `tail` method to make it convenient for us to access the second item if we have a `Cons` variant.
In the next example we add to `main` function's body.
This code create a list in `a` and a list in `b` that points to the list in `a`
It then modifies the list in `a` to point to `b`, this creates a reference cycle.
We show what is happening via `println!` statements to show what the reference count is at various points in the process.
```rust
fn main() {
let a = Rc::new(Cons(5, RefCell::new(Rc::new(Nil))));
println!("a initial rc count = {}", Rc::strong_count(&a));
println!("a next item = {:?}", a.tail());
let b = Rc::new(Cons(10, RefCell::new(Rc::clone(&a))));
println!("a rc count after b creation = {}", Rc::strong_count(&a));
println!("b initial rc count = {}", Rc::strong_count(&b));
println!("b next item = {:?}", b.tail());
if let Some(link) = a.tail() {
*link.borrow_mut() = Rc::clone(&b);
}
println!("b rc count after changing a = {}", Rc::strong_count(&b));
println!("a rc count after changing a = {}", Rc::strong_count(&a));
// Uncomment the next line to see that we have a cycle;
// it will overflow the stack
// println!("a next item = {:?}", a.tail());
}
```
Here we create a `Rc<List>` instance holding a `List` value in the variable `a` with an initial list of `5, Nil`.
Next we create another `Rc<List>` instance holding another `List` value in the variable `b` that contains the value 10 and points to the list in `a`.
We then modify `a` so that it points a `b` instead of `Nil`.
This creates a reference cycle.
We do this by using the `tail` method to get a reference to the `RefCell<Rc<List>>` in `a` which we put in the variable `link`.
Then we use the `borrow_mut` method on the `RefCell<Rc<LIST>>` to change the value inside form a `Rc<List>` that holds a `Nil` value to the `Rc<List>` in `b`.
When we run this, while keeping the last `println!` commented out for the moment, we get this output
```
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.53s
Running `target/debug/cons-list`
a initial rc count = 1
a next item = Some(RefCell { value: Nil })
a rc count after b creation = 2
b initial rc count = 1
b next item = Some(RefCell { value: Cons(5, RefCell { value: Nil }) })
b rc count after changing a = 2
a rc count after changing a = 2
```
We can see the reference count of the `Rc<List>` instances in both `a` and `b` are 2 after we change the list in `a` to point to `b`.
At the end of `main` Rust will drop the variable `b`, this decreases the reference count of the `b` `Rc<List>` instance from 2 to 1.
The memory of that `Rc<List>` has on heap won't be dropped at this point because the reference count is still not 0, it is 1 currently.
Next Rust drops `a`, this also decreases the reference count from the `a` `Rc<List>` instance from 2 to 1.
This instance's memory cant be dropped either because of the reference form the other `Rc<List>` instance still referes to it.
This memory allocated to the list will remain uncollected forever.
Here is a visual aid to show this.
<img src="https://doc.rust-lang.org/book/img/trpl15-04.svg" />
If you now uncomment the last `println!` and run the program.
Rust will try to print this cycle with `a` pointing to `a` and so forth until it overflows the stack.
Compared to a real-world program, the consequences of creating a reference cycle in this example aren't very dire.
Right after we create the reference cycle, the program ends.
If this were a more complex program allocating lots of memory in a cycle and held onto it for a long time, the program will use more memory than it needs and might overwhelm the system, causing it to run out of available memory.
If you have `RefCell<T>` values that contain `Rc<T>` values or similar nested combinations of types with interior mutability and reference counting, you must ensure that you don't create these cycles.
You are unable to rely on Rust to catch them.
Creating a reference cycle would be a logic bug in your program that you should use automated tests, code reviews and other software development practices to minimize.
Another solution for avoiding this is reorganizing your data structs so that some references express ownership and some references don't.
This results in you can have cycles made up of some ownership relationships and some non-ownership relationships, and only the ownership relationships affect whether or not a value can be dropped.
In the previous example we always want `Cons` variants to own their list, so reorganizing the data struct isn't possible.
Now we will look at an example using graphs made up of parent nodes and child nodes to see when non-ownership relationships are an appropriate way to prevent reference cycles.
## Preventing Reference Cycles: Turning a `Rc<T>` into a `Weak<T>`
So far we have demonstrated that calling `Rc::clone` increases the `strong_count` of a `Rc<T>` instance, and a `Rc<T>` instance is only cleaned up if its `strong_count` is 0.
You can also create a *weak reference* to the value within a `Rc<T>` instance by calling `Rc::downgrade` and passing a reference to the `Rc<T>`.
Strong references don't express an ownership relationship.
Weak references don't express an ownership relationship, and their count doesn't affect when a `Rc<T>` instance is cleaned up.
They will no cause a reference cycle because any cycle involving weak references will be broken once the strong reference count of values involved is 0.
When you call `Rc::downgrade`, you get a smart point of type `Weak<T>`.
Instead of increasing the `strong_count` in the `Rc<T>` by 1, using `Rc::downgrade` increases the weak count by `1`.
The `Rc<T>` type uses `weak_count` to keep track of how many `Weak<T>` references exist, this is similar to `strong_count`.
The differences is that `weak_count` doesn't need to be 0 for the `Rc<T>` instance to be cleaned up.
Due to the value that `Weak<T>` references could be referred to might have been dropped, to do anything with a value that a `Weak` is pointing to, you must ensure that the value will still exist.
You can do this by calling the `upgrade` method on a `Weak<T>` instance, this will return an `Option<Rc<T>>`.
You will get a result of `Some` if the `Rc<T>` value has not been dropped yet and a results of `None` if the `Rc<T>` value has been dropped.
Due to `upgrade` returning an `Option<Rc<T>>`, Rust will ensure that the `Some` case and the `None` cases are handled and there will no be an invalid pointer.
Next we will show an example where rather than using a list whose items know only about the next item, we will create a tree whose items know about their children items *and* their parent items.
### Creating a Tree Data Structure a Node with Child Nodes
We will start with building a tree with nodes that know about their child nodes.
We will create a struct called `Node` that holds its own `i32` value as well as references to its children `Node` values.
```rust
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Node {
value: i32,
children: RefCell<Vec<Rc<Node>>>,
}
```
Here we want a `Node` to own its children, and we want to share that ownership with variables so we can access each `Node` in the tree directly.
We do this by defining the `Vec<T>` items to be values of type `Rc<Node>`.
We also want to be able to modify which nodes are children of another node.
Now we have a `RefCell<T>` in children around the `Vec<Rc<Node>>`.
Next we will use the struct definition and create one `Node` instance named `leaf` with the value 3 and no children and another instance named `branch` with the vale 5 and `leaf` as one of its children.
```rust
fn main() {
let leaf = Rc::new(Node {
value: 3,
children: RefCell::new(vec![]),
});
let branch = Rc::new(Node {
value: 5,
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
}
```
Here we clone the `Rc<Node>` in `leaf` and store that in `branch`, meaning the `Node` in `leaf` now has two owners.
These are `leaf` and `branch`.
We can get from `branch` to `leaf` through `branch.children`.
There is no way to get from `leaf` to `branch`.
The reason that `leaf` has no reference to `branch` and doesn't know they are related.
The reason that `leaf` has no reference to `branch` is that it doesn't know they are related.
We want `leaf` to know that `branch` is its parent.
### Adding a Reference form a `child` to Its Parent
To make the child node aware of the relationship to its parent, we need to add a `parent` field to our `Node` struct definition.
The trouble is in deciding what the type of `parent` should be.
We know that it cannot contain a `Rc<T>`, because that would create a reference cycle with `leaf.parent` pointing to `branch` and `branch.children` pointing to `leaf`.
This would cause their `strong_count` values to never be 0.
Thinking about the relationships another way, a parent node should own its children.
If a parent node is dropped, then its child nodes should be dropped as well.
A child should not own its parent.
If a child node, the parent should still exist.
We should use weak references in this case.
So we instead of `Rc<T>` we will make the type of `parent` use `Weak<T>`.
Specifically a `RefCell<Weak<Node>>`. Now the `Node` definition will look like this.
```rust
use std::cell::RefCell;
use std::rc::{Rc, Weak};
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Weak<Node>>,
children: RefCell<Vec<Rc<Node>>>,
}
```
Now a node will be able to refer to its parent node but doesn't own its parent.
In the next example we will update `main` to use this new definition so the `leaf` node will have a way to refer to its parent `branch`.
```rust
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
}
```
Creating the `leaf` node is similar to the example above with the exception of the `parent` field.
`leaf` starts out without a parent, so we create a new , empty `Weak<node>` reference instance.
At this point when we try to get a reference to the parent of `leaf` by using the `upgrade` method, we get a `None` value.
We will see this in the output from the first `println!` statement.
```
leaf parent = None
```
Here when we create the `branch` node, it will also have a new `Weak<Node>` reference in the `parent` field, this is because the `branch` doesn't have a parent node.
We will still have `leaf` as one of the children of `branch`.
Once we have the `Node` instance in `branch`, we can modify `leaf` to give it a `Weak<Node>` reference to its parent.
We will use the `borrow_mut` method on the `RefCell<Weak<Node>>` in the `parent` field of `leaf`.
Then we use the `Rc::downgrade` function to create a `Weak<Node>` reference to `branch` form the `Rc<Node>` in `branch`.
When we then print the parent of `leaf` again, this time we will get a `Some` variant holding `branch`
Now `leaf` will know the relationship to the parent and will have access to its parent.
When we print `leaf`, we need to avoid the cycle that eventually end in a stack overflow, like what we had before.
The `Weak<Node>` references are printed as `(Weak)`
```
leaf parent = Some(Node { value: 5, parent: RefCell { value: (Weak) },
children: RefCell { value: [Node { value: 3, parent: RefCell { value: (Weak) },
children: RefCell { value: [] } }] } })
```
Th lack of infinite output indicates that this code didn't create a reference cycle.
We can also tell this by looking at the values we get form calling `Rc::strong_count` and `Rc::weak_count`.
### Visualizing Changes to `strong_count` and `weak_count`
Now we will look at how the `strong_count` and `weak_count` values of the `Rc<Node>` instances change by creating a new inner scope and moving the creation of `branch` into that scope`.
Doing this we can then see what happens when `branch` and then dropped when it goes out of scope.
Here we can see the modifications to `main`
```rust
fn main() {
let leaf = Rc::new(Node {
value: 3,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![]),
});
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
{
let branch = Rc::new(Node {
value: 5,
parent: RefCell::new(Weak::new()),
children: RefCell::new(vec![Rc::clone(&leaf)]),
});
*leaf.parent.borrow_mut() = Rc::downgrade(&branch);
println!(
"branch strong = {}, weak = {}",
Rc::strong_count(&branch),
Rc::weak_count(&branch),
);
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
println!("leaf parent = {:?}", leaf.parent.borrow().upgrade());
println!(
"leaf strong = {}, weak = {}",
Rc::strong_count(&leaf),
Rc::weak_count(&leaf),
);
}
```
Now after creating `leaf` is created its `Rc<Node>` has a strong count of 1 and a weak count of 0.
In the inner scope we create `branch` and associate it with `leaf`, at which point when we print the counts, the `Rc<Node>` in `branch` will have a strong count of 1 and a weak count of 1.
For `leaf.parent` pointing to `branch` with a `Weak<Node>`.
When we print the counts in `leaf` we will see it have a strong count of 2, because `branch` now has a clone of the `Rc<Node>` of `leaf` stored in `branch.children`, built will still have a weak count of 0.
When the inner scope ends, `branch` goes out of scope and the strong count of the `Rc<node>` decreases to 0. The `Node` will be dropped.
The weak count of 1 form `leaf.parent` has no bearing on whether or not `Node` is dropped, so now we will not het any memory leaks.
Now if we try to access the parent of `leaf` after the inner scope we will get `None` again.
At the end of the program the `Rc<Node>` in `leaf` has a strong count of 1 and a weak count of 0.
This is because the variable `leaf` is now the only reference to the `Rc<Node>`.
All of this logic manages the counts and value dropping is built into `Rc<T>` and `Weak<T>` and their implementations of the `Drop` trait.
By specifying that the relationship form a child to its parent should be a `Weak<T>` reference in the definition of `Node`.
You are able to have parent nodes point to child nodes and vice versa without creating a reference cycle and memory leaks.

502
Macros.md Normal file
View File

@ -0,0 +1,502 @@
# Macros
The term *macro* refers to a family of features in Rust: *declarative* macros with `macro_rules!` and three kinds of *procedural* macros:
- Custom `#[derive]` macros that specify code added with the `derive` attribute used on structs and enums.
- Attribute-like macros that define custom attributes usable on any item
- Function-like macros that look like function calls but operate on the tokens specified as their argument
Each will be discussed, but let's first look at why we even need macros when we already have functions.
## The Difference Between Macros and Functions
Fundamentally macros are a way of writing code that writes other code, which is known as *metaprogramming*.
In Appendix C, we discuss the `derive` attribute, which generates an implementation of various traits for you.
All of these macros *expand* to produce more code than the code you have written manually.
Metaprogramming is useful for reducing the amount of code you have to write and maintain, which is also one of the roles of functions.
Macros have some additional powers that functions don't have.
A function signature must declare the number and type of parameters the function has.
Macros can take a variable number of parameters.
To show this: we can call `println!("hello")` with one argument or `println!("hello {}", name)` with two arguments.
Macros are also expanded before the compiler interprets the meaning of the code, so a macro can.
For example, implement a trait on a give type.
A function cannot, because it gets called at runtime and a trait needs to be implemented at compile time.
The downside to implementing a macro instead of a function is that macro definition are more complex than function definitions because you are writing Rust code that writes Rust code.
This indirection of macro definitions are generally more difficult to read, understand and maintain than function definitions.
Another important difference between macros and functions is that you must define macros or bring them into scope *before* you call them in a file.
This is opposed to functions where you can define anywhere and call anywhere.
## Declarative Macros with `macro_rules!` for General Metaprogramming
The most widely used form of macros in Rust is the *declarative macro*.
These are sometimes also referred to as "macros by example," *"`macro rules` macros"* or just plain "macros."
At their core, declarative macros allow you to write something similar to a Rust `match` expression.
`match` expressions are control structures that take an expression, compare the resulting value of the expression to patterns, and then run the code associated with the matching pattern.
Macros also compare a value to patterns that are associated with particular code.
In this situation, the value is the literal Rust source code passed to the macro, the patterns are compared with the structure of that source code and the code associated with each pattern, when matched, replaces the code passed to the macro.
This happens during compilation.
In order to define a macro, you use the `macro_rules!` construct.
Now lets explore how to use `macro_rules!` by looking at how the `vec!` macro is defined.
Ch8 covered how we can use the `vec!` macro to create a new vector with particular values.
For example, the following macro creates a new vector containing three integers:
```rust
let v: Vec<u32> = vec![1, 2, 3];
```
We could also use the `vec!` macro to make a vector of two integers or a vector of five string slices.
We wouldn't be able to use a function to do the same because we wouldn't know the number or type values up front.
Here shows a slightly simplified definition of the `vec!` macro.
```rust
#[macro_export]
macro_rules! vec {
( $( $x:expr ),* ) => {
{
let mut temp_vec = Vec::new();
$(
temp_vec.push($x);
)*
temp_vec
}
};
}
```
Note: The actual definition of the `vec!` macro in std library includes code to preallocate the correct amount of memory up front.
That code is an optimization that we don't include here to make the example simpler.
The `#[macro_export]` annotation indicates that this macro should be made available whenever the crate in which the macro is defined is brought into scope.
We then start the macro definition with `macro_rules!` and the name of the macro we are defining *without* the exclamation mark.
Then name here `vec` is followed by curly brackets denoting the body of the macro definition.
The structure in the `vec!` body is similar to the structure of a `match` expression.
Here we have one arm with the pattern `( $( $x:expr ),* )`, followed by `=>` and the block of code associated with this pattern.
If the pattern matches, the associated block of code will be emitted.
Given this is the only pattern in this macro, there is only one valid way to match; any other pattern will result in an error.
More complex macros will have more than one arm.
Valid pattern syntax in macro definitions is different than the pattern syntax covered in Ch19.
This is because macro patterns are matched against Rust code structure rather than values.
Now lets go over what the pattern pieces in the previous examples mean.
The full macro pattern syntax can be seen in the [Rust Reference](https://doc.rust-lang.org/reference/macros-by-example.html).
First, we use a set of parentheses to encompass the whole pattern.
We use a dollar sign (`$`) to declare a variable in the macro system that will contain the Rust code matching the pattern.
The dollar sign makes it clear this a macro variable as opposed to a regular Rust variable.
Next comes a set of parentheses that captures values that match the pattern within the parentheses for use in the replacement code.
Within `$()` is `$x: expr`, this matches any Rust expression and gives the expression the name `$x`.
The comma following `$()` indicates that a literal comma separator character must appear between each instance of the code that matches the code within `$()`.
The `*` specifies that the pattern matches zero or more of whatever precedes the `*`.
When we call this macro with `vec![1, 2, 3];`, the `$x` pattern matches three times with the three expressions `1`, `2`, and `3`.
Now lets look at the pattern in the body of the code associated with this arm: `temp_vec.push()` within `$()*` is generated for each part that matches `$()` in the pattern zero or more times depending on how many times the pattern matches.
The `$x` is replaced with each expression matched.
When we call this macro with `vec![1, 2, 3];` the code generated that replaces this macro call will be this:
```rust
{
let mut temp_vec = Vec::new();
temp_vec.push(1);
temp_vec.push(2);
temp_vec.push(3);
temp_vec
}
```
Here we dined a macro that can take any number of arguments of any type and can generate code to create a vector containing the specified elements.
To learn more about how to write macros, read online documentation or other resources like ["The Little Book of Rust Macros"](https://veykril.github.io/tlborm/) started by Daniel Keep and continued by Lukas Wirth.
## Procedural Macros for Generating Code from Attributes
The second form of macros is the *procedural macro*, which acts more like a function (and is a type of procedure).
Procedural macros accept some code as an input, operate on this code, and produce some code as an output rather than matching against patterns and replacing the code with other code as declarative macros do.
The three kinds of procedural macros are custom derive, attribute-like and function-like and all work in a similar way.
When creating procedural macros, the definitions must reside in their own crate with a special enum crate type.
This is for complex technical reasons that the Rust team hopes to eliminate in the future.
Here we show how to define a procedural macro, where `some_attribute` is placeholder for using a specific macro variety.
```rust
use proc_macro;
#[some_attribute]
pub fn some_name(input: TokenStream) -> TokenStream {
}
```
This function that defines a procedural macro takes `TokenStream` as an input and produces a `TokenStream` as an output.
The `ToeknnStream` type is defined by the `proc_macro` crate that is included with Rust and represents a sequence of tokens.
This is the core of the macro: the source code that the macro is operating on makes up the input `TokenStream` and the code the macro produces is the output `TokenStream`.
This function also has an attribute attached to it which specifies what kind of procedural macro we are creating.
We can have multiple kinds of procedural macros in the same crate.
Now we will look at the different kinds of procedural macros.
First we will start with a custom derive macro and then go on to explain the small dissimilarities that make the other forms different.
## How to Write a Custom `derive` Macro
Lets start with a crate named `hello_macro` which defines a trait named `HelloMacro` with one associated function named `hello_macro`.
Rather than forcing our users to implement the `HelloMacro` trait for each of their types, we will provide a procedural macro so users can annotate their type with `#[derive(HelloMacro)]` to get a default implementation of the `hello_macro` function.
The default implementation will print `Hello, Macro! My name is TypeName!` where `TypeName` is the name of the type which this trait has been defined.
We will write a crate that enables another programmer to write code like this below using our crate.
```rust
use hello_macro::HelloMacro;
use hello_macro_derive::HelloMacro;
#[derive(HelloMacro)]
struct Pancakes;
fn main() {
Pancakes::hello_macro();
}
```
This will print `Hello, Macro! My name is Pancakes!` when we are done.
The first step will be to make a new library crate using this:
```
$ cargo new hello_macro --lib
```
Then we will define the `HelloMacro` trait and its associated function.
```rust
pub trait HelloMacro {
fn hello_macro();
}
```
*src/lib.rs*
We have a trait and its function.
Now at this point our crate user could implement the trait to achieve the desired functionality, like this:
```rust
use hello_macro::HelloMacro;
struct Pancakes;
impl HelloMacro for Pancakes {
fn hello_macro() {
println!("Hello, Macro! My name is Pancakes!");
}
}
fn main() {
Pancakes::hello_macro();
}
```
However they would need to write the implementation block for each type they wanted to use with `hello_macro`.
We want to spare them from having to do this.
Additionally, we can't yet provide the `hello_macro` function with default implementation that will print the name of the type the trait is implemented on.
Rust doesn't have reflection capabilities, so it cannot look up the type's name at runtime.
Instead we need a macro to generate code at compile time.
Next is to define the procedural macro.
At the time of writing this, procedural macros need to be in their own crate.
The convention for structuring crates and macro crates is as follows.
For a crate named `foo`, a custom derive procedural macro crate is called `foo_derive`.
Now lets start a new crate called `hello_macro_derive` inside our `hello_macro` project.
```
$ cargo new hello_macro_derive --lib
```
The two crates are tightly related, so we create the procedural macro crate within the directory of our `hello_macro` crate.
If we change the trait definition in `hello_macro`, we will have to change the implementation of the procedural macro in `hello_macro_derive` as well.
The two crates will need to be published separately, and programmers using these crates will need to add both as dependencies and bring them both into scope.
We instead could have the `hello_macro` crate use `hello_macro_derive` as a dependency and re-export the procedural macro code.
The way we have structured the project makes it possible for programmers to use `hello_macro` even if we don't want the `derive` functionality.
We need to declare the `hello_macro_derive` crate as a procedural macro crate.
We also need functionality form the `syn` and `quote` crates.
So we need to add them as dependencies.
Add this to the *Cargo.toml* file for the `hello_macro_derive`.
```toml
[lib]
proc-macro = true
[dependencies]
syn = "2.0"
quote = "1.0"
```
To start defining the procedural macro, place the code into your *src/lib.rs* file for the `hello_macro_derive` crate.
Note that this code will not compile unless we add a definition for the `impl_hello_macro` function.
```rust
use proc_macro::TokenStream;
use quote::quote;
#[proc_macro_derive(HelloMacro)]
pub fn hello_macro_derive(input: TokenStream) -> TokenStream {
// Construct a representation of Rust code as a syntax tree
// that we can manipulate
let ast = syn::parse(input).unwrap();
// Build the trait implementation
impl_hello_macro(&ast)
}
```
*hello_macro_derive/src/lib.rs*
Note that we have split the code into the `hello_macro_derive` function, which is responsible for parsing the `TokenStream` and the `impl_hello_macro` function, which is responsible for transforming the syntax tree.
This makes writing a procedural macro more convenient.
The code in the outer function (`hello_macro_dervie` in this case) will be the same for almost every procedural macro crate you see or create.
The code specified in the body of the inner function (`impl_hello_macro` in this case) will be different depending on your procedural macro's purpose.
We have introduced three new crates: `proc_macro`, [`syn`](https://crates.io/crates/syn), and [`quote`](https://crates.io/crates/quote).
The `proc_macro` crate comes with Rust, so we don't need to add that to the dependencies in *Cargo.toml*.
The `proc_macro` crate is the compiler's API that allows us to read and manipulate Rust code from our code.
The `syn` crate parses Rust code form a string into a data structure that we can perform operations on.
The `quote` crate turns `syn` data structures back into Rust code.
These crate makes it much simpler to parse any sort of Rust code we might want to handle: writing a full parser for Rust code is no simple task.
The `hello_macro_derive` function will be called when a user of our library specifies `#[derive(HelloMacro)]` on a type.
This is possible because we have annotated the `hello_macro_derive` function here with `proc_macro_derive` and specified the name `HelloMaro`.
This matches our trait name, this is the convention most procedural macros follow.
The `hello_macro_derive` function first converts the `input` from a `TokenStream` to a data structure that we can then interpret and perform operations on.
This is where `syn` comes into aciton.
The `parse` function in `syn` takes a `TokenStream` and shows the relevant parts of the `DeriveInput` struct we get form parsing the `struct Pancakes;` string.
```rust
DeriveInput {
// --snip--
ident: Ident {
ident: "Pancakes",
span: #0 bytes(95..103)
},
data: Struct(
DataStruct {
struct_token: Struct,
fields: Unit,
semi_token: Some(
Semi
)
}
)
}
```
The fields of this struct show that the Rust code we have parsed is a unit struct with the `ident` (identifier, this means the name) of `Pancakes`.
There are more fields on this struct for describing all kinds of Rust code.
Check the [`syn` documentation for `DeriveInput`](https://docs.rs/syn/2.0/syn/struct.DeriveInput.html) for more info.
Soon the `impl_hello_macro` function will be defined, which is where we will build the new Rust code we want to include.
Before we do this.
Note that the output for our derive macro is also a `TokenStream`.
The returned `TokenStream` is added to the code that our crate users write, so when they compile their own crate, they will get the extra functionality that we will provide in the modified `TokenStream`.
You may have noticed that we are calling `unwrap` to cause the `hello_macro_derive` function to panic if the call to the `syn::parse` function fails.
This is necessary for our procedural macro to panic on errors because `proc_macro_derive` functions must return `TokenStream` rather than `Result` to conform to the procedural macro API.
Here we have simplified this example by using `unwrap`; in production you should provide more specific error messages about what went wrong by using `panic!` or `expect`.
Note that we have the code to turn the annotated Rust code from a `TokenStream` into a `DeriveInput` instance.
Now we will generate the code that implements the `HelloMacro` trait on the annotated type.
This is shown here.
```rust
fn impl_hello_macro(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;
let gen = quote! {
impl HelloMacro for #name {
fn hello_macro() {
println!("Hello, Macro! My name is {}!", stringify!(#name));
}
}
};
gen.into()
}
```
We get an `Ident` struct instance containing the name (identifier) of the annotated type using `ast.idetn`.
The struct before shows that when we run the `impl_hello_macro` function on the code form before that.
The `ident` we get will have the `ident` field with a value of `"Pancakes"`.
The `name` variable here will contain an `Ident` struct instance that, when printed will be the string `"Pancakes"`, the name of the struct from way before.
The `quote!` macro lets us define the Rust code that we want to return.
The compiler expects something different to the direct result of the `quote!` macro's execution, so we need to convert it to a `TokenStream`.
We do this by calling the `into` method, this consumes this intermediate representation and returns a value of the required `TokenStream` type.
The `quote!` macro also provides some very interesting templating mechanics.
We can enter `#name` and `quote!` will replace it with the value in the variable `name`.
You can even do some repetition similar to the way regular macros work.
Check the [`quote` crate's docs](https://docs.rs/quote) for a thorough introduction.
We want our procedural macro to generate an implementation of our `HelloMacro` trait for the type the user annotated, which we can get by using `#name`.
The trait implementation has the one function has the one function `hello_macro`, whose body contains the functionality we want to provide.
Printing `Hello, Macro! My name is` and then the name of the annotated type.
The `stringify!` macro used here is built into Rust.
This takes a Rust expression, such as `1 + 2`, and at compile time turns the expression into a string literal, such as `"1 + 2"`.
This is different than `format!` or `println!`, macros which evaluate the expression and then turn the result into a `String`.
It is possible that the `#name` input may be an expression to print literally, so we use `stringify!`.
Using `stringify!` also saves an allocation by converting `#name` to a string literal at compile time.
Now at this point, `cargo build` should complete successfully in both `hello_macro` and `hello_macro_derive`.
Now we will hook these crates to the code from before to see the procedural macro in action.
Create a new binary project in your *projects* directory using `cargo new pancakes`.
We need to add `hello_macro` and `hello_macro_derive` as dependencies in the `pancakes` crate's *Cargo.toml*.
If you are publishing your versions of `hello_macro` and `hello_macroderive` to [crates.io](https://crates.io) they would be regular dependencies.
If not you can specify them as `path` dependencies as follows:
```toml
hello_macro = { path = "../hello_macro" }
hello_macro_derive = { path = "../hello_macro/hello_macro_derive" }
```
Now you can put the code from way before into *src/main.rs*, and run `cargo ran`.
It should print `Hello, Macro! My name is Pancakes!`.
The implementation of the `HelloMacro` trait form the procedural macro was included without the `pancakes` crate needing to implement it.
The `#[derive(HelloMacro)]` added the trait implementation.
## Attribute-like macros
These kinds of macros are similar to custom derive macros, but instead of generating code for the `derive` attribute, they allow you to create new attributes.
They are also more flexible: `derive` only works for structs and enums.
Attributes can be applied to other items as well, such functions.
Here is an example of using an attribute-like macro: say you have an attribute named `route` that annotates functions when using a web application framework.
```rust
#[route(GET, "/")]
fn index() {
```
This `#[route]` attribute would defined by the framework as a procedural macro.
The signature of the macro definition function would look like this:
```rust
#[proc_macro_attribute]
pub fn route(attr: TokenStream, item: TokenStream) -> TokenStream {
```
Here, we have two parameters of type `TokenStream`.
The first is for the contents of the attribute: the `GET, "/"` part.
The second is the body of the item the attribute is attached to: here it is `fn index() {}` and the rest of the function's body.
Other than that, attribute-like macros work the same way as custom derive macros.
You create a crate with the `proc-macro` crate type and implement a function that generates the code you want.
## Function-like macros
Function-like macros define macros that look like function calls.
This is similar to `macro_rules!` macros.
They are more flexible than functions.
For example they can take an unknown number of arguments.
However `macro_rules!` macros can be defined only using the match-like syntax that was discussed in the [ “Declarative Macros with `macro_rules!` for General Metaprogramming"](./Macros.md#declarative-macros-with-macro_rules-for-general-metaprogramming) section from earlier before.
Function-like macros take a `TokenStream` parameter and their definition manipulates that `TokenStream` using Rust code as the other two types of procedural macros do.
Here is an example of a function-like macro is an `sql!` macro that may be called like this:
```rust
let sql = sql!(SELECT * FROM posts WHERE id=1);
```
This macro would parse the SQL statement inside it and check that is syntactically correct.
This is much more complex processing than a `macro_rules!` macro can do.
The `sql!` macro would be defined like this:
```rust
#[proc_macro]
pub fn sql(input: TokenStream) -> TokenStream {
```
The definition is similar to the custom derive macro's signature: we receive the tokens that are inside the parentheses and return the code we wanted to generate.
s

View File

@ -0,0 +1,16 @@
# Object-Oriented Programming Features of Rust
OOP is a way of modeling programs.
Objects as a programmatic concept were introduced in the programming language Simula in the 1960s.
These objects influenced Alan Kay's programming architecture in which objects pass messages to each other.
To describe this architecture, he coined the term *object-oriented programming* in 1967.
Many competing definitions describe what OOP is, and by some of these definitions Rust is object-oriented, but by other it is not.
In this section, we will explore certain characteristics that are commonly considered object-oriented and how those characteristics translate to idiomatic Rust.
Next we will show how to implement an object-oriented design pattern in Rust and discuss the trade-offs of doing so.
Versus implementing a solution using some of Rust's strengths instead.

View File

@ -0,0 +1,333 @@
# Using Message Passing to Transfer Data Between Threads
One popular approach to ensuring safe concurrency is *message passing*, where threads or actors communicate by sending each other message containing data.
The idea in a solgan is best said by the [Go language documentation](https://golang.org/doc/effective_go.html#concurrency):
"Do not communicate by sharing memory; instead, share memory by communicating."
To accomplish message-sending concurrency, Rust's std library provides an implementation of *channels*.
A channel is a general concept in programming by which data is sent from one thread to another.
It can be imagined being like a directional channel of water, such as a stream or a river.
If you put something like a rubber duck into a river, it will travel downstream to the end of the waterway.
A channel has two parts:
- A transmitter
- A receiver
The transmitter is the upstream location where you put rubber ducks into the river.
The receiver is where the rubber duck ends up downstream.
One part of your code calls methods on the transmitter with the data you want to send
Another part checks the receiving end for messages.
A channel is said to be *closed* if either the transmitter or receiver is dropped.
We will work up to a program that has one thread to generate values and send them down a channel and another thread that will receive the values and print them out.
We will send simple values between threads to demostrate this feature using channels.
Once fimiliar with the technique, you could use channels for any threads that need to communicate between each other.
This could be used as a chat system or a system where many threads perform parts of a calculation and send the parts to one thread that aggregates the results.
First we will create a channel and do nothing with it.
This will not compile yet becuase Rust can't tell what type of values we want to send over the channel.
```rust
use std::sync::mpsc;
fn main() {
let (tx, rx) = mpsc::channel();
}
```
We first crate a new channle using the `mpsc::channel` function.
`mpsc` stands for *multiple producer, single consumer*.
This means that the way Rust's std library implements channels means a channel have multiple *sending* ends that produce values but only one *receiving* end tha consumes thoes values.
This can be picured as multiple streams flowing together into one big river. Everything will be received at one point regradless of which stream it starts at.
Here we will start iwth a single producer for now, later we will add multiple producers when we get this example working.
The `mpsc::channel` function returns a tuple, where the first element is the sending end (the transmitter), and the second element is the receiving end (the receiver).
The abbreviatios `tx` and `rx` are normally used in many fields for *transmitter* and *receiver*, so we name our variables as such to indicate each end.
We are using a `let` statement with a pattern that destructures the tuple (this will be discussed in ch19).
For now knwo that using a `let` statement this way is a convenient approach to extract the pieces of the tuple returned by `mpsc::channel`
Now we will move the transmitting end into a spawned thread and have it send one strin so the spawned thread is communicating with the main thread.
This is like putting a rubber duck in the river upstream or send a chat message from one thread to another.
```rust
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
}
```
Here we use `thread::spawn` to create a new thread and then using `move` to move `tx` into the closure so the spawned thread owns `tx`.
The spawned thread needs to own the transmitter to be able to send messages through the channel.
The tansmitter has a `send` method that takes the value we want to send.
The `send` method returns a `Result<T, E>` type.
This means that if the receiver has already been dropped and there is nowhere to send a value, the send operation will return an error.
Here in this example we call `unwrap` to panic in the case of an error.
In a real application we should handle it properly, check ch 9 to review strategies for proper error handlin. [Found Here](./Error%20Handling.md)
In this next example we will get the value fom the receuver in the main thread.
This is like grabbing the rubber duck from the water at the end of the river or receiving a chat message.
```rust
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
});
let received = rx.recv().unwrap();
println!("Got: {received}");
}
```
The receiver has two useful methods: `recv` and `try_recv`.
Here we use `recv` this is short for *receive*, which will block the main thread's execution and wait until a value is sent down a channel.
Once a value is sent, `recv` will return it in a `Result<T, E>`.
When the transmitter closes, `recv` will return an error to signal that no more values will be coming.
The `try_recv` method doesn't block the thread, instead it will return a `Result<T, E>` immediately.
An `Ok` value holding a message if one is available and an `Err` value if there aren't any messages at this time.
Using `try_recv` is useful if this thread has other work to do while waiting for messages.
We could write a loop that calls `try_recv` every so often, handles a mesage if one is available and otherwise does other work for a little while until checking again.
Here we have used `recv` in this example for simplicity, we dont have any other work for the main thread to do other than wait for messages so blocking the main thread is appropriate.
Here is the output value form the main thread
```
Got: hi
```
## Channels and Ownership Transference
The ownership rules play a crutial rule in message sending because they ensure that you write safe, concurrent code.
Preventing errors in concurrent is the advantage of thinking about ownership throughout your Rust programs.
Here we will do an experiemnt to show how channels and ownership work together to prvent problems.
We will try to use a `val` value in the spawned thread *after* we sent it down the channel.
If we try compiling the code below we will see why this isn't allowed
```rust
use std::sync::mpsc;
use std::thread;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let val = String::from("hi");
tx.send(val).unwrap();
println!("val is {val}");
});
let received = rx.recv().unwrap();
println!("Got: {received}");
}
```
Here we attempt to prin `val` after sending it down the channel via `tx.send`
Allowing this would be a bad idea. Once the value has been sent to another thread, that thread could have already modified or dropped it before we try to use the value again.
Or potentially, the other thread's modifications could cause errors or unexpected results due to inconsistent or non existent data.
Rust gives us this compilation error if we try to compile this
```
$ cargo run
Compiling message-passing v0.1.0 (file:///projects/message-passing)
error[E0382]: borrow of moved value: `val`
--> src/main.rs:10:26
|
8 | let val = String::from("hi");
| --- move occurs because `val` has type `String`, which does not implement the `Copy` trait
9 | tx.send(val).unwrap();
| --- value moved here
10 | println!("val is {val}");
| ^^^^^ value borrowed here after move
|
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
For more information about this error, try `rustc --explain E0382`.
error: could not compile `message-passing` (bin "message-passing") due to 1 previous error
```
Here the `send` function takes ownership of its parameter and when the value is moved, the receiver takes ownership of it.
This stops us form accidentally using the value again after sending it.
Here the ownership ystem checks that everything is ok.
## Sending Multiple Vales and Seeing the Receiver Waiting
Here we will dive into a clear example that will show us that two separate threads that are talking to each other over the channel.
In this example we have made some modifications that will prove that the code is running concurrently.
The spawned thread will now send multiple messages and pause for a second between each message.
```rust
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
let (tx, rx) = mpsc::channel();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {received}");
}
}
```
Now the spawned thread has a vector of strings that we want to send to the main thread.
We then iterate over them, sending each individually, and pause between each by calling the `thread::sleep` function witha a `Duration` value of 1 second.
Now in the main thread we are notcallign the `recv` function explicitly anymore.
Instead we treat `rx` as an iterator.
For each value, received we print it.
When th channel is closed, iteration iwll end.
Here is the output you should see with a 1-second apuse between each line
```
Got: hi
Got: from
Got: the
Got: thread
```
Due to no having any code that pauses or delays in the `for` loop in the main thread, we can tell that the main thread is wating to receive values form te spawned thread.
## Creating Multiple Producers by Cloning the Transmitter
We mentioned that `mpsc` was an acronym for *multiple producer, single consumer*.
Here we will put `mpsc` to use and expand te code example from before to create multiple threads that all send values to the same receiver.
We can do this by clonng the transmitter, shown here
```rust
use std::sync::mpsc;
use std::thread;
use std::time::Duration;
fn main() {
// --snip--
let (tx, rx) = mpsc::channel();
let tx1 = tx.clone();
thread::spawn(move || {
let vals = vec![
String::from("hi"),
String::from("from"),
String::from("the"),
String::from("thread"),
];
for val in vals {
tx1.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
thread::spawn(move || {
let vals = vec![
String::from("more"),
String::from("messages"),
String::from("for"),
String::from("you"),
];
for val in vals {
tx.send(val).unwrap();
thread::sleep(Duration::from_secs(1));
}
});
for received in rx {
println!("Got: {received}");
}
// --snip--
}
```
Now before we create the first spawned, we call `clone` on the transmitter.
This will give us a new transmitter we can pass to the first spawned thread.
We pass the original transmitter to the second spawned thread.
This now allows us to have two threads, each sending different mesages to one receiver.
Now when this code is run it should look similar to this
```
Got: hi
Got: more
Got: from
Got: messages
Got: for
Got: the
Got: thread
Got: you
```
This may be in a different oder depending on the system.
This is what makes concurrency difficult but interesting.
If you experiment with `thread::sleep`, giving it various values in the different threads, each run will be even more nondeterministic and create different outputs each time.
Now we can look at a different method of concurrency, other than channels.
[Next Section Found Here](./Shared%20State%20Concurrency.md)

44
Pattern Matching.md Normal file
View File

@ -0,0 +1,44 @@
# Patterns and Matching
*Patterns* are a special syntax in Rust for matching against the structure of types, both complex and simple.
Using patterns in conjunction with `match` expressions and other constructs give you more control over a program's flow.
A pattern consists of some combination of the following:
- Literals
- Destructured arrays, enums, structs, or tuples
- Variables
- Wildcards
- Placeholders
Some examples include `x`, `(a, 3)` and `Some(Color::Red)`.
In the contexts in which patterns are valid, these components describe the shape of data.
Our program then matches values against the patterns to determine whether it has the correct shape of data to continue running a particular piece of code.
In order to use a pattern, we compare it to some value.
If the pattern matches the value, we use the value parts in our code.
Recall the `match` expression that used patterns, such as the coin-sorting machine example.
If the value fits the shape of the pattern, we can use the named pieces.
If it doesn't, the code associated with the pattern won't run.
This chapter is intended to be a reference on all things related to patterns.
We will cover:
- Valid places to use patterns [Section Link Here]()
- Difference between refutable and irrefutable patterns [Section Link Here](./Refutability.md)
- Different kinds of pattern syntax [Section Link Here](./Pattern%20Syntax.md)
By the end you will know how to use patterns to express many concepts in a clear way.
## Summary
Patterns are very useful in distinguishing between different kinds of data.
When used in `match` expressions, Rust ensures your patterns cover every possible value, or your program will not compile.
Patterns in `let` statements and function parameters make those constructs more useful, enabling the destructuring of values into smaller parts at the same time as assigning to variables.
Then we can create simple or complex patterns to suit our needs.

686
Pattern Syntax.md Normal file
View File

@ -0,0 +1,686 @@
# Pattern Syntax
Here we gather all the syntax valid in patterns and discuss why and when you might want to use each one.
## Matching Literals
As you saw previously in Ch6, you can match patterns against literals directly.
Here is an example of this
```rust
let x = 1;
match x {
1 => println!("one"),
2 => println!("two"),
3 => println!("three"),
_ => println!("anything"),
}
```
The code prints `one` because the value in `x` is 1.
This syntax is useful when you want your code to take an action if it gets a particular concrete value.
## Matching Named Variables
Named variables are irrefutable patterns that match any value, and we have used them many times.
However, there is a complication when you use named variables in `match`, `if let`, or `while let` expressions.
Because each kinds of expression starts a new scope, variables declared as part of a pattern inside the expression will shadow those with the same name outside, as is the case with all variables.
Here we declare a variable named `x` with the value `Some(5)` and a variable `y` with the value `10`.
Next we create a `match` expression on the value `x`.
Look at the patterns in the match arms and `println!` at the end, and try to figure out what the code will print before running this code or reading further.
```rust
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(y) => println!("Matched, y = {y}"),
_ => println!("Default case, x = {x:?}"),
}
println!("at the end: x = {x:?}, y = {y}");
```
Lets run through what happens when the `match` expression runs.
The pattern in the first match arm doesn't match the defined value of `x`, so the code continues.
The pattern in the second match arm introduces a new variable named `y` that will match any value inside a `Some` value.
Because we are in a new scope inside the `match` expression, this is a new `y` variable, not the `y` we declared at the beginning with the value 10.
This new `y` binding will match any value inside a `Some`, which is what we have in `x`.
Therefore the new `y` binds to the inner value of the `Some` in `x`.
That value is `5` so the expression for that arm executes and prints `Matched , y = 5`.
If `x` has been a `None` value instead of `Some(5)`, the patterns in the first two arms wouldn't have matched. so the value would have matched to the underscore.
We didn't introduce the `x` variable in the pattern of the underscore arm, so the `x` in the expression is still the outer `x` that hasn't been shadowed.
For this hypothetical case, the `maatch` would pint `Default case, x = None`.
When the `match` expression is done, its scope ends, and so does the scope of the inner `y`.
The last `println!` produces `at the end: x = Some(5), y = 10`.
To create a `match` expression that compares the values of the outer `x` and `y` rather than introducing a new variable which shadows the exiting `y` variable.
We would need to use a match guard conditional instead.
This will be covered later in the ch.
## Multiple Patterns
You can match multiple patterns using the `|` syntax, which is the pattern *or* operator.
For example in the following code we match the value of `x` against the match arms, the first of which has an *or* option, meaning if the value of `x` matches either of the values in that arm, that arm's code will run
```rust
let x = 1;
match x {
1 | 2 => println!("one or two"),
3 => println!("three"),
_ => println!("anything"),
}
```
This code prints `one or two`.
## Matching Ranges of Values with `..=`
The `..=` syntax allows us to match to an inclusive range of values.
Here when a pattern matches any of the values within the given range, that arm will execute
```rust
let x = 5;
match x {
1..=5 => println!("one through five"),
_ => println!("something else"),
}
```
If `x` is 1, 2, 3, 4, or 5, the first arm will match.
This syntax is more convenient for multiple match values that using the `|` operator to express the same idea.
If we were to use `|` we would need to do `1 | 2 | 3 | 4 | 5`.
Specifying a range is much shorter, especially if we want to match, say any number between 1 and 1,000.
The compiler checks that the range isn't empty at compile time, because only types for which Rust can tell if a range is empty or not are `char` and numeric values, ranges are only allowed with numeric or `car` values.
Rust can tell that `'c'` is within the first pattern's range and prints `early ASCII letter`.
## Destructuring to Break Apart Values
We can also use patterns to destructure structs, enums, and tuples to use different parts of these values.
We will walk through each value.
### Destructuring Structs
This code shows a `Point` struct with two fields, `x` and `y`, that we can break apart using a patter with a `let` statement
```rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x: a, y: b } = p;
assert_eq!(0, a);
assert_eq!(7, b);
}
```
This creates the variables `a` and `b` that match the values of the `x` and `y` fields of the `p` struct.
This shows that the names of the variables in the pattern don't have to match the field names of the struct.
However it is common to match the variable names to the field names to make it easier to remember which variables came from which fields.
Because of this common usage, and because writing `let Point { x: x, y: y} = p;` contains a lot of duplication, Rust has a shorthand for patterns that match struct fields.
You only need to list the name of the struct field, and the variables created from the pattern will have the same names.
This code behaves in the same way as om the code before, but the variables created in the `let` pattern are `x` and `y` instead of `a` and `b`.
```rust
struct Point {
x: i32,
y: i32,
}
fn main() {
let p = Point { x: 0, y: 7 };
let Point { x, y } = p;
assert_eq!(0, x);
assert_eq!(7, y);
}
```
This code creates the variables `x` and `y` that match the `x` and `y` fields of the `p` variable.
The outcome is that the variables `x` and `y` contain the values form the `p` struct.
We can also destructure with literal values as part of the struct pattern rather than creating variables for all the fields.
Doing this allows us to test some of the fields for particular values while creating variables to destructure the other fields.
Here we have a `match` expression that separates `Point` values into three cases.
Points that lie directly on the `x` axis (which is true when `y = 0`)
On the `y` axis (`x = 0`)
Or Neither
```rust
fn main() {
let p = Point { x: 0, y: 7 };
match p {
Point { x, y: 0 } => println!("On the x axis at {x}"),
Point { x: 0, y } => println!("On the y axis at {y}"),
Point { x, y } => {
println!("On neither axis: ({x}, {y})");
}
}
}
```
The first arm will match any point that lies on the `x` axis by specifying that the `y` field matches if its value matches the literal `0`.
The pattern still creates an `x` variable that we can use in the code for this arm.
The second arm matches any point on the `y` axis by specifying that the `x` field matches if its value is `0` and creates a variable `y` for the value of the `y` field.
The third arm doesn't specify any literals, so it matches any other `Point` and creates variables that we can use in the code for this arm.
Here the value `p` matches the second arm by virtue of `x` containing a 0, so this code will print `On the x axis at 0`.
### Destructuring Enums
We have destructured enums before, but haven't explicitly discussed that the pattern to destructure an enum corresponds to the way the data stored within the enum is defined.
For example, here we use the `Message` enum from Ch6 and write a `match` with patterns that will destructure each inner value.
```rust
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
fn main() {
let msg = Message::ChangeColor(0, 160, 255);
match msg {
Message::Quit => {
println!("The Quit variant has no data to destructure.");
}
Message::Move { x, y } => {
println!("Move in the x direction {x} and in the y direction {y}");
}
Message::Write(text) => {
println!("Text message: {text}");
}
Message::ChangeColor(r, g, b) => {
println!("Change the color to red {r}, green {g}, and blue {b}");
}
}
}
```
This code will print `Change the color to red 0, green 160, and blue 255`.
Try changing the value of `msg` to see the code form the other arms run.
For enum variants without any data, like `Message::Quit`.
We can't destructure the value any further.
We can only match on the literal `Message::Quit` value and no variables are in that pattern.
For struct-like enum variants, like `Message::Move`.
We can use a pattern similar to the pattern we specify to match structs.
After the variant name, we place curly brackets and then list the fields with variable so we break apart the pieces to use in the code for this arm.
We did use the shorthand form as we did before.
For tuple-like enum variants, like `Message::Write` that holds a tuple with one element and `Message::ChangeColor` that holds a tuple with three elements.
The pattern is similar to the pattern we specify to match tuples.
The number of variables in the pattern must match the number of elements in the variant we are matching.
### Destructuring Nested Structs and Enums
So we have seen examples that have all been matching structs or enums on level deep.
Matching can work on nested items too.
For example, we can refactor the code form before to support RGB and HSV colors in the `ChangeColor` message.
```rust
enum Color {
Rgb(i32, i32, i32),
Hsv(i32, i32, i32),
}
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(Color),
}
fn main() {
let msg = Message::ChangeColor(Color::Hsv(0, 160, 255));
match msg {
Message::ChangeColor(Color::Rgb(r, g, b)) => {
println!("Change color to red {r}, green {g}, and blue {b}");
}
Message::ChangeColor(Color::Hsv(h, s, v)) => {
println!("Change color to hue {h}, saturation {s}, value {v}");
}
_ => (),
}
}
```
The first arm in the `match` expression, matches a `Message::ChangeColor` enum variant that contains a `Color::Rgb` variant.
Then the pattern binds to the three inner `i32` values.
The second arm also matches a `Message::ChangeColor` enum variant, but the inner enum matches `Color::Hsv` instead.
We can specify these complex conditions in one `match` expression, even though two enums are involved.
### Destructuring Structs and Tuples
We can also mix, match and nest destructuring patterns in even more complex ways.
This example shows a complicated destructure where we nest structs and tuples inside a tuple and destructure all the primitive values out
```rust
let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
```
Here the code lets us break complex types into their component parts so we can use the values we are interested in separately.
Destructuring with patters is a convenient way to use pieces of values such as the value from each field in a struct, separately from each other.
## Ignoring Values in a Pattern
Sometimes it is useful to ignore values in a pattern, such as in the last arm of a `match`, to get a catchall that doesn't actually do anything but does account for all remaining possible values.
There are a few ways to ignore entire values or pats of values in a pattern:
- Using the `_` pattern
- Using the `_` pattern within another pattern
- Using a name that starts with an underscore
- Using `..` to ignore remaining parts of a value.
### Ignoring an Entire Value with `_`
We have used the underscore as a wildcard pattern that will match any value but not bind to the value.
This is particularly useful as the last arm in a `match` expression.
We can also use it in any pattern, including function parameters
```rust
fn foo(_: i32, y: i32) {
println!("This code only uses the y parameter: {y}");
}
fn main() {
foo(3, 4);
}
```
This will completely ignore the value `3` that is passed as the first argument.
You will print `This code only uses the y parameter: 4`.
In most cases when you no longer need a particular function parameter, you would change the signature so it doesn't include the used parameter.
Ignoring a function parameter can be especially useful in cases when you are implementing a trait when you need a certain type signature but the function body in your implementation doesn't need one of the parameters.
Thus then you avoid getting a compiler warning about unused function parameters, as you would if you used a name instead.
### Ignoring Parts of a Value with a Nested `_`
You can also use `_` inside another pattern to ignore just part of a value.
Lets say when you want to test for only part of a value but have no use for the other parts in the corresponding code we want to run.
Here shows code responsible for managing a setting's value.
The business requirements are that the user should not be allowed to overwrite an existing customization of setting but can unset the setting and give it a value if it is currently unset.
```rust
let mut setting_value = Some(5);
let new_setting_value = Some(10);
match (setting_value, new_setting_value) {
(Some(_), Some(_)) => {
println!("Can't overwrite an existing customized value");
}
_ => {
setting_value = new_setting_value;
}
}
println!("setting is {setting_value:?}");
```
This will print `Can't overwrite an existing customized value` and then `setting is Some(5)`.
In the first arm, we don't need to match on or use the values inside either `Some` variant, but we do need to test for the case when `setting_value` and `new_setting_value` are the `Some` variant.
In this case, we print the reason for not changing `setting_value`, and it doesn't get changed.
In all other cases (if either `setting_value` or `new_setting_value` are `None`) expressed by the `_` pattern in the second arm.
We want to allow `new_setting_value` to become `setting_value`.
We could also use underscores in multiple places within one pattern to ignore particular vlaues.
Here shows an example of ignoring the second and fourth values in a tuple of five items.
```rust
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, _, third, _, fifth) => {
println!("Some numbers: {first}, {third}, {fifth}")
}
}
```
This will print `Some numbers: 2, 8, 32`, and the values 4 and 16 will be ignored.
### Ignoring an Unused Variable by Starting Its Name with `_`
If you create a variable but don't use it anywhere, Rust will usually issue a warning because an unused variable could be a bug.
However sometimes it is useful to be able to create a variable you will not use yet.
Such as when you are prototyping or just starting a project.
In this situation, you can tell Rust not to warn you about the unused variable by starting by starting the name of the variable with an underscore.
Here we create two unused variables, but when we compile, we should only get warning about one of them.
```rust
fn main() {
let _x = 5;
let y = 10;
}
```
We get a warning about not using the variable `y`, but we don't get a warning about not using `_x`.
The only difference between using only `_` and using a name that starts with an underscore.
The syntax `_x` still binds the value to the variable, whereas `_` doesn't bind at all.
To show a case where this distinction matters, this will provide us with an error.
```rust
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{s:?}");
```
We will receive an error because the `s` value will still be moved into `_s`, which prevents us from using `s` again.
Using the underscore by itself doesn't ever bind to the value.
This code will compile without an errors because `s` doesn't get moved into `_`.
```rust
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{s:?}");
```
This code works just fine because we never bind `s` to anything; it isn't moved.
### Ignoring Remaining Parts of a Value with `..`
Values that have many parts, we can use the `..` syntax to use specific parts and ignore the rest, avoiding the need to list underscores for each ignored value.
The `..` pattern ignores any parts of a value that we haven't explicitly matched in the rest of the pattern.
In this code we have a `Point` struct that holds a coordinate in three-dimensional space.
In this `match` expression, we want to operate only on the `x` coordinate and ignore the values in the `y` and `z` fields.
```rust
struct Point {
x: i32,
y: i32,
z: i32,
}
let origin = Point { x: 0, y: 0, z: 0 };
match origin {
Point { x, .. } => println!("x is {x}"),
}
```
Here we list the `x` value and then just include the `..` pattern.
This is far quicker than having to list `y: _` and `z: _`, particularly when we are working with structs that have lots of fields in situations where only one or two fields are relevant.
The syntax `..` will expand to as many values as it needs to be.
This is an example of how to use `..` with a tuple.
```rust
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(first, .., last) => {
println!("Some numbers: {first}, {last}");
}
}
}
```
Output
```
Some numbers: 2, 32
```
The fist and last value are matched with `first` and `last`.
The `..` will match and ignore everything in the middle.
Using `..` must be unambiguous.
If it unclear which values are intended for matching and which should be ignored, Rust will give us an error.
Here shows an example of using `..` ambiguously, so it will not compile.
```rust
fn main() {
let numbers = (2, 4, 8, 16, 32);
match numbers {
(.., second, ..) => {
println!("Some numbers: {second}")
},
}
}
```
We get this compiler error
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error: `..` can only be used once per tuple pattern
--> src/main.rs:5:22
|
5 | (.., second, ..) => {
| -- ^^ can only be used once per tuple pattern
| |
| previously used here
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
It is impossible for Rust to determine how many values in the tuple to ignore before matching a value with `second` and then how many further values to ignore after.
This code could mean we want to ignore `2`, bind `second` to `4` and then ignore `8` and `16` and `32`.
Or it could mean we want to ignore `2` and `4`, bind `second` to `8`, and then ignore `16` and `32`.
Or any other case.
The variable name `second` doesn't mean anything special to Rust, we get a compiler error because using `..` in two places like this ambiguous.
## Extra Conditionals with Match Guards
A *match guard* is an additional `if` condition, specified after the pattern in a `match` arm, that must also match for that arm to be chosen.
Match guards are useful for expressing complex ideas than a pattern alone allows.
They are only available in `match` expressions, not in `if let` or `while let` expressions.
The condition can use variables created in the pattern.
Here shows a `match` where the first arm has the pattern `Some(x)` and also has a match guard of `if x % 2 == 0`
This will be true if the number is even.
```rust
let num = Some(4);
match num {
Some(x) if x % 2 == 0 => println!("The number {x} is even"),
Some(x) => println!("The number {x} is odd"),
None => (),
}
```
This will print `The number 4 is even`.
When `num` is compared to the pattern in the first arm, it matches.
This is because `Some(4)` matches `Some(x)`.
Next the match guard checks whether the remainder of dividing `x` by 2 is equal to 0.
Because this is true the first arm is selected.
If `num` had been `Some(5)` instead, the match guard in the first arm would have been false.
This is because the remainder of 5 / 2 is 1, which is not equal to 0.
Rust would then go to the second arm, which doesn't have a match guard and therefore matches any `Some` variant.
There is not may to express the `if x % 2 == 0` condition within a pattern, so the match guard gives us the ability to express this logic.
The downside of this is that the compiler doesn't try to check for exhaustiveness when match guard expressions are involved.
Before we mentioned that we could use match guards to solve our pattern shadowing problem.
Recall that after we created a new variable inside the pattern in the `match` expression instead of using the variable outside the `match`.
This new variable meant we couldn't test against the value of the outer variable.
Here shows how we can use match guard to fix this problem.
```rust
fn main() {
let x = Some(5);
let y = 10;
match x {
Some(50) => println!("Got 50"),
Some(n) if n == y => println!("Matched, n = {n}"),
_ => println!("Default case, x = {x:?}"),
}
println!("at the end: x = {x:?}, y = {y}");
}
```
Output
```
Default case, x = Some(5)
at the end: x = Some(5), y = 10
```
The pattern in the second match arm doesn't introduce a new variable `y` that would shadow the outer `y`.
This means that we can use the outer `y` in the match guard.
Instead of specifying the pattern as `Some(y)`, which would have shadowed the outer `y`, we specify `Some(n)`.
This creates a new variable `n` that doesn't shadow anything because there is no `n` variable outside the `match`.
The match guard `if n == y` is not a pattern and therefore doesn't introduce new variables.
This `y` *is* the outer `y` rather than a new `y` shadowing it.
We can look for a value that has the same value as the outer `y` by comparing `n` to `y`.
You can also use the *or* operator `|` in a match guard to specify multiple patterns.
The match guard condition will apply to all the patterns.
Here shows the precedence when combining a pattern uses `|` with a match guard.
The important part of this example is that the `if y` match guard applies to `4`, `5`, and `6`, even though it might look like `if y` only applies to `6`.
```rust
let x = 4;
let y = false;
match x {
4 | 5 | 6 if y => println!("yes"),
_ => println!("no"),
}
```
This match condition states that the arm only matches if the if the value of `x` is equal to `4`, `5`, or `6` *and* if `y` is `true`.
When this runs, the pattern of the first arm matches because `x` is `4`, but the match guard `if y` is false, so the first arm is not chosen.
The code then moves on to the second arm, which does match and this program prints `no`.
The reason is that the `if` condition applies to the whole pattern `4 | 5| 6`, not only to the last value `6`.
In other words, the precedence of a match guard in relation to a pattern behaves like this
```
(4 | 5 | 6) if y => ...
```
rather than this
```
4 | 5 | (6 if y) => ...
```
After running this, the precedence behavior is evident.
If the match guard applied only to the final value in the list of values specified using the `|` operator, the arm would have matched and the program would have printed `yes`.
## `@` Bindings
The *at* operator `@` lets us create a variable that holds a value at the same time as we are testing that value for a pattern match.
Here we want to test that a `Message::Hello` `id` field is within the range `3..=7`.
We also want to bind that value to the variable `id_variable` so we can use it in the code associated with the arm.
We could name this variable `id`, the same as the field, but for this example we will use a different name.
```rust
enum Message {
Hello { id: i32 },
}
let msg = Message::Hello { id: 5 };
match msg {
Message::Hello {
id: id_variable @ 3..=7,
} => println!("Found an id in range: {id_variable}"),
Message::Hello { id: 10..=12 } => {
println!("Found an id in another range")
}
Message::Hello { id } => println!("Found some other id: {id}"),
}
```
Output
```
Found an id in range: 5
```
By specifying `id_vaariable @` before the range `3..=7`, we are capturing whatever value matched the range while also testing that the value matched the range pattern.
In the second arm, where we only have a range specified in the pattern, the code associated with the arm doesn't have a variable that contains the actual value of the `id` field.
The `id` field's values could have been 10, 11, or 12, but the code that goes with the pattern doesn't know which it is.
The pattern code isn't able to use the value form the `id` field, this is due to us not saving the `id` value in a variable.
In the last arm, where we have specified a variable without a range, we do have the value available to use in the arm's code in the variable named `id`.
The reason is that we have used the struct field shorthand syntax.
But we haven't applied any test to the value in the `id` field in this arm, as we did with the first two arms.
Any value would match this pattern.
Using `@` lets us test a value and save it in a variable within one pattern.

View File

@ -0,0 +1,254 @@
# All the Places Patterns Can Be Used
Patterns pop up in a number of places in Rust.
You use them a lot without realizing it.
## `match` Arms
As discussed in Ch6, we can use patterns in the arms of `match` expressions.
`match` expressions are defined as the keyword `match`, a value to match on, and one or more match arms that consist of a pattern and an expression to run if the value matches that arm's pattern, like this:
```
match VALUE {
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
PATTERN => EXPRESSION,
}
```
Here is an example of a `match` expression from ch6 that matches on an `Option<i32>` value in the variable `x`:
```rust
match x {
None => None,
Some(i) => Some(i + 1),
}
```
The patterns in here are the `None` and `Some(i)` on the left of each arrow.
One requirement for `match` expression is that they need to be *exhaustive* in the sense that all possibilities for the value in the `match` expression must be accounted for.
One way to ensure you have covered every possibility is to have a catchall pattern for the last arm.
For example, a variable name matching any value can never fail and thus covers every remaining case.
The particular pattern `_` will match anything, but it never binds to a variable, so it is often used in the last match arm.
The `_` pattern in more detail in the ["Ignoring Values in a Pattern"]() section.
## Conditional `if let` Expressions
In Ch6 we discussed how to use `if let` expressions mainly as a shorter way to write the equivalent of a `match` that only matches o one case.
Optionally `if let` can have a corresponding `else` containing code to run if the pattern in the `if let` doesn't match.
In this example it shows that it is also possible to mix and match `if let`, `else if` and `else if let` expressions.
This gives us more flexibility than a `match` expression in which we can express only one value to compare with the patterns.
Rust doesn't require that the conditions in a series of `if let`, `else if`, `else if let` arms relate to each other.
This code determines what color to make your background based on a series of checks for several conditions.
For example, we have created variables with hardcoded values that a real program might receive form user input.
```rust
fn main() {
let favorite_color: Option<&str> = None;
let is_tuesday = false;
let age: Result<u8, _> = "34".parse();
if let Some(color) = favorite_color {
println!("Using your favorite color, {color}, as the background");
} else if is_tuesday {
println!("Tuesday is green day!");
} else if let Ok(age) = age {
if age > 30 {
println!("Using purple as the background color");
} else {
println!("Using orange as the background color");
}
} else {
println!("Using blue as the background color");
}
}
```
Output
```
Using purple as the background color
```
If the user specifies a favorite color, that color is used as the background.
If no color is specified and today is Tuesday, the background is green.
If the user specifies their age as a string and we can parse it as a number successfully, the color is either purple or orange depending on the value of the number.
If none of the conditions apply, the background is blue.
This conditional structure lets us support complex requirements.
You can see that `if let` can also introduce new variables which shadow existing variables in the same way that `match` arms can.
The line `if let Ok(age) = age` introduces a new `age` variable that contains the `Ok` variant, shadowing the existing `age` variable.
This means we need to place the `if age > 30` condition within that block.
We cannot combine these two conditions into `if let Ok(age) = age && age > 30`.
The new `age` we want to compare to 30 isn't valid until the new scope starts with the curly bracket.
The downside of using `if let` expressions is that the compiler doesn't check for exhaustiveness, whereas with `match` expressions it does.
If we omitted the last `else` block and therefore missed handling some cases, the compiler would not alert us to the possible logic bug.
## `while let` Conditional Loops
Similar to the construction of `if let`, the `while let` conditional loop allows a `while` loop to run for as long as a pattern continues to match.
We first saw this in Ch17, where we used it to keep looping as long as a stream produced new values.
Similarly here we show a `while let` loop that waits on messages sent between threads, but in this case checking a `Result` instead of an `Option`.
```rust
let (tx, rx) = std::sync::mpsc::channel();
std::thread::spawn(move || {
for val in [1, 2, 3] {
tx.send(val).unwrap();
}
});
while let Ok(value) = rx.recv() {
println!("{value}");
}
```
This example will print 1, 2, and 3.
When we saw `recv` back in Ch16, we unwrapped the error directly, or interacted with it as an iterator using a `for` loop.
Here shows we can also use `while let`, because the `recv` method returns `Ok` as long as the sender is producing messages and then produces an `Err` once the sender side disconnects.
## `for` Loops
In a `for` loop, the value that directly follows the keyword `for` is a pattern.
This example demonstrates how to use a pattern in a `for` loop to destructure or break apart, a type as part of the `for` loop.
```rust
let v = vec!['a', 'b', 'c'];
for (index, value) in v.iter().enumerate() {
println!("{value} is at index {index}");
}
```
Output
```rust
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.52s
Running `target/debug/patterns`
a is at index 0
b is at index 1
c is at index 2
```
We adapt an iterator using the `enumerate` method so it produces a values and the index for that value, placed into a tuple.
The first value produced is the tuple `(0, 'a')`.
When this value is matched to the patter `(index, value)`, `index` will be `0` and `value` will be `'a'`, printing the first line out the output.
## `let` Statements
Prior to this ch, we only discussed using patterns with `match` and `if let`, but in fact, we have used patterns in other places as well.
This includes `let` statements.
For example consider this straightforward variable assignment with `let`
```rust
let x = 5;
```
Every time you used a `let` statement like this you have been using patterns, although you might not have realized it.
More formally, a `let` statement looks like this
```
let PATTERN = EXPRESSION;
```
In statements like `let x = 5;` with a variable name in the `PATTERN` slot.
The variable name is just a particularly simple form of a pattern.
Rust compares the expression against the pattern and assign any names it finds.
So in the `let x = 5;` example `x` is a pattern that means "bind what matches here to the variable `x`."
Because the name `x` is the whole pattern, this pattern effectively means "bind everything to the variable `x`, whatever the values is."
To see the pattern matching aspect of `let` more clearly, consider this, which uses a pattern with `let` to destructure a tuple.
```rust
let (x, y, z) = (1, 2, 3);
```
Here we match a tuple against a pattern.
Rust compares the value `(1, 2, 3)` to the pattern `(x, y, z)` and sees that the value matches the pattern.
Rust binds `1` to `x`, `2` to `y`, and `3` to `z`.
You can think of this tuple pattern as nesting three individual variable patterns inside it.
If the number of elements in the pattern doesn't match the number of elements in the tuple, the overall type won't match and we will get a compiler error.
Here shows an attempt to destructure a tuple with three elements into two variables, this will not work.
```rust
let (x, y) = (1, 2, 3);
```
Here is the compiler error form attempting to compile
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0308]: mismatched types
--> src/main.rs:2:9
|
2 | let (x, y) = (1, 2, 3);
| ^^^^^^ --------- this expression has type `({integer}, {integer}, {integer})`
| |
| expected a tuple with 3 elements, found one with 2 elements
|
= note: expected tuple `({integer}, {integer}, {integer})`
found tuple `(_, _)`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
In order to fix this error, we could ignore one or more of the values in the tuple using `_` or `..`
You will see this in the ["Ignoring Values in a Pattern"]()
If the problem is that we have too many variables in the pattern, the solution is to make the types match by removing variables so the number equals the number of elements in the tuple.
## Function Parameters
Function parameter can also be patterns.
The code here, which declares a function named `foo` that takes one parameter named `x` of type `i32`, should by now look familiar.
```rust
fn foo(x: i32) {
// code goes here
}
```
The `x` part is a pattern.
As we did with `let` we could match a tuple in a function's arguments to the pattern.
In this next example, this splits the values in a tuple as we pass it to a function.
```rust
fn print_coordinates(&(x, y): &(i32, i32)) {
println!("Current location: ({x}, {y})");
}
fn main() {
let point = (3, 5);
print_coordinates(&point);
}
```
This code prints `Current loaction: (3, 5)`.
The values `&(3, 5)` match the pattern `&(x, y)`, so `x` is the value `3` and `y` is the value `5`.
We can also use patterns in closure parameter lists in the same way as in function parameter lists, because closure are similar to functions (discussed in Ch 13).
Now we have seen several ways of using patterns, but patterns don't work the same in every place we can use them.
In some places, the patterns must be irrefutable; other circumstances, they can be refutable.
This will be discussed in the next section [Here](./Refutability.md)

453
Publishing libraries.md Normal file
View File

@ -0,0 +1,453 @@
# Publishing a Crate to Crates.io
We have used packages form [crates.io](http://crates.io) as dependencies of our pojects.
You could also share your code with others by publishing your own packages.
The crate regsitry at [crates.io](http://crates.io) distributes the source code of your packages, it primarily hosts code that is open source.
Rust and Cargo have features that make your published package easier for people to find and use.
These features will be covered later and then explaining how to publish a package
## Making Useful Documentation Comments
Accurately documenting your packages will others know how and when to use them.
It is worth investing the time to write documentation
In ch we said that to comment in Rust you use two slashes, `//`
Rust also has a pariticualr kind of comment for documentation.
This is known conveniently as a *documentation comments*, that will generate HTML documentation.
The HTML diesplays the contents of documentation comments for public API items intended for programmers interested in knowing how to use your crate as opposed to how your crate is *implemented*.
The documentation comments uses three slashes `///` instead of two and this supports Markdown notation for formatting the text.
The placement of documentation comments just before the item they are documenting.
Here is an example of documentation comments for an `add_one` function in a crate named `my_crate`.
```rust
/// Adds one to the number given.
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
Here we first give a description of what the `add_one` function does.
Then we add a section starting with the heading `Examples`, and then provide code that demonstrates how to use the `add_one` function.
We can generate te HTML documentation from this documentation comment by running `cargo doc`.
This command runs the `rsutdoc` tool which comes distributed with Rust and pts the generated HTML documentation in the *target/doc* directory.
For convenience running `cargo doc --open` will build the HTML for your current crate's documentation as well as the documentation for all of your crate's dependencies then it will open the result in a web browser.
Navigating to the `add_one` function you will see how the texxt in the documentation comments is rendered as shown below
<img src="https://doc.rust-lang.org/book/img/trpl14-01.png" />
### Commonly Used Sections
We previously used the `# Examples` Markdown heading to create a section in the HTML with the titl "Examples".
Here are some other secions that crate author commonly use in the documentation
- **Panics**: The scenarios in which the function being documented could panic.
Funtion callers who don't want thier programs to panic should make sure they dont call the function in this way/situation
- **Errors**: If the function returns a `Result`, that describes the kinds of errors that may occur and what conditions might cause those errors to be returned.
This can be helpful to caller so that they can write code to handle different kinds of errors in different ways.
- **Safety**: If the function is inheritly `unsafe` to call, there should be a section explaing why the function is unsafe and covering the invariants that the function expects callers to uphold.
Most documentation comments don't need all of these sctions but this is a good checklist ot remind you of the aspects of your code users will be interested in knowing.
### Documentation Comments as Tests
Adding example code blocks in your documentation comments can help demonstrate how to use the library.
Doing so also has an addtional bonus: running `cargo test` will run the code examples in your documentation as tests
This ensures that your examples will be tested to work, because that would be the worst to ship an example that doesn't work.
If we run `cargo test` with the documentation for `add_one` function we would get this output
```
Doc-tests my_crate
running 1 test
test src/lib.rs - add_one (line 5) ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.27s
```
Now if we change either the function or the example so the `assert_eq!` in the example panics, then we will see that the doc tests catch that the example and the code are out of sync with each other.
### Commenting Contained Items
The style of commnet `//!` adds documentation to the item that contains the comments rather than to the items following the comments.
We typically use these doc comments inside the crate root file (src/lib.rs by convention) or inside a module to document the crate or the module as a whole.
For example, adding documentation that describes the purpose of the `my_crate` that contains the `add_one` function
We add documentation comments qith `//!` to the beginning of the *src/lib.rs* file
Here is an example of this
```rust
//! # My Crate
//!
//! `my_crate` is a collection of utilities to make performing certain
//! calculations more convenient.
/// Adds one to the number given.
// --snip--
///
/// # Examples
///
/// ```
/// let arg = 5;
/// let answer = my_crate::add_one(arg);
///
/// assert_eq!(6, answer);
/// ```
pub fn add_one(x: i32) -> i32 {
x + 1
}
```
Notice that there isn't any code after the last line that begins with `//!`
Because we started the comments with `//!` instead of `///` , this inidcates we are documenting the item that contains this comment rather than an item that follows his comment.
In this case, that item is the *src/lib.rs* file which is the crate root.
These comments describe the entire crate
When we run `cargo doc --open`, these comments will display on the front page of the documentation for `my_crate` above the list of public items in the crate
Here is what the docs would look like
<img src="https://doc.rust-lang.org/book/img/trpl14-02.png" />
Documentation comments within items are useful for describing crates and modules especially.
Use them to explain the overall purpose of the container to help your users understand the crate's organization
## Exporting a Convenient Public API with `pub use`
The structure of your public API is a major consideration when publishing a crate.
People who use your crate are less familiar with the structure than you.
They might have difficulty finding the pieces they want to use if your crate has a large moudle hierarchy
Before we covered how to make items public using the `pub` keyword and bring items into a scope iwth the `use` keyword.
The structure that makes sense to you while you are developing the crate might not be very useful or convenient for your users.
You might want to organize your structs in a heirary containing multiple levels.
The people who want to use a type you have defined deep in the hierary might have trouble finding out that tpye exists.
They might also be annoyed having to enter `use` `my_crate::some_module::another_module::UsefulType;` rather than `use` `my_crate::UsefulType;`.
The good news is that if the struct isn't convenient for others to use from another library, you dont have to rearrange your interal organization.
You can instead re-export items to make a public structure that is different form your private structure by using `pub use`.
Re-exporting takes a public item in one location and makes it public in another location as if it we defined in the other location instead
For example lets say we made a libarary named `art`
Within this library there are two modules:
- a `kinds` module containing two enums named `PrimaryColor` and `SecondaryColor`
- a `utils` module containinga function named `mix`
Here is what it would look like in *src/lib.rs*
```rust
//! # Art
//!
//! A library for modeling artistic concepts.
pub mod kinds {
/// The primary colors according to the RYB color model.
pub enum PrimaryColor {
Red,
Yellow,
Blue,
}
/// The secondary colors according to the RYB color model.
pub enum SecondaryColor {
Orange,
Green,
Purple,
}
}
pub mod utils {
use crate::kinds::*;
/// Combines two primary colors in equal amounts to create
/// a secondary color.
pub fn mix(c1: PrimaryColor, c2: PrimaryColor) -> SecondaryColor {
// --snip--
}
}
```
Here is what the frontpage docs generated by `cargo doc` would look like
<img src="https://doc.rust-lang.org/book/img/trpl14-03.png" />
Notice that the `PirmaryColor` and `SecondaryColor` types are't listed on the front page nor is the `mix` function.
We have to navigate to `kinds` and `utils` to see them.
Another crate that depends on this library would need `use` statements that bring items from `art` into scope. Specifying the module structure that is currently defined
Here is an example of a crate that uses the `PrimaryColor` and `mix` items form the `art` crate
```rust
use art::kinds::PrimaryColor;
use art::utils::mix;
fn main() {
let red = PrimaryColor::Red;
let yellow = PrimaryColor::Yellow;
mix(red, yellow);
}
```
The author of the code in above which uses the `art` crate had to figure out that `PrimaryColor` is in the `kinds` module and `mix` is in the `utils` module.
The module struct of the `art` crate is more relevant to developers working on the `art` rate than to those using it.
The internal structure doesn't contain any useful info for someone trying to understand how to use the `art` crate, but rather causes confusion becasue devs who use it have to figure out where to look and must specify the module names in the `use` statements.
To remove the interal organization from the public API, we can modify the `art` crate to add `pub use` statements to re-export the items at the top level
```rust
//! # Art
//!
//! A library for modeling artistic concepts.
pub use self::kinds::PrimaryColor;
pub use self::kinds::SecondaryColor;
pub use self::utils::mix;
pub mod kinds {
// --snip--
}
pub mod utils {
// --snip--
}
```
The API docs that `cargo doc` generates for this crate will now list and link re-exprots on the front page.
This makes the `PrimaryColor` and `SecondaryColor` types and makes finding the `mix` function easier
<img src="https://doc.rust-lang.org/book/img/trpl14-04.png" />
The `art` crate users can still see the internal structure as demonstrated in the picture above.
They could also use the more convenient structure like in the example below
```rust
use art::mix;
use art::PrimaryColor;
fn main() {
// --snip--
}
```
In cases where there are many nested modules, re-exporting the types at the top level with `pub use`.
This can make a very significant difference in the experience of people who use the crate.
Another common use of `pub use` is to re-export definitions of a dependency in the current crate to make that crate's definitions part of your crate's public API.
Creating a useful public API structure is more of an art than a science.
You can iterate to find the API that works best for your users.
Choosing `pub use` gives you flexibility in how you structure your crate internally and decouples that interanl struct from what you present to your users.
Look at some of the code of crates you have used previously to see if their internal struct differs from their public API.
## Setting Up a Crates.io Account
Before being able to publish creates, you need an account on [crates.io](https://crates.io) and get an API toekn
You can do ths by
1. visit the homepage at [crates.io](https://crates.io)
2. Log in via a Github account (could use any other type that is supported)
3. Once logged in, go to your account settings at [https://crates.io/me/](https://crates.io/me/)
4. Retrieve your API key
5. Run the `cargo login` command nad paste the API key when prompted
Here is an example
```
$ cargo login
abcdefghijklmnopqrstuvwxyz012345
```
This will inform Cargo of your API token and store it locally in *~/.cargo/credentials*
Note that this tken is a *secret*. DO NOT SHARE IT
You can revoke it and generate a new token on [crate.io](https://crates.io) if you do accidentally share it.
## Adding Metadata to a New Crate
Lets say you gave a crate you want ot publish.
Before doing that you need to add some metadata in the `[package] section of the crate's *Cargo.toml* file.
You need a unqiue crate name.
When working locally you can name a crate anything you like.
However crate names on [crates.io](https://crates.io) are allocated on a first-come, first-serverd basis.
Once a crate name is taken, no one else can publish a crate with that same name.
SUPER GOOD ADVICE: Before attempting to publish a crate search for the name you want to use.
If the name has been used, you will need to find another name and edit the `name` field in the *Cargo.toml* file under the `[package]` section to use the new name for publishing.
Here is an example of this
```toml
[package]
name = "guessing_game"
```
Even if you chose a unqiue name when you run `cargo publish` to publish the crate at this point you will get a warning then an error.
Here is an example of this output
```
$ cargo publish
Updating crates.io index
warning: manifest has no description, license, license-file, documentation, homepage or repository.
See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
--snip--
error: failed to publish to registry at https://crates.io
Caused by:
the remote server responded with an error (status 400 Bad Request): missing or empty metadata fields: description, license. Please see https://doc.rust-lang.org/cargo/reference/manifest.html for more information on configuring these field
```
These errors are caused by missing some crucial information:
- A description
- A license
Both of these are required so people will know what your crate does and under what terms they can use it.
In *Cargo.toml* add a description that that is a sentence or two. This will appear with your crate in search results.
For the `license` field you need to give a *license identifier value*
The [Linux Foundations Software Package Data Exchange (SPDX)](https://spdx.org/licenses/) lists identifers you can use for this value.
For example to specify that you are licensing your crate using the MIT License add the `MIT` identifier
```toml
[package]
name = "guessing_game"
license = "MIT"
```
If you want to use a license that isnt in te SPDX, you will need to plcae the text of that license in a file.
Include that file in your porject and then use `license-file` to specify the name of that file instead of using the `license` key.
Guidance on which license is appropriate for your project is a highly personal and higly techincal.
Please read through the license to pick the most approprate one for your case use with any considerations to dependances.
Many people in the Rust community license their projects in the same way as Rust by using a dual license of `MIT OR Apache-2.0`
This demonstrates that you can also specify multiple license identifiers separated by `OR` to have multiple licenses for your project.
With a unique name, the version, the description and a license added. The *Cargo.toml* file for a project that is ready to publish would look similar to this:
```toml
[package]
name = "guessing_game"
version = "0.1.0"
edition = "2021"
description = "A fun game where you guess what number the computer has chosen."
license = "MIT OR Apache-2.0"
[dependencies]
```
[Cargo's documentation](https://doc.rust-lang.org/cargo/) describes other metadata you can specify to ensure othes can discover and use your crate more easily.
## Publishing to Crates.io
Now that you have an account, cargo has saved your API otken, chosen a name for your crate and specified the required metadata. Yuo are ready to publish.
Publishing a crate uploads a specific version to [crates.io](https://crates.io) for others to use.
A Publish is *PERMANENT*.
The version can never be overwritten and the code cannot be deleted.
One major goal of [crates.io](https://crates.io) is to act as a permanent archive of code so that builds of all projects that depend on crates from [crates.io](https://crates.io) will continue to always work.
Allowing version deletions would make this goal impossible.
There is no limit to the number of crate versions you can publish.
If you run `cargo publish` again it should succeed now.
Here is the output now
```
$ cargo publish
Updating crates.io index
Packaging guessing_game v0.1.0 (file:///projects/guessing_game)
Verifying guessing_game v0.1.0 (file:///projects/guessing_game)
Compiling guessing_game v0.1.0
(file:///projects/guessing_game/target/package/guessing_game-0.1.0)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.19s
Uploading guessing_game v0.1.0 (file:///projects/guessing_game)
```
This is a successful output and indicates you have successfully shared your code with the Rst community and now anyone can easily add your crate as a dependency of their project.
## Publishing a New Version of an Exisiting Crate
When you made changes to your crate and are ready to release a new version.
First you change the `version` value specified in your *Cargo.toml* file and republish.
Use [Semantic Versioning rules](http://semver.org/) to decide what an appropriate nexxt version based on the kinds of changes made.
Finally run `cargo publish` to upload a new version
### Deprecaitng Versions for mCrates.io with `cargo yank`
Even though you can remove previous versions of a crate, you can prevent any future projects fom adding them as a new dependency.
This is useful when a crate version is broken for some reason.
In such situations, Cargo supports *yanking* a crate version.
Yanking a version prevents new projects form depending on that version while allowing all exisitng projects to continue to depend on that version.
This essentially means a yank won't break any exisiting projects with a *Cargo.lock* with that version will not break. But any new *Cargo.lock* files generated will not be able to use the yanked version.
To yank a version of a create.
1. Go to the directory of the crate that has been previously publish.
2. Run `cargo yank` and specify which version to yank.
For example lets say we have published a create named `guessing_game` version 1.0.1 and we want to yank it.
In the project directory for the `guessing_game` crate we would run
```
$ cargo yank --vers 1.0.1
Updating crates.io index
Yank guessing_game@1.0.1
```
If we wanted to undo that we would add `--undo` to the command.
This would allow prjects to start depending on that version again
```
$ cargo yank --vers 1.0.1 --undo
Updating crates.io index
Unyank guessing_game@1.0.1
```
ONCE AGAIN NOTICE a yank does *NOT* delete any code.
If you accidentally uploaded secrets, you must reset those secrets immediately.

505
Ref Cell Mutability.md Normal file
View File

@ -0,0 +1,505 @@
# `RefCell<T>` and the Interior Mutability Pattern
*Interior mutability* is a design pattern in Rust that allows for you to mutate data even when there are immutable references to the data.
This is normally not allowed due to Rust's strict borrowing rules.
To mutate data, the pattern uses `unsafe` code inside a data structure to allow for this to happen even though Rust's usual rules that govern mutation and borrowing.
Unsafe will be covered later.
Unsafe code indicates that we are checking the rules manually and not the compiler , this is instead of relying on the compiler to check for us.
We can use types that use interior mutability pattern only when we can ensure that the borrowing rules will be followed at runtime.
This is despite the compiler being unable to ensure that the borrowing rules are followed.
One example of interior mutability pattern is the `RefCall<T>`.
We will be exploring this structure.
## Enforcing Borrowing Rules at Runtime with `RefCell<T>`
Unlike `Rc<T>`, `RefCell<T>` type represents single ownership over the data it holds.
This makes `RefCell<T>` similar to `Box<T>` but it has some differences.
Here is a recall of the borrowing rules so that we can then explain the difference between the two.
- At any given time, you can have *either* (not both) one mutable reference or nay number of immutable references.
- References must always be valid
With `Box<T>` and references, the borrowing rules' invariants are enforced at compile time.
With `RefCell<T>`, these invariants are enforced *at runtime*.
With references if you break the borrowing rules, you get a compiler error.
With `RefCell<T>` if you break the rules, your program will panic and exit.
The advantage of checking at compile time is that you will catch errors sooner in the development process and there is no impact to runtime performance.
This is due to all of the analysis is completed before.
This is why checking the borrow rules at compile time is the best choice in the majority of cases.
Hence why it is Rust's default.
Due to some of this analysis being impossible, the Rust compiler can't be sure that the code complies with the ownership rules, it can reject the program.
This would be a very conservative approach.
If Rust accepted a incorrect program, users wouldn't be able to trust in the guarantees Rusts makes.
Instead if Rust rejects a correct program, the programmer will be inconvenienced, but nothing drastic or catastrophic can occur.
`RefCell<T>` type is useful when you are sure your code follows the borrowing rules, the compiler is unable to understand and guarantee that.
`RefCell<T>` is similar to `Rc<T>` in regards to the fact that it is used in single-threaded cases.
It will give a compile-time error if you attempt to use it in a multithreaded cases.
We will discuss later how to get the same functionality of `RefCell<T>` in a multithreaded application.
Here are the reasons to choose `Box<T>`, `Rc<T>`, or `RefCell<T>`
- `Rc<T>` enables multiple owners of the same data
- `Box<T>` and `RefCell<T>` has single owners
- `Box<T>` allows immutable or mutable borrows checked at compile time
- `Rc<T>` allows only immutable borrows checked at compile time
- `RefCell<T>` allows immutable or mutable borrows checked at runtime
- Due to `RefCell<T>` allowing mutable borrows to be checked at runtime, you are able to mutate the value inside the `RefCell<T>` even when the `RefCell<T>` is immutable.
Mutating the value inside an immutable value is the *interior mutability* pattern.
Now we will look at a situation where interior mutability is useful and examine how it is possible.
## Interior Mutability: A Mutable Borrow to an Immutable Value
One consequence of the borrowing rules is that when you have an immutable value, you can't borrow it mutably.
One example of this is the code below it will not compile
```rust
fn main() {
let x = 5;
let y = &mut x;
}
```
You would get this compilation output for this type of error
```
$ cargo run
Compiling borrowing v0.1.0 (file:///projects/borrowing)
error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable
--> src/main.rs:3:13
|
3 | let y = &mut x;
| ^^^^^^ cannot borrow as mutable
|
help: consider changing this to be mutable
|
2 | let mut x = 5;
| +++
For more information about this error, try `rustc --explain E0596`.
error: could not compile `borrowing` (bin "borrowing") due to 1 previous error
```
There are situations where it would be useful for a value to mutate itself in its methods but also appear immutable to other code.
Then using `RefCell<T>` is one way to get the ability to have interior mutability.
Another reminder that `RefCell<T>` doesn't get around the borrowing rules completely.
The borrow checker in the compiler allows for this interior mutability and the borrowing rules are checked at runtime instead.
If you violate those rules, you will get a `panic!` instead of a compilation error.
Next we will go though a practical example where we can use `RefCell<T>` to mutate an immutable and see its usefulness.
### A Use Case for Interior Mutability: Mock Objects
Sometimes during tests a programmer will use a type in place of another type.
In order to observe a particular behavior and assert it is implemented correctly.
This placeholder type is called a *test double*.
This is often thought of as a "stunt double" in filmmaking, where a person substitutes for an actor to a particularly tricky scene.
Test doubles stand in for other types when running tests.
*Mock objects* are specific types of test doubles that record what happens during a test so that you can assert that the correct action(s) took place.
Rust doesn't have objects in in the same vain as other languages have objects.
Rust doesn't have mock objects functionality built into the std library like other languages do.
You can create a struct that will serve the same purpose as a mock object.
In this case we will test.
We will create a library that tracks a value against a maximum value and sends messages based on how close to the maximum value the current value is.
The library could be used to keep track of a user's quota for the number of API calls they are allowed to make, as an example.
This library will only provide the functionality of tracking how close to the maximum a value is and what the messages should be at what times.
Applications that use the library will be expected to provide the mechanism for sending the messages.
The application could put a message in the application, send an email, send a text message, or something else.
The library doesn't need to know what kind of message it is.
All it needs is something that implements a trat we will provide called `Messenger`.
```rust
pub trait Messenger {
fn send(&self, msg: &str);
}
pub struct LimitTracker<'a, T: Messenger> {
messenger: &'a T,
value: usize,
max: usize,
}
impl<'a, T> LimitTracker<'a, T>
where
T: Messenger,
{
pub fn new(messenger: &'a T, max: usize) -> LimitTracker<'a, T> {
LimitTracker {
messenger,
value: 0,
max,
}
}
pub fn set_value(&mut self, value: usize) {
self.value = value;
let percentage_of_max = self.value as f64 / self.max as f64;
if percentage_of_max >= 1.0 {
self.messenger.send("Error: You are over your quota!");
} else if percentage_of_max >= 0.9 {
self.messenger
.send("Urgent warning: You've used up over 90% of your quota!");
} else if percentage_of_max >= 0.75 {
self.messenger
.send("Warning: You've used up over 75% of your quota!");
}
}
}
```
One important part to notice is that the `Messenger` trait has one method called `send`.
This takes an immutable reference to `self` and the text of the message.
This trait is the interface our mock object needs to implement so that the mock can be used in the same way a real object is.
The other important part is that we want to test the behavior of the `set_value` method on the `LimitTracker`
Then we can change what we pass in for the `value` parameter, but `set_value` doesn't return anything for us to make a assertion on.
We want to be able to say if we create a `LimitTracker` with something that implements the `Messenger` trait and a particular value for `max`, when we pass different numbers for `value`.
The messenger is told to send the appropriate messages.
We need a mock object.
Instead of sending an email or text message when `send` is called, we will only keep track of the messages it's told to send.
We can create a new instance of the mock, then create a `LimitTracker` that uses the mock, call `set_value` method on `LimitTracker` and finally check that the mock has the messages we expect.
Here is an example that was an attempt to implement a mock object to do just that, but the borrow checker will not allow for it.
```rust
#[cfg(test)]
mod tests {
use super::*;
struct MockMessenger {
sent_messages: Vec<String>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: vec![],
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
let mock_messenger = MockMessenger::new();
let mut limit_tracker = LimitTracker::new(&mock_messenger, 100);
limit_tracker.set_value(80);
assert_eq!(mock_messenger.sent_messages.len(), 1);
}
}
```
Here the test code defines a `MockMessenger` struct that has a `sent_messages` field with a `Vec` of `String` values to keep track of the sent messages.
We also define an associated function `new`, this makes it convenient ot create new `MockMessenger` values that start with an empty list of messages.
Then we implement the `Messenger` trait for `MockMessenger` so that we can give a `MockMessenger` to a `LimitTracker`.
In the definition of `send`, we take the message passed in as a message passed in as a parameter and store it in the `MockMessenger` list of `sent_messages`.
Now in the test we are testing what happens when the `LimitTracker` is told to set `value` to something that is more than 75 percent of the `max` value.
First we create a new `MockMessenger`, this will start with a empty list of messages.
We then create a `LimitTracker` and we give it a reference to the `MockMessenger` and a `max` value of 100.
We call the `set_value` method in the `LimitTracker` with a value of 80.
This is more than 75% of 100.
We finally assert that the list of messages that the `MockMessenger` is keeping track of should now have one message in it.
There is one problem with this test, here is the output from running the test
```
$ cargo test
Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker)
error[E0596]: cannot borrow `self.sent_messages` as mutable, as it is behind a `&` reference
--> src/lib.rs:58:13
|
58 | self.sent_messages.push(String::from(message));
| ^^^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be borrowed as mutable
|
help: consider changing this to be a mutable reference in the `impl` method and the `trait` definition
|
2 ~ fn send(&mut self, msg: &str);
3 | }
...
56 | impl Messenger for MockMessenger {
57 ~ fn send(&mut self, message: &str) {
|
For more information about this error, try `rustc --explain E0596`.
error: could not compile `limit-tracker` (lib test) due to 1 previous error
```
Since we can't modify the `MockMessenger` to keep track of the messages.
Due to the `send` method taking in an immutable reference to `self`.
We also can't take the suggestion from the error text to use `&mut slef` in both the `impl` method and the `trait` def.
We do not want to change the `Messenger` trait only for the sake of testing.
Instead we should find a way to make our test code work without changing the existing design.
Interior mutability would be highly useful in this situation.
We will store the `sent_messages` within a `RefCell<T>`, then the `send` method will then be able to modify `sent_messages` the messages.
Here it wat it would look like with this new definition
```rust
#[cfg(test)]
mod tests {
use super::*;
use std::cell::RefCell;
struct MockMessenger {
sent_messages: RefCell<Vec<String>>,
}
impl MockMessenger {
fn new() -> MockMessenger {
MockMessenger {
sent_messages: RefCell::new(vec![]),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
self.sent_messages.borrow_mut().push(String::from(message));
}
}
#[test]
fn it_sends_an_over_75_percent_warning_message() {
// --snip--
assert_eq!(mock_messenger.sent_messages.borrow().len(), 1);
}
}
```
Now `sent_messages` is a type `RefCell<Vec<String>>` instead of using a `Vec<String>`.
Now in the `new` function we create a new empty vector of `RefCell<Vec<String>>` instance.
For the implementation of the `send` method, the first parameter is still an immutable borrow of `self`, this matches the trait definition.
We can call `borrow_mut` on the `RefCell<Vec<String>>` in `self.sent_messages` to get a mutable reference to the vector inside the `RefCell<Vec<String>>`.
Next we can call `push` on the mutable reference to the vector to keep track of the messages sent during the test.
The last change we need to make is in the assertion.
We need to see how many items are in the inner vector, we call `borrow` on the `RefCell<Vec<String>>` to get an immutable reference to the vector.
Now we will dig into how it works.
### Keeping Track of Borrows at Runtime with `RefCell<T>`
Creating immutable and mutable references, we use `&` and `&mut` syntax.
With `RefCell<T>`, we use `borrow` and `borrow_mut` methods.
These are part of the safe API that belongs to `RefCell<T>`.
The `borrow` method returns the smart pointer type `Ref<T>`.
The `borrow_mut` method returns the smart pointer type `RefMut<T>`.
Both types implement the `Deref`, so they can be treated like regular references.
`RefCell<T>` keeps track of how many `Ref<T>` and `RefMut<T>` smart pointers are currently active.
Every time we call `borrow`, the `RefCell<T>` increases its count of how many immutable borrows are active.
When a `Ref<T>` value/"reference" goes out of scope, the count of immutable borrows goes down by 1.
`RefCell<T>` uses the same rules are the borrowing rules, it allows you to have many immutable borrows or one mutable borrow at any point in time.
If we violate the rules, rather than getting a compiler error as we would with references, the implementation of `RefCell<T>` will panic at runtime.
This example shows a modification of the `send` implementation.
Here we are deliberately trying to create two mutable borrows active for the same scope to illustrate that `RefCell<T>` prevents us from doing this at runtime.
```rust
impl Messenger for MockMessenger {
fn send(&self, message: &str) {
let mut one_borrow = self.sent_messages.borrow_mut();
let mut two_borrow = self.sent_messages.borrow_mut();
one_borrow.push(String::from(message));
two_borrow.push(String::from(message));
}
}
```
Here we create the variable `one_borrow` for the `RefMut<T>` smart pointer returned form `borrow_mut`.
We then create a different variable `two_borrow` in the same way as `one_borrow`.
This makes two mutable references in the same scope. **This is not Allowed**.
When we run the tests for our library, the code will compile without errors but the test will fail with this output.
```
$ cargo test
Compiling limit-tracker v0.1.0 (file:///projects/limit-tracker)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.91s
Running unittests src/lib.rs (target/debug/deps/limit_tracker-e599811fa246dbde)
running 1 test
test tests::it_sends_an_over_75_percent_warning_message ... FAILED
failures:
---- tests::it_sends_an_over_75_percent_warning_message stdout ----
thread 'tests::it_sends_an_over_75_percent_warning_message' panicked at src/lib.rs:60:53:
already borrowed: BorrowMutError
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
failures:
tests::it_sends_an_over_75_percent_warning_message
test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
error: test failed, to rerun pass `--lib`
```
Note that the code panicked with the message `already borrowed: BorrowMutError`.
This is how `RefCell<T>` handles violation of the borrowing rules at runtime.
Choosing to catch borrowing violation errors at runtime rather than compile time, this means that you may potentially be finding mistakes in your code at a later point in development.
Even possibly not until your code was deployed to production.
Also your code would have a small runtime performance penalty of keeping track of the borrows at runtime rather than at compile time.
However the benefit of using `RefCell<T>` makes it possible to write a mock object that can modify itself to keep track of the messages it has seen while you are using it in a context where only immutable values are allowed.
`RefCell<T>` despite its trade-offs to get more functionality than regular references provide.
### Having Multiple Owners of Mutable Data by Combining `Rc<T>` and `RefCell<T>`
A common use of `RefCell<T>` is in combination with `Rc<T>`.
`Rc<T>` lets you have multiple owners of some data, but it only gives immutable access to that data.
If you have a `Rc<T>` that holds a `RefCell<T>`, you can get a value that can have multiple owners *and* that you can mutate.
For example recall the cons list form before where we used `Rc<T>` to allow multiple lists to share ownership of another list.
Due to `Rc<T>` only being able to hold immutable values, we are unable to change any of the values in the list once it has been created.
Now lets add a `RefCell<T>` to be able to change the values in the lists.
This is an example where using a `RefCell<T>` in the `Cons` definition we can modify the value stored in all of the lists.
```rust
#[derive(Debug)]
enum List {
Cons(Rc<RefCell<i32>>, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::cell::RefCell;
use std::rc::Rc;
fn main() {
let value = Rc::new(RefCell::new(5));
let a = Rc::new(Cons(Rc::clone(&value), Rc::new(Nil)));
let b = Cons(Rc::new(RefCell::new(3)), Rc::clone(&a));
let c = Cons(Rc::new(RefCell::new(4)), Rc::clone(&a));
*value.borrow_mut() += 10;
println!("a after = {a:?}");
println!("b after = {b:?}");
println!("c after = {c:?}");
}
```
Here we create a value that is an instance of `Rc<RefCell<i32>>` and it is stored in the variable `value` so that it can be accessed lasted.
Next we create a `List` in `a` with a `Cons` variant that holds `value`.
We need to code `value` so both `a` and `value` have ownership of the inner `5` rather than transferring ownership from `value` to `a` or having `a` borrow form value.
Then we wrap `a` in a `Rc<T>` so when we create the lists `b` and `c` then can both refer to `a`. (This is the same as the before example)
After we create `a`, `b`, and `c`, we want to add 10 to the value in `value.
We can do this by calling `borrow_mut` on `value`, which uses the automatic dereferencing feature that was discussed previously.
We use this to dereference the `Rc<T>` to the inner `RefCell<T>` value.
The `borrow_mut` method returns a `RefMut` smart pointer and we use the dereference operator on it and change the inner value.
Finally we print `a`, `b`, and `c` so that we can see that they all have the modified value of 15 rather than 5.
```
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.63s
Running `target/debug/cons-list`
a after = Cons(RefCell { value: 15 }, Nil)
b after = Cons(RefCell { value: 3 }, Cons(RefCell { value: 15 }, Nil))
c after = Cons(RefCell { value: 4 }, Cons(RefCell { value: 15 }, Nil))
```
This is very neat and a very useful technique.
By using `RefCell<T>` we have an outwardly immutable `List` value.
We can then use the methods on `RefCell<T>` that provide access to its interior mutability so we can modify our data when we need to.
The runtime checks of the borrowing rules ensure the protection form data races and it is sometimes worth trading a bit of speed for this level of flexibility in our data structures.
Again Note that `RefCell<T>` does **NOT** work for multithreaded code.
`Mutex<T>` is the tread-safe version of `RefCell<T>`, this will be discussed in the next chapter.

View File

@ -0,0 +1,214 @@
# `RC<T>`, the Reference Counted Smart Pointer
In the majority of times ownership is clear. You always know which variable owns a value.
There are cases when a single value might have multiple owners.
An example of this includes in graph data structures, multiple edges might point to the same node, and that node is conceptually owned by all of the edges that point to it.
A node shouldn't be cleaned up unless it doesn't have any edges pointing to it and so has no owners.
You must explicitly enable multiple ownership by using the Rust type `Rc<T>`, this is a abbreviation for *reference counting*.
This type keeps track of the number of references to a value to determine whether or not the value is still in use.
If there are no references to a value, then the value can be cleaned up without any references becoming invalid.
`Rc<T>` can be pictured as a TV in a family room.
When one person enters to watch the TV, they turn it on.
Others can come into the room and watch the TV.
When the last person leaves the room, they turn it off because it is no longer being used.
If someone turns off the TV while others are still watching it, there would be uproar from the remaining TV watchers.
`Rc<T>` type is used when we want to allocate some data on the heap for multiple parts of our program to read.
We can't determine at compile time which part will finish using the data last.
If we knew which part would finished last, we could just make that part the data's owner and the normal ownership rules enforced at compile time would take effect.
Note that `Rc<T>` is only for use in single-threaded cases.
We discuss later how to do reference counting in multithreaded programs.
## Using `Rc<T>` to Share Data
Lets use the cons list again to exemplify why to use a `Rc<T>`.
Recall that we previously defined it using `Box<T>`.
Now we will create two lists that both share ownership of a third list.
Here is a graph of what it would look like
<img src="https://doc.rust-lang.org/book/img/trpl15-03.svg" />
Here we create a list `a` that contains 5 then 10.
We then create two more lists
- `b` that starts with 3
- `c` that starts with 4
Both `b` and `c` will continue on to the first `a` list containing 5 and 10.
Both lists will share the first list containing 5 and 10.
Trying to implement this with our definition of `List` with `Box<T>` will not work nor compile
```rust
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
let b = Cons(3, Box::new(a));
let c = Cons(4, Box::new(a));
}
```
When we try to compile this code we get this error
```
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
error[E0382]: use of moved value: `a`
--> src/main.rs:11:30
|
9 | let a = Cons(5, Box::new(Cons(10, Box::new(Nil))));
| - move occurs because `a` has type `List`, which does not implement the `Copy` trait
10 | let b = Cons(3, Box::new(a));
| - value moved here
11 | let c = Cons(4, Box::new(a));
| ^ value used here after move
For more information about this error, try `rustc --explain E0382`.
error: could not compile `cons-list` (bin "cons-list") due to 1 previous error
```
The `Cons` variants own the data they hold so when we create the `b` list
`a` is moved into `b` and `b` owns `a`.
We could change the definition of `Cons` to hold a reference instead. We would then have to specify lifetime parameters.
Then by specifying lifetime parameters we would be specifying that every element in the list will live at least as long as the entire list.
This would be the case for the example above, but not in every scenario.
Instead we will change our definition of `List` to use `Rc<T>` in place of `Box<T>`.
Each `Cons` variant will now hold a value and an `Rc<T>` pointing to a `List`.
Now when we create `b`, instead of taking ownership of `a`.
We will clone the `Rc<List>` that `a` is holding, this increases the number of references from 1 -> 2 and letting `a` and `b` share ownership of the data in that `Rc<List>`.
Next we will clone `a` when creating `c`, increasing again the number of references form 2 -> 3.
Every time we call `Rc::clone`, the references count to the data within the `Rc<List>` will increase, and the data will not be cleaned up unless there are zero references to it.
```rust
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
let b = Cons(3, Rc::clone(&a));
let c = Cons(4, Rc::clone(&a));
}
```
We also need to add a `use` statement to bring `Rc<T>` into scope because it is not in the prelude.
Now in main we create the list holding 5 and 10 and store it in a new `Rc<List>` in `a`.
Then we create a `b` and `c`, we call the `Rc::clone` function and pass a reference to the `Rc<List>` in `a` as an arg.
We could have used `a.clone()` rather than `Rc::clone(&a)`.
It is convention in Rust to use `Rc::clone` in this case.
The implementation of `Rc::clone` doesn't make a deep copy of all data, this is unlike most tpyes' implementations of `clone`.
The call to `Rc::clone` only increments the reference count, this doesn't take much time.
Deep copies take much more time than a shallow copy.
By using `Rc::clone` for reference counting, we can visually distinguish between the deep-copy kinds of clines and the kinds of clones that increase the reference count.
When looking for performance problems in the code, we only need to consider the deep copy clones and can disregard class to `Rc::clone`
## Cloning an `Rc<T>` Increases the Reference Count
We will now change the example above to see the reference counts changing as we create and drop references to the `Rc<List>` in `a`
Here we changed it so that there is an inner scope around list `c`.
This is used so that we can see a difference when dropping `c`
```rust
enum List {
Cons(i32, Rc<List>),
Nil,
}
use crate::List::{Cons, Nil};
use std::rc::Rc;
fn main() {
let a = Rc::new(Cons(5, Rc::new(Cons(10, Rc::new(Nil)))));
println!("count after creating a = {}", Rc::strong_count(&a));
let b = Cons(3, Rc::clone(&a));
println!("count after creating b = {}", Rc::strong_count(&a));
{
let c = Cons(4, Rc::clone(&a));
println!("count after creating c = {}", Rc::strong_count(&a));
}
println!("count after c goes out of scope = {}", Rc::strong_count(&a));
}
```
At each point in the program where the ref count changes we print out the count so that we can see it.
We do this by calling the `Rc::strong_count` function.
This is named `string_count` rather than `count` because the `Rc<T>` type also has a `weak_count`.
We will see `weak_count` later.
Here is the output
```
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.45s
Running `target/debug/cons-list`
count after creating a = 1
count after creating b = 2
count after creating c = 3
count after c goes out of scope = 2
```
We cam see that the `a` of type `Rc<List>` has an initial count of 1.
Then each time we call `clone`, it goes up by 1.
When `c` goes out of scope, the count goes down by 1
We don't have to call a function to decrease the reference count like how we have to call `Rc::clone` to increase the ref count.
The implementation of the `Drop` trait decreases the ref count automatically when an `Rc<T>` value goes out of scope.
In this example we can't see what happens when `b` and `a` goes out of scope at the end of `main`, when the count is 0.
The `Rc<List>` is cleaned up completely.
Using `Rc<T>` allows a single value to have multiple owners, and the count ensures that the value remains valid as long as any of the owners still exist.
Using immutable references `Rc<T>` allows you to share data between multiple parts of your program for read only.
If `Rc<T>` allowed for multiple mutable references, you have the possibility of violating borrowing rules.
Multiple mutable borrows to the same place can cause data races and inconsistencies. [Section Reference Here](./ownership.md)
Being able to mutate data is very useful.
The nest section will the interior mutability pattern and the `RefCell<T>` type that you can use in conjunction with an `Rc<T>` to work with this immutability restriction.
It can be found [here](./Ref%20Cell%20Mutability.md).

107
Refutability.md Normal file
View File

@ -0,0 +1,107 @@
# Refutability: Whether a Pattern Might Fail to Match
Patterns come in two forms:
- Refutable
- Irrefutable
Patterns that will match for any possible value passed are *irrefutable*.
An example would be `x` in the statement `let x = 5;` because `x` matches anything and therefore cannot fail to match.
Patterns that can fail to match for some possible value are *refutable*.
An example would be `Some(x)` in the expression `if let Some(x) = a_value` because if the value in the `a_value` variable is `None` rather than `Some`, the `Some(x)` pattern will not match.
Function parameters, `let` statements and `for` loops can only accept irrefutable patterns, because the program cannot do anything meaningful when values don't match.
The `if let` and `while let` expressions and the `let`-`else` statement accept refutable and irrefutable patterns, but the compiler warns against irrefutable patterns.
This is because by definition they are intended to handle possible failure.
The functionality of a conditional is in its ability to perform differently depending on success or failure.
Generally you shouldn't have to worry about the distinction between refutable and irrefutable patterns.
However you do need to be familiar with the concept of refutability so you can respond when you see it in an error message.
In these cases, you will need to change either the pattern or the construct you are using the pattern with, depending on the intended behavior of the code.
Now lets take a look at an example of what happens when you try to use a refutable pattern where Rust requires an irrefutable pattern and vice versa.
Here shows a `let` statement, but for the pattern we have specified `Some(x)`, a refutable pattern.
As expected, this code will not compile.
```rust
let Some(x) = some_option_value;
```
If `some_option_value` was a `None` value, it would fail to match the pattern `Some(x)`, meaning the pattern is refutable.
However, the `let` statement can only accept an irrefutable pattern because there is nothing valid the code can do with a `None` value.
At compile time, Rust will complain that we have tried to use a refutable pattern where an irrefutable pattern is required
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
error[E0005]: refutable pattern in local binding
--> src/main.rs:3:9
|
3 | let Some(x) = some_option_value;
| ^^^^^^^ pattern `None` not covered
|
= note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
= note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
= note: the matched value is of type `Option<i32>`
help: you might want to use `let else` to handle the variant that isn't matched
|
3 | let Some(x) = some_option_value else { todo!() };
| ++++++++++++++++
For more information about this error, try `rustc --explain E0005`.
error: could not compile `patterns` (bin "patterns") due to 1 previous error
```
Because we didn't cover (and couldn't cover) every valid value with the pattern `Some(x)`, Rust rightfully produces a compiler error.
If we have a refutable pattern where an irrefutable pattern is needed, we can fix it by changing the code that uses the pattern.
Instead of using `let`, we can use `if let`.
Then if the code doesn't match, the code will just skip the code in the curly brackets, giving a way to continue validly.
Here shows a fix to the code
```rust
if let Some(x) = some_option_value {
println!("{x}");
}
```
We given the code an out, this code is perfectly valid now.
However, if we give `if let` an irrefutable pattern, such as `x`, the compiler will give a warning.
```rust
if let x = 5 {
println!("{x}");
};
```
Rust complains that it doesn't make sense to use `if let` with an irrefutable pattern
```
$ cargo run
Compiling patterns v0.1.0 (file:///projects/patterns)
warning: irrefutable `if let` pattern
--> src/main.rs:2:8
|
2 | if let x = 5 {
| ^^^^^^^^^
|
= note: this pattern will always match, so the `if let` is useless
= help: consider replacing the `if let` with a `let`
= note: `#[warn(irrefutable_let_patterns)]` on by default
warning: `patterns` (bin "patterns") generated 1 warning
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.39s
Running `target/debug/patterns`
5
```
For this reason, match arms must use refutable patterns, except for the last arm, which should match any remaining values with an irrefutable pattern.
Rust allows us to use an irrefutable pattern in a `match` with only one arm.
This syntax isn't particularly useful and could be replaced with a simpler `let` statement.
Next we will cover all the syntax we can use to create patterns [here](./Pattern%20Syntax.md)

364
Shared State Concurrency.md Normal file
View File

@ -0,0 +1,364 @@
# Shared-State Concurrency
Message passing is not the only way of handling concurrency.
Another way would be multiple threads to access the same shared data.
Consider this part of the slogan form the Go language documentation:
"Do not communicate by sharing memory."
What would communicating by sharing memory look like?
Why would message-passing enthusiasts caution not to use memory sharing.
Channels in any programming language are similar to single ownership, because once you transfer a value down a channel, you should no longer use that value.
Shared memory concurrency is like multiple ownership: multiple threads can access the same memory location at the same time.
As we saw before [Ch15](./Smart%20Pointers.md), where smart pointers made multiple ownership possible.
This can add complexity because these different owners need managing.
Rust's type system and ownership rules majority assist in getting this management correct.
Lets look at one example mutexes, one of the more common concurrency primitives for shared memory.
## Using Mutexes to Allow Access to Data from One Thread at a Time
*Mutex* is an abbreviation for *mutual exclusion*, as in, a mutex allows only one thread to access some data at any given time.
To access the data in a mutex, a thread must first signal that it wants access by asking to acquire the mutex's *lock*.
The lock is a data structure that is part of the mutex that keeps track of who is currently gas exclusive access to the data.
The mutex can be described as *guarding* the data it holds via the locking system.
Mutexes have an associated reputation for being difficult to use because to must remember two rules:
- You must attempt to acquire the lock before using the data
- When you are done with the data that the mutex guards, you must unlock the data so other threads can acquire the lock
A real-world metaphor for a mutex would be like imagining a panel discussion at a conference with only one microphone.
Before a panelist can speak, they have to ask or signal that they want to use the microphone.
When they get the microphone, they can talk for as long as they want to and then hand the microphone to the next panelist who requests to speak.
If a panelist forgets to hand off the microphone off when they they are finished with it, no one else is able to speak.
If management of the shared microphone goes wrong, the panel won't work as planned.
Management of mutexes can be incredibly tricky to get right.
This is why so many people are enthusiastic about channels.
However due to Rust's type system and ownership rules, you can't get locking and unlocking wrong.
### The API of `Mutex<T>`
Here is an example of how to use a mutex.
We will start by using a mutex in a single threaded context.
```rust
use std::sync::Mutex;
fn main() {
let m = Mutex::new(5);
{
let mut num = m.lock().unwrap();
*num = 6;
}
println!("m = {m:?}");
}
```
Just like with many types, we create a `Mutex<T>` using the associated function `new`
To access the data in the data inside the mutex, we use the `lock` method to acquire the lock.
This call will block the current thread so it can't do any work until its our turn to have the lock.
The call to `lock` would fail if another thread holding the lock panicked.
In that case no one would ever be able to get the lock.
Here we chose to `unwrap` and have this thread panic if we are in that situation.
After the acquire the lock we can treat the return value, named `num` in this case as a mutable reference to the data inside.
The type system ensures that we acquire a lock before using the value in `m`.
The type of `m` is `Mutex<i32>`, not `i32`, therefore we *must* call `lock` to be able to use the `i32` value.
The type system won't let us access the inner `i32` otherwise.
`Mutex<T>` is a smart pointer.
More accurately, the call to `lock` *returns* a smart pointer called `MutexGuard`, wrapped in a `LockResult` that we handled with the call to `unwrap`.
The `MutexGaurd` smart pointer implements `Deref` to point at our inner data.
The smart pointer also has a `Drop` implementation that releases the lock automatically when a `MutexGaurd` goes out of scope. This happens at the end of the inner scope.
This results in not risking forgetting to release the lock and blocking the mutex form being used by other threads, because the lock releases happens automatically.
After dropping the lock, we can print the mutex value and see that we are able to change the inner `i32` to 6.
## Sharing a `Mutex<T>` Between Multiple Threads
Here we will try to share a value between multiple threads suing `Mutex<T>`.
We will spin up 10 threads and each will increment a counter by 1.
The counter will go from 0 to 10.
In this example it will give a compiler error and we will use that to learn a bit more about using `Mutex<T>` and how Rust helps us use it correctly.
```rust
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Mutex::new(0);
let mut handles = vec![];
for _ in 0..10 {
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
```
Here we create the `counter` variable which holds an `i32` inside a `Mutex<T>`, just like before.
Then we create 10 threads by iterating over a range of numbers.
We use `thread::spawn` and give all the threads the same closure.
This will moves the counter into the thread, acquires a lock on the `Mutex<T>` by calling the `lock` method, then adding 1 to the value in the mutex.
Finally when a thread finishes running its closure, `num` will go out of scope and release the lock so another thread can acquire it.
Here in the main thread we collect all the join handles.
Then just as we did before we call `join` on each handle to make sure that all the threads finish.
Once all the threads have finished the main thread will acquire the lock and print the result of the program.
Here is the output and compiler error
```
$ cargo run
Compiling shared-state v0.1.0 (file:///projects/shared-state)
error[E0382]: borrow of moved value: `counter`
--> src/main.rs:21:29
|
5 | let counter = Mutex::new(0);
| ------- move occurs because `counter` has type `Mutex<i32>`, which does not implement the `Copy` trait
...
8 | for _ in 0..10 {
| -------------- inside of this loop
9 | let handle = thread::spawn(move || {
| ------- value moved into closure here, in previous iteration of loop
...
21 | println!("Result: {}", *counter.lock().unwrap());
| ^^^^^^^ value borrowed here after move
|
help: consider moving the expression out of the loop so it is only moved once
|
8 ~ let mut value = counter.lock();
9 ~ for _ in 0..10 {
10 | let handle = thread::spawn(move || {
11 ~ let mut num = value.unwrap();
|
For more information about this error, try `rustc --explain E0382`.
error: could not compile `shared-state` (bin "shared-state") due to 1 previous error
```
This error message states that the `counter` value was moved in the pervious iteration of the loop.
Rust is telling us that we can't move the ownership of `counter` into multiple threads.
We will fix this compilation error with a multiple-ownership method discussed previously. [Ch15](./Smart%20Pointers.md)
### Multiple Ownership with Multiple Threads
Previously we gave gave a value multiple owners by using the smart pointer `Rc<T>` to create a reference counted value.
Lets see what happens when we do the same here to see what happens.
We will wrap the `Mutex<T>` in `Rc<T>` and clone the `Rc<T>` before moving ownership to the thread.
```rust
use std::rc::Rc;
use std::sync::Mutex;
use std::thread;
fn main() {
let counter = Rc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Rc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
```
This once again will give us a compilation error, but this is a different compiler error.
```
$ cargo run
Compiling shared-state v0.1.0 (file:///projects/shared-state)
error[E0277]: `Rc<Mutex<i32>>` cannot be sent between threads safely
--> src/main.rs:11:36
|
11 | let handle = thread::spawn(move || {
| ------------- ^------
| | |
| ______________________|_____________within this `{closure@src/main.rs:11:36: 11:43}`
| | |
| | required by a bound introduced by this call
12 | | let mut num = counter.lock().unwrap();
13 | |
14 | | *num += 1;
15 | | });
| |_________^ `Rc<Mutex<i32>>` cannot be sent between threads safely
|
= help: within `{closure@src/main.rs:11:36: 11:43}`, the trait `Send` is not implemented for `Rc<Mutex<i32>>`, which is required by `{closure@src/main.rs:11:36: 11:43}: Send`
note: required because it's used within this closure
--> src/main.rs:11:36
|
11 | let handle = thread::spawn(move || {
| ^^^^^^^
note: required by a bound in `spawn`
--> file:///home/.rustup/toolchains/1.82/lib/rustlib/src/rust/library/std/src/thread/mod.rs:675:8
|
672 | pub fn spawn<F, T>(f: F) -> JoinHandle<T>
| ----- required by a bound in this function
...
675 | F: Send + 'static,
| ^^^^ required by this bound in `spawn`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `shared-state` (bin "shared-state") due to 1 previous error
```
Here is the important part to focus on: ``Rc<Mutex<i32>>` cannot be send between threads safely`.
The compiler also tells us the reason why: the trait `Send` is not implemented `Rc<Mutex<i32>>`
We will discuss `Send` in the next section.
For now: it's one of the traits that ensures the types we use with threads are meant for use in concurrent situations.
`Rc<T>` is not safe to share across threads.
When `Rc<T>` manages the reference count, it adds to the count for each call to `clone` and subtracts from the count when each clone is dropped.
This doesn't use any concurrency primitives to make sure that changes to the count can't be interrupted by another thread.
This could lead to wrong counts, this could cause subtle bugs that could in turn lead to memory leaks or a value being dropped before we are don't with it.
We need something that is exactly like `Rc<T>` but one that makes changes to the reference count in a thread-safe way.
### Atomic Reference Counting with `Arc<T>`
`Arc<T>` *is* a type like `Rc<T>` that is safe to use in concurrent situations.
The *a* stands for *atomic* meaning that it is an *atomically reference counted* type.
Atomics are an additional kind of concurrency primitive that we won't cover in detail here.
See the std library documentation for [`std::sync::atomic`](https://doc.rust-lang.org/std/sync/atomic/index.html) for more info.
At this point know that atomics work like primitive types but are safe to share across threads.
You may wonder why all primitives types aren't atomic and why std library types aren't implemented to use `Arc<T>` by default.
This is due the performance penalty that comes with being thread safe. You only want to pay when you really need to.
If you are just performing operations on values within a single thread, your code can run faster if it doesn't have to enforce the guarantees atomics provide.
We will update our example to use `Arc<T>`.
`Arc<T>` and `Rc<T>` have the same API.
To fix our program by changing the `use` line to call to `new` and the call to `clone`.
Here is the updated code
```rust
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap());
}
```
This will print the following
```
Result: 10
```
This counts from 0 to 10.
This doesn't seem very impressive but this taught us a lot about `Mutex<T>` and thread safety.
This could also be used in a program's structure to do more complex operations than just incrementing a counter.
Using this strategy, you can divide a calculation into independent parts, split those parts across threads and then use a `Mutex<T>` to have each thread update the final result with its part.
Note that if you are doing simple numerical operations, there are types simpler than `Mutex<T>` types provided by the [`std::sync::atomic module`](https://doc.rust-lang.org/std/sync/atomic/index.html)
These types provide safe concurrent, atomic access to primitives types.
Here we decided to use `Mutex<T>` with a primitive type for this example so we could show how `Mutex<T>` works.
## Similarities Between `RefCell<T>`/`Rc<T>` and `Mutex<T>`/`Arc<T>`
Notice that `counter` is immutable but we could get a mutable reference to the value inside it.
This means `Mutex<T>` provides interior mutability, just like how the `Cell` family does.
In the same way we use `RefCell<T>` in [Ch15](./Smart%20Pointers.md) to allow us to mutate contents inside an `Rc<T>`, we use `Mutex<T>` to mutate contents inside an `Arc<T>`.
Another thing to notice is that Rust can't protect you form all kinds of logic errors when use use `Mutex<T>`.
Recall that using `Rc<T>` came with the risk of creating reference cycles, where tow `Rc<T>` values refer to each other, thus causing a memory leak.
Similarly, `Mutex<T>` comes with the rusk of creating *deadlocks*.
These occur when an operation needs to lock two resources and two threads each acquired one of the locks, thus causing them to wait for each other forever.
You can research deadlock mitigation strategies for mutexes in any language and have a go at implementing them in Rust.
The std library API documentation for `Mutex<T>` and `MutexGuard` offer useful info.
Next we will talk about the `Send` and `Sync` traits and how we can use them with custom types.
Go [Here](./Sync%20and%20Send.md) for the next chapter

View File

@ -0,0 +1,340 @@
# Using Threads to Run Code Simultaneously
In most modern operating systems, an executed program's program's code is run in a *process*, and the operating system will manage multiple process at once.
Within a progam you can also have independent components that run simultaneously.
The features that run these independent parts are called *threads*.
An example of this is a we server could have multiple threads so that it could respond to more than one request at the same time.
Splitting this computation in yor program into multiple threads to run multiple tasks at the same time can improve performance.
This comes with the drawback of added complexity.
Due to threads being able to run simultaneously, there is no ingerent guarantee about the order in which parts of your code on different threads will run.
This can lead to problems like:
- Race conditions - where threads are accessing data or resources in an inconsistent order
- Deadlock - where two threads are waiting for each other, preventing both threads from continuing
- Bugs that happen only in specific cases and are hard to reproduce and fix reliably
Rust attempts to minimize the negative effects of using threads, but programming in a mutlithreaded context still takes a lot of careful thought and reuires a code structure that is different from that in programs running in a single threaded manner.
Rrogramming languages often implement threads in a few different ways, and amny operating systmes provide an API the language can call for creating new threads
The Rust std library uses a *1:1* model of thread implementation, whereby a program uses one operating system thread per on language thread.
There are crates that implement other models of threading that make different tradeoffs to the 1:1 model
(Rust's aync system provides another approach to concurrency as well, we will see this in th nex section.)
## Creating a New Thread with `spawn`
To create a new thread, we use the `thread::spawn` function and pass it a closure (this was discussed previously [here](./Closures.md)).
This contains the code we want to run in the new thread.
Here is an example where this code prints some text from a main thread and other text from a new thread
```rust
use std::thread;
use std::time::Duration;
fn main() {
thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread!");
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {i} from the main thread!");
thread::sleep(Duration::from_millis(1));
}
}
```
Note that when the main thread of Rust program completes, all spawned threads are shut down, whether or not they have finished running.
The output form this program might be a little different every time.
Overall it will look similar to this output
```
hi number 1 from the main thread!
hi number 1 from the spawned thread!
hi number 2 from the main thread!
hi number 2 from the spawned thread!
hi number 3 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the main thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
```
The call to `thread::sleep` force a thread to stop its execution for a short duration.
This allws for a different thread to run.
The threads will probably take turns, this is not guaranteed.
This is entirely dependant on how your operating system schedules the threads.
Here in this run, the main thread is printed first, even though the print statement from the spawned thread appears first.
And even though we told the spawned thread to print unti `i` is 9, it only got to 5 before the main thread shut down.
If you run this code and only see the output form the main thread, or dont see any overlap. You can try increasing the numbers in the ranges to create mroe opportunities for the operating system to switch between the threads.
## Waiting for All Threads to Finishe Using `join` Handles
THe code from the example before not only stops the spwaned thread prematurely most of the time due to the main thread ending.
There is no guarantee on the order in which the threads run, we also can't guarantee that the spawned thread will get to run at all.
We can fix the problem of the spawned thread not running o ending prematurely by saving value of `thread::spawn` in a variable.
The return type of `thread::spawn` is `JoinHandle`.
A `JoinHandle` is an owned value that, wqhen we call the `join` method on it, will wait for its thread to finish.
This next example shows how to use the `JoinHandle` of the thread we created in and call `join` to make sure the spawned thread finishes before `main` exits:
```rust
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread!");
thread::sleep(Duration::from_millis(1));
}
});
for i in 1..5 {
println!("hi number {i} from the main thread!");
thread::sleep(Duration::from_millis(1));
}
handle.join().unwrap();
}
```
Here calling `join` on the handle blocks the thread currently running until the thread represented by the handle terminates.
*Blocking* a thread means that the thread is prevented form performing work or exiting.
Due to us putting the `join` call after the main thread's `for` loop.
Running this now the output should look similar to this
```
hi number 1 from the main thread!
hi number 2 from the main thread!
hi number 1 from the spawned thread!
hi number 3 from the main thread!
hi number 2 from the spawned thread!
hi number 4 from the main thread!
hi number 3 from the spawned thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
hi number 6 from the spawned thread!
hi number 7 from the spawned thread!
hi number 8 from the spawned thread!
hi number 9 from the spawned thread!
```
The two threads will alternate btween the two, but the main thread waits because of the call to `handle.join()`.
It does not end until the spawned thread is finished.
Lets see what happens when we move `handle.join()` to before the `for` loop in main
```rust
use std::thread;
use std::time::Duration;
fn main() {
let handle = thread::spawn(|| {
for i in 1..10 {
println!("hi number {i} from the spawned thread!");
thread::sleep(Duration::from_millis(1));
}
});
handle.join().unwrap();
for i in 1..5 {
println!("hi number {i} from the main thread!");
thread::sleep(Duration::from_millis(1));
}
}
```
Now the main thread will wait for the spawned thread to finish and then run its `for` loop.
Now the output will not be interleaved anymore, like this
```
hi number 1 from the spawned thread!
hi number 2 from the spawned thread!
hi number 3 from the spawned thread!
hi number 4 from the spawned thread!
hi number 5 from the spawned thread!
hi number 6 from the spawned thread!
hi number 7 from the spawned thread!
hi number 8 from the spawned thread!
hi number 9 from the spawned thread!
hi number 1 from the main thread!
hi number 2 from the main thread!
hi number 3 from the main thread!
hi number 4 from the main thread!
```
These small details, such as where `join` is called, can affect whether or not your threads run at the same time.
We need `.unwrap` to consume the closures otherwise it will not run.
## Using `move` Closures with Threads
We often use the `move` keyword with closures passed to `thread::spawn`.
This is due the closure taking ownership of the values it uses from the environment, and ths transferring ownership of those values form one thread to another.
Remember the [Capturing References or Moving Ownership](./Closures.md#capturing-references-or-moving-ownership) section, where we discussed `move` in the context of clousres.
Here we will focus on the interaction between `move` and `thread::spawn`.
Note that in the first example that the closure we pass to `thread::spawn` takes no args.
There we are not using any data from the main thread in the spawned thread's code.
To use data from the main thread within the spawned thread, we need the spawned thread's closure to capture the values it needs.
In this example shows an attempt to create a vector in the main thread a nd use it in the spawned thread.
This will not comile, it will be exampled afterwards.
```rust
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(|| {
println!("Here's a vector: {v:?}");
});
handle.join().unwrap();
}
```
This closures uses `v`, so it will capture `v` and make it part of the closures environment.
Due to `thread::spawn` runs this closure in a new thread.
Here we should be able to access `v` inside that new thread.
But when we compile this we get this compiler error
```
$ cargo run
Compiling threads v0.1.0 (file:///projects/threads)
error[E0373]: closure may outlive the current function, but it borrows `v`, which is owned by the current function
--> src/main.rs:6:32
|
6 | let handle = thread::spawn(|| {
| ^^ may outlive borrowed value `v`
7 | println!("Here's a vector: {v:?}");
| - `v` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:6:18
|
6 | let handle = thread::spawn(|| {
| __________________^
7 | | println!("Here's a vector: {v:?}");
8 | | });
| |______^
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
|
6 | let handle = thread::spawn(move || {
| ++++
For more information about this error, try `rustc --explain E0373`.
error: could not compile `threads` (bin "threads") due to 1 previous error
```
Rust here will *infer* how to capture `v` and because `println!` only needs a reference to `v`, the closure tires to borrow `v`.
Here the problem is that Rust can't tell how long the spawned thread will run so it doesn't know if the reference to `v` will always be valid.
This next example provides a scenario that is more likely to habve a referncfe to `v` that will not be valid
```rust
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(|| {
println!("Here's a vector: {v:?}");
});
drop(v); // oh no!
handle.join().unwrap();
}
```
If Rust allwed this code to run, there is a possibility that the spawned thread would be immediately put in the backgrounf without running at all.
The spawned reference to `v` inside, but the main thread immediately drops `v` usng the `drop` function.
Then when the spawned thread starts to execute, `v` is no longer valid, so a reference to it is also invalid.
Here is what the compiler suggests to fix this, it is located in the compiler error message
```
help: to force the closure to take ownership of `v` (and any other referenced variables), use the `move` keyword
|
6 | let handle = thread::spawn(move || {
| ++++
```
By adding the `move` keyword before the closure. This forces the closure to take ownership of the values it is using rather than allowing Rust to unfer that it should borrow the values.
Here is the modification to the bfore exampl that will compile and run as intended
```rust
use std::thread;
fn main() {
let v = vec![1, 2, 3];
let handle = thread::spawn(move || {
println!("Here's a vector: {v:?}");
});
handle.join().unwrap();
}
```
We may be tempted to try the sam ething to dix the code in the previous example where the main thread called `drop` by using a `move` closure.
This fix will not work because od what the example is attempting to do is disallowed for a different reason.
If we were to add `move` to the closure, we would move `v` into the closure's environment and we could no longer call `drop` on it in the main thread.
We would get this compiler error instead
```
$ cargo run
Compiling threads v0.1.0 (file:///projects/threads)
error[E0382]: use of moved value: `v`
--> src/main.rs:10:10
|
4 | let v = vec![1, 2, 3];
| - move occurs because `v` has type `Vec<i32>`, which does not implement the `Copy` trait
5 |
6 | let handle = thread::spawn(move || {
| ------- value moved into closure here
7 | println!("Here's a vector: {v:?}");
| - variable moved due to use in closure
...
10 | drop(v); // oh no!
| ^ value used here after move
For more information about this error, try `rustc --explain E0382`.
error: could not compile `threads` (bin "threads") due to 1 previous error
```
The Rust ownership rules save us again.
The we get this error becuase Rust was being conservative and only borrowing `v` for the thread.
This means that the thread could theoretically invaildate, we are guaranteeing Rust that the main thread won't use `v` anymore.
If we change the example form before in the same way then we would voilate the ownership rules rules when we try to use `v` in the main thread.
The `move` keyword overrides Rust's conservative default of borrowing; it doesnt let us violate the ownership rules.
Now with a basic understanding of threads and the thread API, we will look at what we can *do* with threads
[Next Section Here]()

59
Smart Pointers.md Normal file
View File

@ -0,0 +1,59 @@
# Smart Pointers
A *pointer* is a concept for a variable that contains an address in memory.
This address refers or "points at", some other data.
In Rust the most common kind of pointer is a reference.
References are indicated by the `&` symbol and borrow the value they point to.
They don't have any additional or special capabilities other than referring to data and have no overhead.
*Smart pointers* are data structures that act like a pointer but also have additional metadata and capabilities.
This idea of smart pointers is not unique to Rust.
Smart pointers come from C++ and exist in other languages as well.
Rust has a variety of smart pointers defined in the std library that provide functionality beyond that provided by references.
To explore the general concept, we will look at a couple of different examples of smart pointers, including a *reference counting* smart pointer type.
This pointer enables you to allow data to have multiple owners by keeping track of the number of owners and when there are no more owners remaining, clean up the data.
With the concept of ownership and borrowing in Rust it has an additional difference between references and smart pointers.
While references only borrow data, in many cases, smart pointers *own* the data they point to.
Even though we haven't called them smart pointers before we have already interacted with a few smart pointers in previous chapters.
This includes `String` and `Vec<T>`.
Both of these types count as smart pointers because they own some memory and allow you to manipulate it.
They both contain metadata and extra capabilities or guarantees.
As an example `String` stores its capacity as metadata and has the extra ability to ensure its data will always be valid UTF-8.
Smart pointers are usually implemented using structs.
Unlike an ordinary struct, smart pointers implements the `Deref` and `Drop` traits.
The `Deref` trait allows an instance of the smart pointer struct to behave like a reference so you can write your code to with either references or smart pointers. [Section Link Here](./Deref%20Trait.md)
The `Drop` trait allows you to customize the code that is run when an instance of the smart pointer goes out of scope. [Section Link Here](./Drop%20Trait.md)
We will go over both traits and demonstrate why they are important to smart pointers.
Given that the smart pointer pattern is a general design used often in Rust, we won't cover every existing smart pointer.
Many libraries have their own smart pointers, and you can even write your own.
The ones we will cover are the most common smart pointers in the std library:
- [`Box<T>` for allocating values on the heap](./Using%20Box%20on%20the%20Heap.md)
- `Rc<T>`, a reference counting type that enables multiple ownership [Section Link Here](./Reference%20Counter%20Smart%20Pointer.md)
- `Ref<T>` and `RefMut<T>` this is accessed through `RefCell<T>`, a type that enforces the borrowing rules at runtime instead of compile time [Section Link Here](./Ref%20Cell%20Mutability.md)
In addition we will also cover *interior mutability* patter where an immutable type exposes an API for mutating an interior value.
As well discuss *reference cycles*; how they can leak memory and how to prevent them. [Section Link Here](./Leaky%20Reference%20Cycles.md)

57
Sync and Send.md Normal file
View File

@ -0,0 +1,57 @@
# Extensible Concurrency with the `Sync` and `Send` Traits
The Rust language gas *very* few concurrency features.
Almost every feature we talked about so far has been part of the std library and not the language.
Your options for handling concurrency are not limited to the language or the std library; you are able to write your own concurrency features or use those written by others.
However, tow concurrency concepts that are embedded into the language are the `std::marker` traits `Sync` and `Send`.
## Allowing Transference of Ownership Between Threads with `Send`
The marker trait `Send` indicates that ownership of values of the type implemented `Send` can be transferred between threads.
Almost every Rust type is `Send`.
There are some exceptions, including `Rc<T>`.
This cannot be be `Send` because if you cloned a `Rc<T>` value and tried to transfer ownership of the clone to another thread, both threads might update the reference count at the same time.
This is the reason, `Rc<T>` is implemented for use in single-threaded situations where you don't want to pay the thread-safe performance penalty.
Rust's type system and trait bounds ensure that you can never accidentally send a `Rc<T>` value across threads unsafely.
When we tried to do this before we got the error: the trait `Send` is not implemented for `Rc<Mutex<i32>>`.
Any type composed entirely of `Send` types is automatically marked as `Send` as well.
Almost all primitives are `Send`, aside form raw pointers (This will be discussed in ch20).
## Allowing access form Multiple Threads with `Sync`
The `Sync` marker trait indicates that it is safe for the type implementing `Sync` to be referenced from multiple threads.
Any type `T` is `Sync` if `&T` (an immutable reference to `T`) is `Send`, meaning the reference can be sent safely to another thread.
Similar to `Send`, primitive types are `Sync` and types composed entirely of types that are `Sync` are also `Sync`.
The smart pointer `Rc<T>` is not `Sync` as well for the same reasons that it is not `Send`.
The `RefCell<T>` types ([Ch15](./Smart%20Pointers.md)) and the family related to `Cell<T>` types are not `Sync`.
The implementation for borrow checking that `RefCell<T>` does at runtime is not thread-safe.
The smart pointer `Mutex<T>` is `Sync` and can be used to share access with multiple threads alike what we saw in ["Sharing a `Mutex<T>` Between Multiple Threads"](./Shared%20State%20Concurrency.md) Section.
## Implementing `Send` and `Sync` Manually is Unsafe
Because types that are made up of `Send` and `Sync` traits are also automatically `Send` and `Sync`, we don't need to implement these traits manually.
As marker traits they don't even have any methods to implement.
These are just useful for enforcing invariants related to concurrency.
Manually implemented these traits involves implementing unsafe Rust code (This will be discussed in Ch20).
For now the important information is that building new concurrent types not made up of `Send` and `Sync` parts requires careful thought to uphold the safety guarantees.
["The Rustonomicion"](https://doc.rust-lang.org/nomicon/index.html) has more information about these guarantees and how to uphold them.

View File

@ -0,0 +1,84 @@
# Comparing Performance: Loops vs. Iterators
To determince whether to use loops or iterators, you need to know which implementation is faster
Is it the version with an explicit `for` loop?
Is it the version with iterators?
Here is a benchmark where we load the entire contnets of *The Adventures of Sherlock Holmes* by Sir Arthur Conan Doyle into a `String` and looking ofr the word *the* in the contents
Here is the results of the benchmark on the version of `search` using the `for` loop and the version using iterators:
```
test bench_search_for ... bench: 19,620,300 ns/iter (+/- 915,700)
test bench_search_iter ... bench: 19,234,900 ns/iter (+/- 657,200)
```
The two have similar performace!
We won't explain the benchmark code here, because the poin is not to prive that the two versions are equivalent but to get a general sense of how these two compare performance-wise.
For a more comprehensive benchmark, you should check using various texts of various sizes as the `contents`, different words and words of different lenghts as the `query` and all kinds of other variations.
The point is this, iterators, although a high-level abstraction, get compiled down to roughly the same code as if you wrote the lower-level code yourself.
Iterators are one of Rust's *zero-cost abstractions`. This means using the abstraction imposes no addtional runtime overhead.
This is analogous to how Bjarne Stroustrup, the original designer and implementor of C++ defines *zero-verhead* in "Fondations of C++" (2012)
```
In general, C++ implementations obey the zero-overhead principle: What you dont use, you dont pay for. And further: What you do use, you couldnt hand code any better.
```
Here is another example, the code is taken from an audio decoder.
The decoding algorithm uses the linear prediction mathematical operation to estimate future values based on a linear function of the previous samples.
This code uses an iterator chain to do some math on three variables in scope:
- a `buffer` slice of data
- an array of `coefficients`
- an amount ot which shift data in `qlp_shift`
We declared the variables within this example but not given them any values.
Even though this code doesnt have muc meaning outside of its context, it is still a concise, real-world example of how Rust tranlate high-level ideas to low-level code.
```rust
let buffer: &mut [i32];
let coefficients: [i64; 12];
let qlp_shift: i16;
for i in 12..buffer.len() {
let prediction = coefficients.iter()
.zip(&buffer[i - 12..i])
.map(|(&c, &s)| c * s as i64)
.sum::<i64>() >> qlp_shift;
let delta = buffer[i];
buffer[i] = prediction as i32 + delta;
}
```
To calcuate the value of `prediction`, the code iterates though each of he 12 values in `coefficients` and ses the `zip` method to pair the coefficient values with the previous 12 values in `buffer`
For each pair then we multiply the values together, sum all the results and shift the bits in the sum `qlp_shift` bits to the right.
Calculations in applications like audio decoders often prioritize perfomance.
Here we are creating an iterator, using two adapters and then consuming the value.
What assembly would this Rust code compile into.
As of writing this in the book, it compiles down to the same assbly you would write by hand.
There is no loop at all corresponding to the iteration over the values in `coefficients`.
Rust knows that there are 12 iterations, so it "unrolls" the loop.
*Unrolling* is an optimization that removes the overhead of the loop controlling code and instead generates repetitive code for each iteration fo the loop.
All of the coefficients ge stored in registers which means accessing the values is very fast.
There are no bounds checks on the array access at runtime.
All of these optimizations that Rust is able to apply make the resulting code extremely efficient.
Now you know that you can use iterators and closures without fear of performance hits.
They make code seem like its highe level but again dont impose a performance hit.

View File

@ -0,0 +1,254 @@
# Using Trait Objects That Allow for Values of Different Types
In ch8 we discussed one of the limitation of vectors is that they can store elements of only one type
We created a workaround where we defined a `SpreadsheetCell` enum that had variants to hold integers, floats and text.
This meant that we could store different types of data in each cell and still have a vector that represented a row of cells.
This is a good solution when our interchangeable items are a fixed set of types that we know when our code is compiled.
However, sometimes we want our library user to be able to extend the set of types that are valid in a particular situation.
To show how we may achieve this, we will create a example graphical user interface (GUI) tool that iterates through a list of items, calling a `draw` method on each one to draw it to the screen.
This is a common technique for GUI tools.
We will start with creating a library crate called `gui` that contains the structure of a GUI library.
This crate might include some types for people to use, such as `Button` or `TextField`.
In addition `gui` users will want to create their own types that can be drawn.
For example, one programmer might add an `Image` and another programmer might add a `SelectBox`
In this example we won't build a fully fledged GUI library, but instead will show how all of the pieces would fit together.
At the time of writing the library, we cant know and define all the types other programmers might want to create.
We do know that `gui` needs to keep track of many values of different and it needs to call a `draw` method on each of these differently typed values.
It doesn't need to know exactly what will happen when we call the `draw` method, just that the value will have that method available for us to call.
In a language to do this, we might define a class named `Component` that has a method named `draw` on it.
The other classes, such as `Button`, `Image` and `SelectBox`, would inherit form `Component` and thus inherit the `draw` method.
Each one would override the `draw` method to define their custom behavior, but the framework could treat all of the types as if they were `Component` instances and call `draw` on them.
Due to Rust not having inheritance, we need a different way to structure the `gui` library to allow users to extend it with new types.
## Defining a Trait for Common Behavior
In order to implement the behavior we want `gui` to have, we will define a trait named `Draw` that will have one method named `draw`.
We then can define a vector that takes a *trait object*.
A trait object points to both an instance of a type implementing our specified trait and a table used to look up trait methods on that type at runtime.
We create a trait object by specifying some sort of pointer, such as a `&` reference or a `Box<T>` smart pointer, then the `dyn` keyword and then specifying the relevant trait.
We will discuss about the reason trait objects must use a pointer in Ch20.
We can use trait objects in place of a generic or concrete type.
Whenever we use a trait object, Rust's type system will ensure at compile time that any value used in that context will implement the trait object's trait.
Due to this we don't need to know all possible types at compile time.
We mentioned that in Rust, we refrain from calling structs an enums "objects" to distinguish them from other language's objects.
In a struct or enum, the data in the struct fields and the behavior in `impl` blocks are separated, where as in other languages, the data and behavior combined into one concept is often labeled an object.
Trait objects *are* more like objects in other languages in the sense that they combine data and behavior.
Trait objects still differ form traditional objects in that we can't add data to a trait object.
Trait objects aren't as generally useful as objects in other languages: their purpose is to allow abstraction across common behavior.
Here is an example of how to define a trait named `Draw` with one method named `draw`
```rust
pub trait Draw {
fn draw(&self);
}
```
This is similar syntax to how we defined traits in Ch10.
Next comes some new syntax.
Here we define a struct named `Screen` that holds a vector named `components`.
This vector is of type `Box<dyn Draw>`, which is a trait object; it is a stand in for any type inside a `Box` that implements the `Draw` trait.
```rust
pub struct Screen {
pub components: Vec<Box<dyn Draw>>,
}
```
Now on the `Screen` struct we will define a method named `run` that will call the `draw` method on each of its `components`
```rust
impl Screen {
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
```
This works differently form defining a struct that uses a generic type parameter with trait bounds.
A generic type parameter can only be substituted with one concrete type at a time, whereas trait objects allow for multiple concrete types to fill in for the trait object at runtime.
For example we could have defined the `Screen` struct using generic type and a trait bound, this is shown here.
```rust
pub struct Screen<T: Draw> {
pub components: Vec<T>,
}
impl<T> Screen<T>
where
T: Draw,
{
pub fn run(&self) {
for component in self.components.iter() {
component.draw();
}
}
}
```
This restricts us to a `Screen` instance that has a list components all of type `Button` or all of type `TextField`.
If you only ever have homogeneous collections, using generics and trait bounds is preferable because the definitions will be monomerized at compile time to use the concrete types.
With the method using trait objects, one `Screen` instance can hold a `Vec<T>` that contains a `Box<Button>` as well as a `Box<TextField>`.
Now lets look at how that works and then we will talk about the runtime performance implications.
## Implementing the Trait
Next we will add some types that implement the `Draw` trait.
We will provide the `Button` type.
So the `draw` method won't have any useful implementation in its body.
To imagine what the implementation might look like, a `Button` struct might have fields for `width`, `height` and `label`.
Here is an example of this
```rust
pub struct Button {
pub width: u32,
pub height: u32,
pub label: String,
}
impl Draw for Button {
fn draw(&self) {
// code to actually draw a button
}
}
```
The `width`, `height` and `label` fields on `Button` will differ from the fields on other components.
For example a `TextField` type might have those same fields plus a `placeholder` field.
Each of the types we want to draw on the screen will implement the `Draw` trait, but will use different code in the `draw` method to define how to draw that particular type as `Button` has here (without any actual GUI code).
The `Button` type, for instance, might have an additional `impl` block containing method related to what happens when a user clicks the button.
These kinds of methods related to what happens when a user clicks the button.
These kinds of methods won't apply to types like `TextField`.
If someone using our library decides to implement a `SelectBox` struct that has `width`, `height`, and `options` fields, they implement the `Draw` trait on the `SelectBox` type as well.
This is shown below
```rust
use gui::Draw;
struct SelectBox {
width: u32,
height: u32,
options: Vec<String>,
}
impl Draw for SelectBox {
fn draw(&self) {
// code to actually draw a select box
}
}
```
When we originally wrote the library, we didn't know that someone might add the `SelectBox` type, but our `Screen` implementation was able to operate on the new type and draw it because `SelectBox` implements the `Draw` trait.
This means that it implements the `draw` method.
This concept of being concerned only with the messages a value responds to rather than the value's concrete type.
This is similar to the concept of *duck typing* in dynamically typed languages.
If it walks like a duck and quacks like a duck, then it must be a duck!
In the implementation of `Run` on `Screen`, `run` doesn't need to know what the concrete type of each component is.
It doesn't check whether a component is an instance of a `Button` or a `SelectBox`, it just calls the `draw` method on the component.
By specifying `Box<dyn Draw>` as the type of the values in the `componets` vector.
Here we have defined `Screen` to need values that we can call the `draw` method on.
The advantage of using trait objects and Rust's type system to write code similar to code using duck typing is that we never have to check whether a value implements a particular method at runtime or worry about getting errors if a value doesn't implement a method but we call it anyway.
Rust will not compile the code if the values don't implement the traits that the trait objects need.
Here is an example of this shows what happens if we try to create a `Screen` with a `String` as a component
```rust
use gui::Screen;
fn main() {
let screen = Screen {
components: vec![Box::new(String::from("Hi"))],
};
screen.run();
}
```
Here we will get this error because `String` doesn't implement the `Draw` trait
```
$ cargo run
Compiling gui v0.1.0 (file:///projects/gui)
error[E0277]: the trait bound `String: Draw` is not satisfied
--> src/main.rs:5:26
|
5 | components: vec![Box::new(String::from("Hi"))],
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Draw` is not implemented for `String`
|
= help: the trait `Draw` is implemented for `Button`
= note: required for the cast from `Box<String>` to `Box<dyn Draw>`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `gui` (bin "gui") due to 1 previous error
```
This error let us know that either we are passing something to `Screen` we didn't mean to pass and so should pass a different type or we should implement `Draw` on `String` so that `Screen` is able to call `draw` on it.
## Trait Objects Preform Dynamic Dispatch
Recall the ["Performance of Code Using Generics"](./Generics.md#perfomance-of-code-using-generics) our discussion on the monomorphization process performed on generics by the compiler.
The compiler generates nongeneric implementations of functions and methods for each concrete type that we use in place of a generic type parameter.
The code that results from monomorphization is doing *static dispatch*, which is when the compiler know what method you are calling at compile time.
This is the opposite to *dynamic dispatch*, which is when the compiler can't tell at compile time which method you are calling.
In dynamic dispatch cases, the compiler emits code that at runtime will figure out which method to call.
When we use trait objects, Rust must use dynamic dispatch.
The compiler won't know all the types that might be used with the code that is using trait objects, so it doesn't know all the types that might be used with the code that is using trait objects, so it doesn't know which method implemented on which type to call.
Instead at runtime, Rust uses the pointers inside the trait object to know which method to call.
This lookup incurs a runtime cost that doesn't occur with static dispatch.
Dynamic dispatch also prevents the compiler from choosing to inline a method's code, which prevents some optimizations, and Rust has some rules about where you can and cannot use dynamic dispatch.
This is called [dyn compatibility](https://doc.rust-lang.org/reference/items/traits.html#dyn-compatibility).
However you will get the extra flexibility in the code that we wrote before and we were able to support in the following examples, so it is a trade-off to consider.

405
Traits for Async.md Normal file
View File

@ -0,0 +1,405 @@
# A Closer Look at the Traits for Async
Sometime, you will encounter situations where you will need to understand a few more of these details.
A high level understanding is ok for most of day to day Rust writing.
In this chapter we will dig in just enough to help in those scenarios.
Diving even requires reading the documentation.
## The `Future` Trait
Now lets look at how the future trait works.
Here is how Rust defines it
```rust
use std::pin::Pin;
use std::task::{Context, Poll};
pub trait Future {
type Output;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
```
The trait definition includes a bunch of new types and also some syntax we haven't seen before.
First, `Future`'s associated type `Output` says what the future resolves to.
This is analogous to the `Item` associated type for the `IUterator` trait.
Second, `Future` also has the `poll` method, this takes a special `Pin` reference for its `self` parameter and a mutable reference to a `Context` type, and returns a `Poll<Self::Output>`.
For now we will focus on what the method returns, the `Poll` type
```rust
enum Poll<T> {
Ready(T),
Pending,
}
```
This `Pool` type is similar to an `Option`.
It has one variant that has a value, `Ready(T)`, and one which does not `Pending`.
`Poll` means something quite different form `Option`.
The `Pending` variant indicates that the future still has work to do, so the caller will need to check again later.
The `Ready` variant indicates that the future has finished its work and the `T` value is available.
Note that futures, the caller should not call `poll` again after the future has returned `Ready`.
Many of the futures will panic if polled again after becoming ready.
Futures that safe to poll again will say so explicitly in their documentation.
This is similar behavior to `Iterator::next`.
When toy see code that uses `await`, Rust compiles it under the hood to code that calls `poll`.
If you look back at the previous example, where we printed out the page title for a single URL once it resolved.
Rust compiles it into something kind of like this
```rust
match page_title(url).poll() {
Ready(page_title) => match page_title {
Some(title) => println!("The title for {url} was {title}"),
None => println!("{url} had no title"),
}
Pending => {
// But what goes here?
}
}
```
What should we do when the future is still `Pending`?
We need way to try again and again, until the future is finally ready.
We need a loop
```rust
let mut page_title_fut = page_title(url);
loop {
match page_title_fut.poll() {
Ready(value) => match page_title {
Some(title) => println!("The title for {url} was {title}"),
None => println!("{url} had no title"),
}
Pending => {
// continue
}
}
}
```
If Rust compiled it to exactly this code.
Every `await` would be blocking, exactly the opposite of what we are trying to do.
Instead Rust makes sure that the loop can hand off control to something that can pause work in this future to work on other futures and then check this again later.
This is something that async runtime, and this scheduling and coordination work is one of its main jobs.
Earlier we described waiting on `rx.recv`.
The `recv` call returns a future, and awaiting the future polls it.
We noted that a runtime will pause the future until it is ready with either `Some(message)` or `None` when the channel closes.
Now with the deeper understanding of the `Future` trait, and specifically `Future::poll`, we can now see how that works.
The runtime knows the future isn't ready when it returns `Poll::Pending`.
The runtime also knows the future *is* ready and advances it when `poll` returns `Poll::Ready(Some(message))` or `Poll::Ready(None)`
The exact details of how a runtime works, is something that will not be covered by this book.
The key is to see the basic mechanics of futures.
A runtime *polls* each future it is responsible for, putting the future beck to sleep when it is not yet ready.
## The `Pin` and `Unpin` Traits
When we introduced pinning, we run into this error message.
Here is the relevant part again
```
error[E0277]: `{async block@src/main.rs:10:23: 10:33}` cannot be unpinned
--> src/main.rs:48:33
|
48 | trpl::join_all(futures).await;
| ^^^^^ the trait `Unpin` is not implemented for `{async block@src/main.rs:10:23: 10:33}`, which is required by `Box<{async block@src/main.rs:10:23: 10:33}>: Future`
|
= note: consider using the `pin!` macro
consider using `Box::pin` if you need to access the pinned value outside of the current scope
= note: required for `Box<{async block@src/main.rs:10:23: 10:33}>` to implement `Future`
note: required by a bound in `futures_util::future::join_all::JoinAll`
--> file:///home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/futures-util-0.3.30/src/future/join_all.rs:29:8
|
27 | pub struct JoinAll<F>
| ------- required by a bound in this struct
28 | where
29 | F: Future,
| ^^^^^^ required by this bound in `JoinAll`
```
This error message tells us not only that we need to pin the values but also why pinning is required.
The `trpl::join_all` function returns a struct called `JoinAll`.
The struct is a generic over a type `F` which is constrained to implement the `Future` trait.
Directly awaiting a future with `await` pins the future implicitly.
This is why we don't need to use `pin!` everywhere we want to await futures.
However we are 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` requires that the types of the items in the collection all implement the `Future` trait.
`Box<T>` implements `Future` only if the `T` wraps is a future that implements the `Unpin` trait.
Now we will dive a little deeper into how the `Future` trait actually works, in particular around *pinning*.
Lets look at the definition of pf the `Future` trait.
```rust
use std::pin::Pin;
use std::task::{Context, Poll};
pub trait Future {
type Output;
// Required method
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}
```
The `cx` parameter and its `Context` type are the key to how a runtime actually knows when to check any given future while still being lazy.
The details of how that works are beyond the scope of this chapter, and you generally only need to think about this when writing a custom `Future` implementation.
Here we will focus on the type for `self` as this is the first time we have seen a method where `self` has a type annotation.
A type annotation for `self` is works like type annotations for other function parameters, but there are two key differences.
- It tells Rust what type `self` must be for the method to be called.
- It can't be just any time
- It is restricted to the type on which the method is implemented, a reference or smart pointer to the type, or a `Pin` wrapping a reference to that type.
We will see more on this syntax in Ch18.
For now know that if we want to poll a future to check whether it is `Pending` or `Ready(Output)`m we need a `Pin` wrapped mutable reference to the type.
`Pin` is a wrapper for pointer-like types such as `&`, `&mut`, `Box`, and `Rc`.
(Technically `Pin` works with types that implement the `Deref` or `DerefMut` traits but this is effectively equivalent to working only with pointers)
`Pin` is not a pointer itself.
It also doesn't have any behavior of its own like `Rc` and `Arc` do with reference counting.
This is purely a tool the compiler can use to enforce constraints on pointer usage.
Recall that `await` is implemented in terms of calls to `poll` start to explain the error message from before.
This was in terms of `Unpin`, not `Pin`.
How does `Pin` relate to `Unpin` and why does `Future` need `self` to be in a `Pin` type to call `poll`?
Remember from before, a series of await points in a future get compiled into a state machine, and the compiler makes sure that state machine follows all of Rust's normal rules around safety, which includes borrowing and ownership.
In order to make this work, Rust looks at what data is needed between one await point and either the next await point or the end of the async block.
Each variant get the access it needs to the data that will be used in that section of the source code, whether by taking ownership of that data or by getting a mutable or immutable reference to it.
If we get anything wrong about the ownership or references in a given async block, the borrow checker will tell us.
When we want to move around the future that corresponds to that block, like moving it into a `Vec` to pass to `join_all`, where things get tricker.
When we move a future, either by pushing it into a data structure to use as an iterator with `join_all` or by returning from a function, this actually means moving the state machine Rust creates for us.
Unlike most other types in Rust, the future Rust creates for async blocks can end up with references to themselves in the fields of any given variant.
This is shown in this illustration
<img src="https://doc.rust-lang.org/book/img/trpl17-04.svg" />
By default, any object that has a reference to itself is unsafe to move, because references always point to the actual memory address of whatever they refer to.
If you move the data structure itself, those internal references will be left pointing to the old location.
However that memory location is now invalid.
One thing is that its value will not be updated when you make changes to the data structure.
Another thing, which is more important, is the computer is now free to reuse that memory for other purposes.
You could end up reading completely unrelated data later.
<img src="https://doc.rust-lang.org/book/img/trpl17-05.svg" />
Theoretically, the Rust compiler could try to update every reference to an object whenever it gets moved, but that could add a lot of performance overhead.
This is especially true if a whole web of references needs updating.
If we could instead ensure that the data structure *doesn't move in memory*, we then wouldn't have to update any references.
This is exactly what Rust's borrow checker requires: in safe code, it prevents you from moving any item with an active reference to it.
`Pin` builds on that give us the exact guarantee we need.
When we *pin* a value by wrapping a pointer to that value in `Pin`, it can no longer move.
Thus if you have `Pin<Box<SomeType>>`, you actually pin the `SomeType` value, *not* the `Box` pointer.
The image illustrates this process.
<img src="https://doc.rust-lang.org/book/img/trpl17-06.svg" />
In fact, the `Box` pointer can still move around freely.
We car about making sure the data ultimately being referenced stays in place.
If a pointer moves around, *but the data it points is in the same place*, there is no potential problem.
As an independent exercise, look at the dos for the types as well as the `std::pin` module and try to work out how you would do do this with a `Pin` wrapping a `Box`.
The key is that the self-referential type cannot move, because it is still pinned.
<img src="https://doc.rust-lang.org/book/img/trpl17-07.svg" />
However most types are perfectly safe to move around, even if they happen to be behind a `Pin` pointer.
We only need to think about pinning when the items have internal references.
Primitives values such as numbers and Booleans are safe since they obviously don't have any internal references, so they are obviously safe.
Neither do most types you normally work with in Rust.
You can move around a `Vec`, for example, without worrying.
given what we have seen, if you have a `Pin<Vec<String>>`, you would have to everything via the safe but restrictive APIs provided by `Pin`/
Even though a `Vec<String>` is always safe to move if there are no other references to it.
We need a way to tell the compiler that it is fine to move items around in cases like this, this is where `Unpin` comes into action.
`Unpin` is a marker trait, similar to the `Send` and `Sync` traits.
Thus has no functionality of its own.
Marker traits exist only to tell the compiler to use the type implementing a given trait in a particular context.
`Unpin` informs the compiler that a given type does *not* need to uphold any guarantees about whether the value in question can be safely moved.
Just like `Send` and `Sync`, the compiler implements `Unpin` automatically for all types where it can prove it is safe.
A special case, is 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 that *does* need to uphold those guarantees to be safe whenever a pointer to that type is used in a `Pin`.
The relationship between `Pin` and `Unpin` has two important things to remember:
- `Unpin` is the "normal case", `!Unpin` is the special case
- Whether a type implements `Unpin` or `!Unpin` *only* matters when you are 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 that make it up.
We can wrap a `String` in `Pin`.
However `String` automatically implements `Unpin` as do most other types in Rust.
<img src="https://doc.rust-lang.org/book/img/trpl17-08.svg" />
Pinning a `String`; the dotted line indicates that the `String` implements the `Unpin` trait, and thus is not pinned.
This results, in the ability to do things that would be illegal if `String` implemented `!Unpin`, such as replacing one string with another at the exact same location in has no interval references that make it unsafe to move around.
This wouldn't violate the `Pin` contract, because `String` has no internal references that make it unsafe to move around.
This is precisely why it implements `Unpin` rather than `!Unpin`.
<img src="https://doc.rust-lang.org/book/img/trpl17-09.svg" />
Now that we know enough to understand the errors reported for that `join_all` call from before.
There we originally tried to move the futures produced by the async blocks into a `Vec<Box<dyn Future<Output = ()>>>`.
As we have 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.
`Pin` and `Unpin` are mostly important for building lower-level libraries, or when you are building a runtime itself, rather than for day-to-day Rust.
When you see these traits in error messages, now you will have a better idea of how to fix your code.
Note, the combination of `Pin` and `Unpin` makes it possible to safely implement a whole class of complex types in Rust that would otherwise prove challenging because they are self-referential.
Types that require `Pin` show up most commonly in async Rust today.
Every once in a while, you may see them in other contexts too.
The specifics of how `Pin` and `Unpin` work, and the rules they are required to uphold are covered extensively in the `API` documentation for `std::pin`, so you can check there for more info.
In fact there is a whole BOOK on async Rust programming, that you can find [here](https://rust-lang.github.io/async-book/)
## The `Stream` Trait
As we leaned earlier, streams are similar to asynchronous iterators.
Unlike `Iterator` and `Future`, `Stream` has no definition in the std library (as of writing this), but there *is* a very common definition form the `fuitures` crate used throughout the ecosystem.
Here is a review of the `Iterator` and `Future` traits before going into how a `Stream` trait might merge them together.
From `Iterator`, we have the idea of a sequence: its `next` method provides an `Option<Self::Item>`
From `Future`, we have the idea of readiness over time: the `poll` method provides a `Poll<Self::Output>`
This allows us to represent a sequence of items that become ready over time, we define a `Stream` trait that puts those features together.
```rust
use std::pin::Pin;
use std::task::{Context, Poll};
trait Stream {
type Item;
fn poll_next(
self: Pin<&mut Self>,
cx: &mut Context<'_>
) -> Poll<Option<Self::Item>>;
}
```
Here the `Stream` trait defines an associated type called `Item` for the type of the items produced by stream.
This is similar to `Iterator`, where there may be zero to many items, and unlike `Future`, where there is always a single `Output`, even if it is the unit type `()`.
`Stream` also defines a method to get those items.
We call it `poll_next`, to make it clear that it polls in the same way `Future::poll` does and produces a sequence of items in the same way `Iterator::next` does.
Its return type combines `Poll` with `Option`.
The outer type is `Poll`, because it has to be checked for readiness, just as a future does.
The inner type is `Option`, because it needs to signal whether there are more messages, just as an iterator does.
Somethin like this will likely end up as part of Rust's standard library.
In the meantime, it is part of the toolkit of most runtimes, so you can rely on it, and everything that will be covered should apply generally.
In the example we saw previously in the section on streaming, we didn't use `Poll_next` or `Stream`, but instead used `next` and `StreamExt`.
We *could* work with futures directly via their `poll` method.
Using `await` is much nicer, and the `StreamExt` trait supplies the `next` method so we can do just this:
```rust
trait StreamExt: Stream {
async fn next(&mut self) -> Option<Self::Item>
where
Self: Unpin;
// other methods...
}
```
Note: The definition that we used earlier in the ch looks slightly different that this.
This is because it supports versions of Rust that did not yet support using async functions in traits.
As a result it looks like this:
```rust
fn next(&mut self) -> Next<'_, Self> where Self: Unpin;
```
This `Next` type is a `struct` that implements `Future` and allows us to name the lifetime of the reference to `self` with `Next<'_, Self>`, so that `await` can work with this method.
The `StreamExt` trait also has some interesting method available to use with steams.
`StreamExt` is automatically implemented for every type that implements `Stream`.
These traits are defined separately to enable the community to iterate on convenience APIs without affecting the foundational trait.
In the version of `StreamExt` used in the `trpl` crate, the trait not only defines the `next` method but also supplies a default implementation of `next` that correctly handles the details of calling `Stream::poll_next`.
Meaning that even when you need to write your own streaming data type, you *only* have to implement `Stream` and then anyone who uses your data type can use `StreamExt` and its methods with it automatically.

585
Unsafe Rust.md Normal file
View File

@ -0,0 +1,585 @@
# Unsafe Rust
So far the code we have discussed has had Rust's memory safety guarantees enforced at compile time.
Rust has a second language hidden inside it that doesn't enforce memory safety guarantees.
This is called *unsafety Rust*, which works just like regular Rust but it gives extra superpowers.
Unsafe Rusts exists because static analysis is conservative.
When the compiler tries to determine whether or not code upholds the guarantees, it is better for it to reject some valid programs than to accept some invalid programs.
Even if the code *may* be ok, if the compiler doesn't have enough information to be confident and therefore reject the code.
In these cases you can use unsafe code to tell the compiler, "Trust me, I know what I'm doing."
Be warned that you use unsafe Rust at your own risk.
If you use unsafe code incorrectly, problems can occur due to memory unsafety, such as null pointer dereferencing.
Rust has an unsafe alter ego is that the underlying computer hardware is inherently unsafe.
If Rust didn't allow us to do unsafe operations, you couldn't do certain tasks.
Rust needs to allow you to do low-level systems programming, such as directly interacting with the operating system or even writing your own operating system.
Working with low-level systems programming is one of the goals of the language.
## Unsafe Superpowers
To switch to unsafe Rust, you need to use the `unsafe` keyword and then start a new block that holds the unsafe code.
You can do five additional actions in unsafe Rust that you can't do in safe Rust, which we call *unsafe superpowers*.
These superpowers are:
- Dereference a raw pointer
- Call an unsafe function or method
- Access or modify a mutable static variable
- Implement an unsafe trait
- Access fields of a `union`
Note: `unsafe` does not turn off the borrow checker or disable any other of Rust's safety checks.
If you use a reference in unsafe code, it will still be checked.
The `unsafe` keyword only gives access to these five features that are then not checked by the compiler for memory safety.
You will still get some degree of safety inside of an unsafe block.
Additionally `unsafe` does not mean the code inside the block is necessarily dangerous or that it will definitely have memory safety problems.
The intent as the programmer, you will ensure the code inside an `unsafe` block will access memory in a valid way.
People are fallible, and mistakes will happen, but by requiring these five unsafe operations to be inside blocks annotated with `unsafe` you will know that any errors related to memory safety must be within an `unsafe` block.
Keep `unsafe` blocks small: you will be thankful later when you investigate memory bugs.
To isolate unsafe code as much as possible, it is best to enclose unsafe code within a safe abstraction and provide a safe API (This will be covered when we examine unsafe functions and methods).
Parts of the std library are implemented as safe abstractions over unsafe code that has been audited.
Wrapping unsafe code in a safe abstraction prevents uses of `unsafe` from leaking out into all the places that you want to use the functionality implemented with `unsafe` code, because using aa safe abstraction is safe.
Now we will look into each of the five unsafe superpowers.
We will also look at some abstractions that provide a safe interface to unsafe code.
## Deferencing a Raw Pointer
We mentioned before that the compiler ensures references are always valid.
Unsafe Rust has two new types called *raw pointers* that are similar to references
Raw pointers can be immutable or mutable, just like with references, are written as `*const T` and `*mut T`, respectively.
The asterisk isn't the dereference operator, it is part of the type name.
In the context of raw pointers, *immutable* means that the pointer can't be directly assigned to after being dereferenced.
Different from references and smart pointers, raw pointers:
- Are allowed to ignore the borrowing rules by having both immutable and mutable pointers or multiple mutable pointers to the same location
- Aren't guaranteed to point to valid memory
- Are allowed to be null
- Don't implement nay automatic cleanup
By opting out of Rust's enforced guarantees, you can give up safety in exchange for greater performance or the ability to interface with another language or hardware where Rust's guarantees don't apply.
Here is an example of how to create an immutable and a mutable raw pointer.
```rust
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
```
Note that we don't include the `unsafe` keyword here.
We can create raw pointers in safe code; we just can't dereference raw pointers outside an unsafe block (We will see this later).
We have created raw pointers by using the raw borrow operators.
`&raw const num` creates a `*const i32` immutable raw pointer.
`&raw mut num` creates a `*mut i32` mutable raw pointer.
Because we created them directly form a local variable, we know these particular raw pointers are valid, but we can't make that assumption about just any raw pointer.
In order to demonstrate this, we will create a raw pointer whose validity we can't be so certain of, using `as` to cast a value instead of using the raw reference operators.
This shows how to create a raw pointer to an arbitrary location in memory.
Trying to use arbitrary memory is undefined: there might be data at that address or there might not, the compiler might optimize the code so there is no memory access, or the program might error with a segmentation fault.
Usually there is no good reason to write code like this, especially in cases where you can use a raw borrow operator instead, but it is possible.
```rust
let address = 0x012345usize;
let r = address as *const i32;
```
Remember that we can create raw pointers in safe code, but we can't *dereference* raw pointers and read the data being pointed to.
Here we use the dereference operator `*` on a raw pointer that requires an `unsafe` block.
```rust
let mut num = 5;
let r1 = &raw const num;
let r2 = &raw mut num;
unsafe {
println!("r1 is: {}", *r1);
println!("r2 is: {}", *r2);
}
```
Creating a pointer does no hard. It is only when we attempt to access the value that it points at that we might end up dealing with an invalid value.
Note in the first and third example, we created `*const i32` and `*mut i32` raw pointers that both pointed to the same memory location where we `num` is stored.
If we instead tried to create an immutable and a mutable reference to `num`, the code would not have compiled because Rust's ownership rules don't allow a mutable reference at the same time as any immutable references.
With raw pointers, we can create a mutable pointer and an immutable pointer to the same location and change data through the mutable pointer, potentially create a data race.
With all of the dangers, why ever use raw pointers?
Once major use case is when interfacing with C code, as you will see in the next section ["Calling an Unsafe Function or Method"]().
Another case is when building up safe abstractions that the borrow checker doesn't understand.
We will introduce unsafe function and then look at an example of a safe abstraction that uses unsafe code.
## Calling an Unsafe Function or Method
The second type of superpower that you can perform in an unsafe block is calling unsafe functions.
Unsafe functions and methods look exactly like regular functions and methods, but they have an extra `unsafe` before the rest of the definitions.
The `unsafe` keyword indicates the function has requirements we need to uphold when we call this function, because Rust can't guarantee we have met these requirements.
By calling an unsafe function within an `unsafe` block, we are saying that we have read this function's documentation and take responsibility for upholding the function's contracts.
This code is an unsafe function named `dangerous` that doesn't do anything in its body
```rust
unsafe fn dangerous() {}
unsafe {
dangerous();
}
```
We must call the `dangerous` function within a separate `unsafe` block.
If we attempted to call `dangerous` without the `unsafe` block, we would get this error
```
$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0133]: call to unsafe function `dangerous` is unsafe and requires unsafe function or block
--> src/main.rs:4:5
|
4 | dangerous();
| ^^^^^^^^^^^ call to unsafe function
|
= note: consult the function's documentation for information on how to avoid undefined behavior
For more information about this error, try `rustc --explain E0133`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
```
With the `unsafe` block, we are asserting to Rust that we have read this function's documentation, we understand how to use it properly, and we have verified that we are fulfilling the contract of the function.
To perform unsafe operations in the body of an unsafe function you still need to use an `unsafe` block just as within a regular function, and the compiler will warn you if you forget.
This helps to keep `unsafe` blocks as small as possible, as unsafe operations may not be needed across the whole function body.
### Creating a Safe Abstraction over Unsafe Code
Just because a function contains unsafe code, this does mean we need to mark the entire function as unsafe.
In fact wrapping unsafe is a common abstraction.
For example, let's take a look at the `split_at_mut` function from the std library, which requires some unsafe code.
We will also explore how we might implement it.
This safe method is defined on mutable slices: it takes once slice and makes it two by splitting the slice at the index given as an argument.
Here is how to use `split_at_mut`
```rust
let mut v = vec![1, 2, 3, 4, 5, 6];
let r = &mut v[..];
let (a, b) = r.split_at_mut(3);
assert_eq!(a, &mut [1, 2, 3]);
assert_eq!(b, &mut [4, 5, 6]);
```
We can't implement this function using only safe Rust.
An attempt might look something like this, which will not compile.
For simplicity we will implement `split_at_mut` as a function rather than a method and only for slices of `i32` values rather than for a generic type `T`.
```rust
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
assert!(mid <= len);
(&mut values[..mid], &mut values[mid..])
}
```
This function first gets the total length of the slice.
Then it asserts that the index given as a parameter is within the slice by checking whether it is less than or equal to the length.
This assertion means that if we pass an index that is greater than the length to split the slice at, the function will panic before it attempts to use that index.
Next we return two mutable slices in a tuple, one form the start of the original slice to the `mid` index and another from `mid` to the end of the slice.
We get this compilation error
```
$ cargo run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
error[E0499]: cannot borrow `*values` as mutable more than once at a time
--> src/main.rs:6:31
|
1 | fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
| - let's call the lifetime of this reference `'1`
...
6 | (&mut values[..mid], &mut values[mid..])
| --------------------------^^^^^^--------
| | | |
| | | second mutable borrow occurs here
| | first mutable borrow occurs here
| returning this value requires that `*values` is borrowed for `'1`
|
= help: use `.split_at_mut(position)` to obtain two mutable non-overlapping sub-slices
For more information about this error, try `rustc --explain E0499`.
error: could not compile `unsafe-example` (bin "unsafe-example") due to 1 previous error
```
Rust's borrow checker can't understand that we are borrowing different parts of the slice.
It only knows that we are borrowing from the same slice twice.
Borrowing different parts of a slice fundamentally ok because the two slices aren't overlapping, but Rust isn't smart enough to know this.
When we know code is ok, but Rust doesn't, it is time to reach for unsafe code.
Below shows how to use an `unsafe` block, a raw pointer, and some calls to unsafe functions to make the implementation of `split_at_work`.
```rust
use std::slice;
fn split_at_mut(values: &mut [i32], mid: usize) -> (&mut [i32], &mut [i32]) {
let len = values.len();
let ptr = values.as_mut_ptr();
assert!(mid <= len);
unsafe {
(
slice::from_raw_parts_mut(ptr, mid),
slice::from_raw_parts_mut(ptr.add(mid), len - mid),
)
}
}
```
Remember from ["The Slice Type"](), from Ch4 that slices are a pointer to some data and the length of the slice.
We can use the `len` method to get the length of a slice and the `as_mut_ptr` method to access the raw pointer of a slice.
In this case because we have a mutable slice to `i32` values, `as_mut_ptr` returns a raw pointer with the type `*mut i32`, which we have stored in the variable `ptr`.
We keep the assertion that the `mid` index is within the slice.
Next we get to the unsafe code: the `slice::from_raw_parts_mut` function takes a raw pointer and a length, and it creates a slice.
We use this function to create a slice that starts from `ptr` and is `mid` items long.
Next we call the `add` method on `ptr` with `mid` as an argument to get a raw pointer that starts at `mid`, and we create a slice using that pointer and the remaining number of items after `mid` as the length.
The function `slice::from_raw_parts_mut` is unsafe because it takes a raw pointer and must trust that this pointer is valid.
The `add` method on raw pointers is also unsafe, because it must trust that the offset location is also a valid pointer.
We have to put this in an `unsafe` block around our calls to `slice::from_raw_parts_mut` and `add` so we could call them.
By looking at the code and by adding the assertion that `mid` must be less than or equal to `len`.
We can tell that all the raw pointers used within the `unsafe` block will be valid pointers to data within the slice.
This is an acceptable and appropriate use of `unsafe`.
Notice that we don't need to mark the resulting `split_at_mut` function as `unsafe`.
We can call this function form safe Rust.
We have created a safe abstraction to the unsafe code with an implementation of the function that uses `unsafe` code in a safe way, because it creates only valid pointers from the data this function has access to.
By contrast, the use of `slice::from_raw_parts_mut` here would likely crash when the slice is used.
This code takes an arbitrary memory location and creates a slice 10,000 items long.
```rust
use std::slice;
let address = 0x01234usize;
let r = address as *mut i32;
let values: &[i32] = unsafe { slice::from_raw_parts_mut(r, 10000) };
```
We don't own the memory at this arbitrary location and there is no guarantee that the slice this code creates contains valid `i32` values.
Attempting to use `values` as though it's aa valid slice results in undefined behavior.
## Using `extern` Functions to Call External Code
Sometimes, your Rust code might need to interact with code written in another language.
To enable this, Rust has the keyword `extern` that facilitates the creation and use of a *Foreign Function Interface (FFI)*.
An FFI is a way for a programming language to defined functions and enable a different (foreign) programming language to call those functions.
This code demonstrates how to set up an integration with the `abs` function form the C std library.
Functions declared within `extern` blocks are usually unsafe to call from Rust code, so they must also be marked `unsafe`.
The reason is that other languages don't enforce Rust's rules and guarantees, and Rust can't check them, so the responsibility falls on the programmer to ensure safety.
```rust
unsafe extern "C" {
fn abs(input: i32) -> i32;
}
fn main() {
unsafe {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
}
```
Within the `unsafe extern "C"` block, we list the names and signatures of external functions from another language we want to call.
The `"C"` part defines which *application binary interface (ABI)* the external function uses: the ABI defines how to call the function at the assembly level.
The `"C"` ABI is the most common and follows the C programming language's ABI.
This particular function does not have any memory safety considerations.
In fact, we know that any call to `aabs` will always be safe for any `i32`, so we can use the `safe` keyword to say that this specific function is safe to call even though it is in an `unsafe extern` block.
Once we make this change, calling it no longer requires an `unsafe` block.
Here is the updated code
```rust
unsafe extern "C" {
safe fn abs(input: i32) -> i32;
}
fn main() {
println!("Absolute value of -3 according to C: {}", abs(-3));
}
```
Marking a function as `safe` does not inherently make it safe.
Instead, it is like a promise you are making to Rust that it *is* safe.
It is still your responsibility to make sure that the promise is kept.
### Calling Rust Functions form Other Languages
You can also use `extern` to create an interface that allows other languages to call Rust functions.
Instead of creating a whole `extern` block, we add the `extern` keyword and specify the ABI to use before the `fn` keyword for the relevant function.
Additionally we need to add a `#[unsafe(no_mangle)]` annotation to tell the Rust compiler not to mange the name of this function.
*Mangling* is when a compiler changes the name we have given a function to a different name that contains more information for other parts of the compilation process to consume but is less human readable.
Every programming language compiler mangles names slightly differently, so for a Rust function to be nameable by other languages, we must disable the Rust compiler's name mangling.
This is unsafe because there might be name collisions across libraries with the built-in mangling, so it is our responsibility to make sure the name we have exported is safe to export without mangling.
Here we make the `call_from_c` function accessible from C code, after it is compiled to a shared library and linked from C
```rust
#[unsafe(no_mangle)]
pub extern "C" fn call_from_c() {
println!("Just called a Rust function from C!");
}
```
This usage of `extern` does not require `unsafe`
## Accessing or Modifying a Mutable Static Variable
So far we have not talked about `global variables`, which Rust does support but can be problematic with Rust's ownership rules.
If two threads are accessing the same mutable global variable, it can cause a data race.
In Rust, global variables are called *static* variables.
Here shows an example declaration and use of a static variable with a string slice as a value.
```rust
static HELLO_WORLD: &str = "Hello, world!";
fn main() {
println!("name is: {HELLO_WORLD}");
}
```
Static variables are similar to constants, which we discussed in the ["Constants"]() section in Ch3.
The names of static variables are in `SCREAMING_SNAKE_CASE` by convention.
Static variables can only store references with the `'static` lifetime.
This means the Rust compiler can figure out the lifetime and we aren't required to annotate it explicitly.
Accessing an immutable static variable is safe.
A subtle difference between constants and immutable static variables is that values in a static variable have a fixed address in memory.
Using the value will always access the same data.
Constants, on the other hand are allowed to duplicate their data whenever they are used.
Another difference is that static variables can by mutable.
Accessing and modifying mutable static variables is *unsafe*.
Here shows how to declare, access and modify a mutable static variable named `COUNTER`.
```rust
static mut COUNTER: u32 = 0;
/// SAFETY: Calling this from more than a single thread at a time is undefined
/// behavior, so you *must* guarantee you only call it from a single thread at
/// a time.
unsafe fn add_to_count(inc: u32) {
unsafe {
COUNTER += inc;
}
}
fn main() {
unsafe {
// SAFETY: This is only called from a single thread in `main`.
add_to_count(3);
println!("COUNTER: {}", *(&raw const COUNTER));
}
}
```
Just like with regular variables, we specify mutability using the `mut` keyword.
Any code that reads or writes from `COUNTER` must be within an `unsafe` block.
The code above compiles and prints `COUNTER: 3` as expected because it is single threaded.
Having multiple thread access `COUNTER` would likely result in data races, so it is undefined behavior.
Due to this we need to mark the entire function as `unsafe` and document the safety limitation, so anyone calling this function knows what they are and are not allowed to do safely.
Whenever we write an unsafe function, it is idiomatic to write a comment starting with `SAFETY` and explaining what the caller needs to do to call the function safely.
Also whenever we perform an unsafe operation it is idiomatic to write a comment starting with `SAFETY` to explain how the safety rules are upheld.
As well, the compiler will not allow you to create references to a mutable static variable.
You can only access it via a raw pointer, created with one of the raw borrow operators.
This includes in cases where the reference is created invisibly as when it is used in the `println!` in this code listing.
The requirement that references to static mutable variables can only be created via raw pointers helps make the safety requirements for using them more obvious.
With mutable data that is globally accessible, it is difficult to ensure that there are no data races, which is why Rust considers mutable static variables to be unsafe.
Where it is possible it is preferred to use concurrency techniques and thread-safe smart pointers, so the compiler checks that data accessed from different threads is done safely.
## Implementing an Unsafe Trait
Additionally `unsafe` to implement an unsafe trait.
A trait is unsafe when at least one of its methods has some invariant that the compiler can't verify.
We declare that a trait is `unsafe` by adding the `unsafe` keyword before `trait` and marking the implementation of the trait as `unsafe` too.
Here is an example of this
```rust
unsafe trait Foo {
// methods go here
}
unsafe impl Foo for i32 {
// method implementations go here
}
fn main() {}
```
By using `unsafe impl`, we are promising that we will uphold the invariants that the compiler can't verify.
As an example, recall the `Sync` and `Send` marker traits we discussed in ["Extensible Concurrency with the `Sync` and `Send` Traits"]() section.
The compiler implements these traits automatically if our types are composed entirely of `Send` and `Sync` types.
If we implement a type that contains a type that is not `Send` or `Sync`, such as raw pointers, and we want to mark that type as `Send` or `Sync`, we must use `unsafe`.
Rust can't verify that our type upholds the guarantees that it can be safely sent across threads or accessed form multiple threads.
We need to do these checks manually and indicate as such with `unsafe`.
## Accessing Fields of a Union
The last superpower that works on with `unsafe` is accessing fields of a *union*.
A `union` is similar to a `struct`, but only one declared field is used in a particular instance at one time.
Unions are primarily used to interface with unions in C code.
Accessing union fields is unsafe because Rust can't guarantee the type of data currently being stored in the union instance.
You can learn more about unions in [the Rust Reference](https://doc.rust-lang.org/reference/items/unions.html).
## Using Miri to check unsafe code
When writing unsafe code, you may want to check that you have written actually is safe and correct.
Using [Miri](https://github.com/rust-lang/miri), an official Rust tool for detecting undefined behavior is one of the best ways to do it.
While the borrow checker is a *static* tool which works at compile time, Miri is a *dynamic* tool which works at runtime.
It checks your code by running your program or its test suite and detecting when you violate the rules it understands about how Rust should work.
Miri requires a nightly build of Rust (discussed in [Appendix G: How Rust is Made and "Nightly Rust"](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html)).
You can install both a nightly version of Rust and the Miri tool by typing `rustup +nightly component add miri`.
This does not change what version of Rust your project uses.
This only adds the tool to your system so you can use it when you want to.
You can run Miri on a project by typing cargo `+nightly miri run` or `cargo +nightly miri test`.
Here is an example of how useful when we run it on a previous example
```
$ cargo +nightly miri run
Compiling unsafe-example v0.1.0 (file:///projects/unsafe-example)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.01s
Running `/Users/chris/.rustup/toolchains/nightly-aarch64-apple-darwin/bin/cargo-miri runner target/miri/aarch64-apple-darwin/debug/unsafe-example`
warning: creating a shared reference to mutable static is discouraged
--> src/main.rs:14:33
|
14 | println!("COUNTER: {}", COUNTER);
| ^^^^^^^ shared reference to mutable static
|
= note: for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html>
= note: shared references to mutable statics are dangerous; it's undefined behavior if the static is mutated or if a mutable reference is created for it while the shared reference lives
= note: `#[warn(static_mut_refs)]` on by default
COUNTER: 3
```
It helpfully and correctly notices that we have shared references to mutable data and warns about it.
Here it does not tell us how to fix the problem, but it mean that we know there is a possible issue and can think about how to make sure it is safe.
In other cases, it can actually tell us that some code is *sure* to be wrong and make recommendations about how to fix it.
Miri will not catch *everything* you may get wrong when writing unsafe code.
Since it is a dynamic check, it only catches problems with code that actually gets run.
This means you will need to use it with good testing techniques to increase your confidence about the unsafe code you have written.
Additionally it does not cover every possible way your code can be unsound.
If Miri *does* catch a problem, you know that there is a bug, but just because Miri *doesn't* catch a bug doesn't mean there isn't a problem.
Miri can catch a lot despite this.
## When to Use Unsafe Code
Using `unsfe` to take one of the five superpowers, isn't wrong or frowned upon.
But it is trickier to get `unsafe` code correct because the compiler can't help uphold memory safety.
When you have a reason to use `unsafe` code, you can do so and having the explicit `unsafe` annotation makes it easier to tack down the source of problems when they occur.
When you write unsafe code, you can use Miri to help to be more confident that the code you wrote upholds Rust's rules.
For a deeper exploration of how to work effectively with unsafe Rust, read Rust's official guide on the subject the [Rustonomicon](https://doc.rust-lang.org/nomicon/).

265
Using Box on the Heap.md Normal file
View File

@ -0,0 +1,265 @@
# Using `Box<T>` to Point ot Data on the Heap
This is the most straightforward smart inter is a *box*, whose tpye is written `Box<T>`.
Boxes allow you to store data on the heap rather than the stack.
What remains on the stack is the pointer the heap data.
Boxes don't have performance overhead, other than storing thier data on the heap instead of on the stack.
They don't have many extra capabilities either.
You often use them in these situation:
- When you have a type whose size can't be known at compile time and you want to use a value of that type in a context that requires an exact size.
- When you have a large amount of data and you want to transfer ownership but ensure the data won't be copied when you do so.
- When you want to own a value and you only care that it's a type that implements a particular trait rather than being of a specific type.
We will demonstrate the first point in the [Enabling Recursive Types with Boxes](#enabling-recursive-types-with-boxes) section.
The second point, transferring ownership of large amount of data can take a long time because the data is copied around on the stack.
To improve performance in this situation, we can store the large amount of data on the heap in a box.
Then only the small amount of pointer data is copied around on the stack, while the data it references stays in one place on the heap.
The third case iis known as a *trait object* and another chapter is devoted entirely to this.
## Using a `Box<T>` to Store Data on the Heap
Before discussing the heap storage use case of `Box<T>`.
We will first cover the syntax and how to interact with values stored within a `Box<T>`
Here us an example of how to use a box to store an `i32` value on the heap
```rust
fn main() {
let b = Box::new(5);
println!("b = {b}");
}
```
Here we define the variable `b` to have the value of a `Box` that points to the value `5`. This is allocated on the heap.
This program will output `b = 5`.
In this case we can access the data in the box similar to how it would be stored on the stack.
Just like any owned value, when a box goes out of scope, as `b` does at the end of `main`, it will be deallocated.
The deallocation happens both for the box (stored on the stack) and the data it points to (stored on the heap).
Putting a single value on the heap isnt very useful, so you won't use boxes by themselves in this way often.
Having a value like a single `i32` on the stack, where they are stored by default is more appropriate in the majority of situations.
Now lets look at a case where oxe allow us to define types that we wouldn't be allowed to if we didn't have boxes
## Enabling Recursive Types with Boxes
A value of *recursive type* can have another value of the same tpye as part of itself.
These types pose an issue because at compile time Rust needs to know how much space a type takes up.
However, the nesting of values of recursive types could theoretically continue infinitelym so Rust cant know how much spcae the value needs.
Due to boxes having a knwon size, we can enable recursive types by inserting a box in the recursive type definition.
As an example of a recursive type, lets explore the *cons list*.
This data type is commonly found in functional programming languages.
The cons list type we will define is straightforward except for the recursion, this means the cencepts in the example we will work with will be useful any time you get into more complex situations involving recursive types.
### More Information About the Cons List
This data structure comes from the Lisp programming language and its dialects and is made up of nested pairs, and is the Lisp version of a linked list.
The name comes form the `cons` function (short for "construct function") in Lisp that constructs a new pair form its two arguments.
By calling `cons` on a pair consisting of a value and another pai, we can construct cons lists made up of recursive pairs.
Here is a pseudocode representation of a cons list containing the list 1, 2, 3 with each pair in parentheses
```
(1, (2, (3, Nil)))
```
Each item is a cons list contains tow elements
1. The value of the current item
2. The next item
The last item in the list only contains only a value called `Nil` without a next item.
A cons list is produced by recursively calling the `cons` function.
The canonical name to denote the base case of the recursion is `Nil`
This is ot the same as the "null" or "nil" concept, which is an invalid or absent value.
The cons list isn't a commonly ued data struct in Rust.
Most of the time when you have a list of items in Rust, `Vec<T>` is a better choice to use.
Other, more complex recursive data types are useful in various situations but by starting with a basic type like the cons list.
We can now explore how boxes let us define a recursive data type without much distraction.
In this example, it contains an enum definition ofr a cons list.
This will not compile yet because the `List` type doesn't have a known size
```rust
enum List {
Cons(i32, List),
Nil,
}
```
Note: We are implementing a cons list that holds only `i32` values for the purpose of this example.
We could have done this with generics to define a cons list type that could store values of any type.
Using the `List` type to store the list `1, 2, 3` would look like this next example
```rust
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Cons(2, Cons(3, Nil)));
}
```
The first `Cons` value holds `1` and another `List` value.
This `List` value is another `Cons` value tha holds `2` and naother `List` value.
This `List` value also contains one more `Cons` value that hoolds `3` and a `List` value, which is finally `Nil`, the non-recursive variant that signals the end of the list
If we try to compile this we would get an error like this
```
$ cargo run
Compiling cons-list v0.1.0 (file:///projects/cons-list)
error[E0072]: recursive type `List` has infinite size
--> src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
2 | Cons(i32, List),
| ---- recursive without indirection
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
2 | Cons(i32, Box<List>),
| ++++ +
error[E0391]: cycle detected when computing when `List` needs drop
--> src/main.rs:1:1
|
1 | enum List {
| ^^^^^^^^^
|
= note: ...which immediately requires computing when `List` needs drop again
= note: cycle used when computing whether `List` needs drop
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information
Some errors have detailed explanations: E0072, E0391.
For more information about an error, try `rustc --explain E0072`.
error: could not compile `cons-list` (bin "cons-list") due to 2 previous errors
```
The errors states that this type "has infinite size".
The reason is that we defined `List` with a variant that is recursive.
It holds another value of itself directly.
This results in Rust being unable to figure out how much space t needs to store a `List` value.
Lets look in detail at why we get this error, first we will look at how Rust decides how much space it needs to store a value of a non-recursive type.
### Computing the Size of a Non-Recursive Type
If we recall the `Message` enum that we defined previously
```rust
enum Message {
Quit,
Move { x: i32, y: i32 },
Write(String),
ChangeColor(i32, i32, i32),
}
```
In order to determine how much space to allocate for a `Message` value, RUst goes through each of the variants to see which variantneeds the msot space.
Rust see that:
- `Message::Quit` doesnt need any space
- `Message::Move` needs enough space to store two `i32` values
- etc.
Because only one variant will be used, the most space a `Message` value will need is the space it would take to store the largest of its variants.
Contrast this with what happens when Rust attempts to determine how much space a recursive type like `List` enum needs.
The compiler starts by looking at the `Cons` variant, which holds a value if type `32` and a value of a type `List`.
Therefore `Cons` needs an amount of space equal to the size of an `i32` plus the size of a `List`
To figure out how much memory the `List` type needs the compiler looks at the variants, starting with the `Cons` variant.
The `Cons` variant holds a value of type `i32` and a value of type `List` and this process continues infinitely
Here is a picture that demonstrates what it looks like
<img src="https://doc.rust-lang.org/book/img/trpl15-01.svg" />
### Using `Box<T>` to Get a Recursive Type with a Known Size
Due to Rust not being able to figure out how much space to allocate for recursively defined tpyes, the compiler gives an error with this great suggestion
```
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle
|
2 | Cons(i32, Box<List>),
| ++++ +
```
In this suggestion "indirection" means that instead of storeing a value directly, we should change the data struct to store the value indirectly by storeing a pointer to the value instead.
Due to `Box<T>` being a pointer, Rust will always know how much space a `Box<T>` needs.
A pointer's size doesnt change based on the kind of data it is pointing to.
This means that we can put a `Box<T>` inside the `Cons` variant instead of directly anthoer `List` value directly.
The `Box<T>` will point ot the next `List` value that will be on the heap rather than inside the `Cons` variant.
Conceptually we still have a list, created with lists holding other lists.
Now with this implementaion it is now more like placing the items next to one another rather than inside one another.
We can now change the defintiion of the `List` enum and the usage of the `List`.
This will now compile.
```rust
enum List {
Cons(i32, Box<List>),
Nil,
}
use crate::List::{Cons, Nil};
fn main() {
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
}
```
The `Cons` varienat needs the size of an `i32` plus the sapce to store the box's pointer data.
The `Nil` variant stores no values so it needs less space than the `Cons` variant.
By using boxes we have borken the infinite, recursive chain.
Now the compiler can figure out the size it needs to store a `List` value.
Here is what the `Cons` variant looks like now
<img src="https://doc.rust-lang.org/book/img/trpl15-02.svg" />
Boxes provide only the indirection and heap allocation.
They do not have any other special capabilities unlike those we will see with the other smart pointer types.
They also dont have the performance overhead that these special capabilities incur so they can be usefil in cases like the cons list where the indirection is the only feature we need.
Boxes uses cases will also be covered later as well in more detail.
The `Box<T>` tpye is a smart pointer because it implements the `Deref` trait which allows `Box<T> values to be treated like refs.
When a `Box<T>` value goes out of scope, the heap data that the box is pointing to is cleaned up as well, due to the `Drop` trait implementation.
These two traits will be even more important to the functionality provided by the other smart pointer tpyes.
Now we will go into these two traits in more detail.
- [`Deref` Trait Quick Link](./Deref%20Trait.md)

1510
actix_web_learning/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
[package]
name = "actix_web_learning"
version = "0.1.0"
edition = "2024"
[dependencies]
actix-web = "4"
serde = { version = "1.0", features = ["derive"] }

View File

@ -0,0 +1,40 @@
use actix_web::{get, post, HttpResponse, Responder};
pub fn add(left: u64, right: u64) -> u64 {
left + right
}
#[get("/")]
pub async fn hello() -> impl Responder {
HttpResponse::Ok().body("Hello world!")
}
#[post("/echo")]
pub async fn echo(req_body: String) -> impl Responder {
HttpResponse::Ok().body(req_body)
}
pub async fn manual_hello() -> impl Responder {
HttpResponse::Ok().body("Hello there!\nGeneral Kenobi")
}
// the path to get to the html response
#[get("/resend")]
// function signature, data that is passed in, return type must implement the Responder trait
pub async fn resend(req_body: String) -> impl Responder {
// this returns a html response with a 200 code
// this should be used for final serialization
// possibly main functionality
HttpResponse::Ok().body(req_body)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}

View File

@ -0,0 +1,17 @@
use actix_web::{web, App, HttpServer};
use actix_web_learning::{hello, echo, resend, manual_hello};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.service(hello)
.service(echo)
.service(resend)
.route("/hey", web::get().to(manual_hello))
})
.bind(("darkicen950.local", 8080))?
.run()
.await
}

7
adder/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "adder"
version = "0.1.0"

View File

@ -1 +1 @@
{"rustc_fingerprint":13662911779824945272,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.83.0 (90b35a623 2024-11-26)\nbinary: rustc\ncommit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf\ncommit-date: 2024-11-26\nhost: x86_64-pc-windows-msvc\nrelease: 1.83.0\nLLVM version: 19.1.1\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"lahfsahf\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"128\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"128\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nub_checks\nwindows\n","stderr":""},"12744816824612481171":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":517133967738620428,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.86.0 (05f9846f8 2025-03-31)\nbinary: rustc\ncommit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb\ncommit-date: 2025-03-31\nhost: x86_64-pc-windows-msvc\nrelease: 1.86.0\nLLVM version: 19.1.7\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}

2127
hello-async/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

7
hello-async/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "hello-async"
version = "0.1.0"
edition = "2024"
[dependencies]
trpl = "0.2.0"

21
hello-async/src/main.rs Normal file
View File

@ -0,0 +1,21 @@
extern crate trpl;
use trpl::Html;
async fn main() {
let args: Vec<String> = std::env::args().collect();
let url = &args[1];
match page_title(url).await {
Some(title) => println!("The title for {url} was {title}"),
None => println!("{url} had no title"),
}
}
async fn page_title(url: &str) -> Option<String> {
let res = trpl::get(url).await;
let res_text = res.text().await;
Html::parse(&res_text)
.select_first("title")
.map(|title_element| title_element.inner_html())
}

11
hello/404.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello!</title>
</head>
<body>
<h1>Oops!</h1>
<p>Sorry, I don't know what you're asking for.</p>
</body>
</html>

7
hello/Cargo.lock generated Normal file
View File

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "hello"
version = "0.1.0"

6
hello/Cargo.toml Normal file
View File

@ -0,0 +1,6 @@
[package]
name = "hello"
version = "0.1.0"
edition = "2024"
[dependencies]

11
hello/hello.html Normal file
View File

@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Hello!</title>
</head>
<body>
<h1>Hello!</h1>
<p>Hi from Rust</p>
</body>
</html>

82
hello/src/lib.rs Normal file
View File

@ -0,0 +1,82 @@
use std::{ sync::{ mpsc, Mutex, Arc }, thread };
pub struct ThreadPool {
workers: Vec<Worker>,
sender: Option<mpsc::Sender<Job>>,
}
impl ThreadPool {
/// Create a new ThreadPool.
///
/// The size is the number of threads in the pool.
///
/// # Panics
///
/// The `new` function will panic if the size is zero.
pub fn new(size: usize) -> ThreadPool {
assert!(size > 0);
let (sender, receiver) = mpsc::channel();
let receiver = Arc::new(Mutex::new(receiver));
let mut workers = Vec::with_capacity(size);
for id in 0..size {
workers.push(Worker::new(id, Arc::clone(&receiver)));
}
ThreadPool { workers, sender: Some(sender) }
}
pub fn execute<F>(&self, f: F) where F: FnOnce() + Send + 'static {
let job = Box::new(f);
self.sender.as_ref().unwrap().send(job).unwrap();
}
// ambitious side project
// pub fn build(size: usize) -> Result<ThreadPool, PoolCreationError> {}
}
impl Drop for ThreadPool {
fn drop(&mut self) {
drop(self.sender.take());
for worker in &mut self.workers.drain(..) {
println!("Shutting down worker {}", worker.id);
worker.thread.join().unwrap();
}
}
}
struct Worker {
id: usize,
thread: thread::JoinHandle<()>,
}
impl Worker {
fn new(id: usize, receiver: Arc<Mutex<mpsc::Receiver<Job>>>) -> Worker {
let thread = thread::spawn(move || {
loop {
let message = receiver.lock().unwrap().recv();
match message {
Ok(job) => {
println!("Worker {id} got a job; executing");
job();
}
Err(_) => {
println!("Worker {id} disconnected; shutting down.");
break;
}
}
}
});
Worker { id, thread }
}
}
type Job = Box<dyn FnOnce() + Send + 'static>;

74
hello/src/main.rs Normal file
View File

@ -0,0 +1,74 @@
use std::{
fs,
io::{ prelude::*, BufReader },
net::{ TcpListener, TcpStream },
thread,
time::Duration,
};
use hello::ThreadPool;
fn main() {
// this is not related I was just curious
// let test = fs::read_to_string("test.yaml").unwrap();
// println!("{}", test);
let listener = TcpListener::bind("127.0.0.1:7878").unwrap();
let pool = ThreadPool::new(4);
for stream in listener.incoming().take(2) {
let stream = stream.unwrap();
pool.execute(|| {
handle_connection(stream);
});
}
println!("Shutting down.");
}
fn handle_connection(mut stream: TcpStream) {
let buf_reader = BufReader::new(&stream);
// let http_request: Vec<_> = buf_reader
// .lines()
// .map(|result| result.unwrap())
// .take_while(|line| !line.is_empty())
// .collect();
let request_line = buf_reader.lines().next().unwrap().unwrap();
// no longer needed, here for debug and being useful
// println!("Request: {:#?}", http_request);
// if request_line == "GET / HTTP/1.1" {
// let status_line = "HTTP/1.1 200 OK";
// let contents = fs::read_to_string("./hello.html").unwrap();
// let length = contents.len();
// let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
// stream.write_all(res.as_bytes()).unwrap();
// } else {
// let status_line = "HTTP/1.1 404 NOT FOUND";
// let contents = fs::read_to_string("404.html").unwrap();
// let length = contents.len();
// let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
// stream.write_all(res.as_bytes()).unwrap();
// }
let (status_line, filename) = match &request_line[..] {
"GET / HTTP/1.1" => ("HTTP/1.1 200 OK", "hello.html"),
"GET /sleep HTTP/1.1" => {
thread::sleep(Duration::from_secs(5));
("HTTP/1.1 200 OK", "hello.html")
}
_ => ("HTTP/1.1 404 NOT FOUND", "404.html"),
};
let contents = fs::read_to_string(filename).unwrap();
let length = contents.len();
let res = format!("{status_line}\r\nContent-Length: {length}\r\n\r\n{contents}");
stream.write_all(res.as_bytes()).unwrap();
}

41
hello/test.yaml Normal file
View File

@ -0,0 +1,41 @@
Diamond Tier:
- Schulich School of Engineering:
LogoUrl: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQj9L3ZGK6WtOmJbzxmCzRxwLXYKGC5SDcAKHb0ScfbUmbtG0IujQt6eQDaI_Pm9g4DZvc&usqp=CAU
Url: https://schulich.ucalgary.ca/
DescriptionAboutSponsor: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce eu magna in diam consectetur rhoncus vel nec turpis. Sed finibus mi eu sem varius faucibus. Donec semper erat et bibendum pharetra. Suspendisse cursus lorem sed nisi semper, a rutrum nunc luctus. Nunc ullamcorper enim id orci interdum ultrices. Donec vestibulum nunc vel nisl pretium tempus. Morbi quis ante et ligula eleifend eleifend. Proin bibendum maximus elit vitae congue. Vivamus egestas, ex in tempor posuere, ligula nunc iaculis massa, in imperdiet dui justo eu dolor. Nullam placerat velit quis sem mattis, laoreet pharetra elit tempor.
Platinum Tier:
- Platinum Sponsor Name:
LogoUrl:
Url:
DescriptionAboutSponsor:
Gold Tier:
- Suri:
LogoUrl: https://lh5.googleusercontent.com/WJsBsmcLypQhY0MMOLQtJSGFXrLQqPKNc3502rYUGKPCq_SfS9CxuoB3n541Kn9bKPm2b5aixCnYsCVYZAts2Y8xvmOHWL3nnbKtWUkE1KoFYYQ4bXUlikfF0NPIynxhzQ=w1280
Url: https://www.surimanufacturing.com/
DescriptionAboutSponsor:
- SKF:
LogoUrl: https://www.skf.com/v2/assets/img/skf-logo-white.svg
Url: https://www.skf.com/ca/en
DescriptionAboutSponsor: I am not sure
- WRMA:
LogoUrl: https://wildrosemx.com/wp-content/uploads/2021/08/wild-rose-motocross-calgary-rasterized.png
Url: https://wildrosemx.com/
DescriptionAboutSponsor:
Silver Tier:
- Encore Metals:
LogoUrl: https://www.encoremetals.com/assets/images/logos/encore-metals-logo.png
Url: https://www.encoremetals.com/
DescriptionAboutSponsor: Metal supplier
- CNOOC:
LogoUrl: https://cnoocinternational.com/img/cnooc-logo.png
Url: https://cnoocinternational.com/
DescriptionAboutSponsor:
Bronze Tier:
- Redbull:
LogoUrl: "https://img.redbull.com/redbullcom/static/redbullcom-logo_double-with-text.svg"
Url: https://www.redbull.com/ca-en/
DescriptionAboutSponsor:
- Canada Action:
LogoUrl:
Url:
DescriptionAboutSponsor:

View File

@ -1 +1 @@
{"rustc_fingerprint":13662911779824945272,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\nfmt_debug=\"full\"\noverflow_checks\npanic=\"unwind\"\nproc_macro\nrelocation_model=\"pic\"\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"lahfsahf\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_has_atomic_equal_alignment=\"128\"\ntarget_has_atomic_equal_alignment=\"16\"\ntarget_has_atomic_equal_alignment=\"32\"\ntarget_has_atomic_equal_alignment=\"64\"\ntarget_has_atomic_equal_alignment=\"8\"\ntarget_has_atomic_equal_alignment=\"ptr\"\ntarget_has_atomic_load_store\ntarget_has_atomic_load_store=\"128\"\ntarget_has_atomic_load_store=\"16\"\ntarget_has_atomic_load_store=\"32\"\ntarget_has_atomic_load_store=\"64\"\ntarget_has_atomic_load_store=\"8\"\ntarget_has_atomic_load_store=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_thread_local\ntarget_vendor=\"pc\"\nub_checks\nwindows\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.83.0 (90b35a623 2024-11-26)\nbinary: rustc\ncommit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf\ncommit-date: 2024-11-26\nhost: x86_64-pc-windows-msvc\nrelease: 1.83.0\nLLVM version: 19.1.1\n","stderr":""},"12744816824612481171":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":517133967738620428,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.86.0 (05f9846f8 2025-03-31)\nbinary: rustc\ncommit-hash: 05f9846f893b09a1be1fc8560e33fc3c815cfecb\ncommit-date: 2025-03-31\nhost: x86_64-pc-windows-msvc\nrelease: 1.86.0\nLLVM version: 19.1.7\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\Brock\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}

View File

@ -10,17 +10,43 @@ pub struct Config {
}
impl Config {
pub fn build(args: &[String]) -> Result<Config, &'static str> {
if args.len() < 3 {
return Err("not enough arguments");
}
// refactor 14
// pub fn build(args: &[String]) -> Result<Config, &'static str> {
// if args.len() < 3 {
// return Err("not enough arguments");
// }
let query = args[1].clone();
let file_path = args[2].clone();
// let query = args[1].clone();
// let file_path = args[2].clone();
// let ignore_case = env::var("IGNORE_CASE").is_ok();
// Ok(Config { query, file_path, ignore_case })
// }
pub fn build(mut args: impl Iterator<Item = String>,) -> Result<Config, &'static str> {
// --snip-- for now
// skip first value in iterator, value inside is name of program
args.next();
let query = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a query string"),
};
let file_path = match args.next() {
Some(arg) => arg,
None => return Err("Didn't get a file path")
};
let ignore_case = env::var("IGNORE_CASE").is_ok();
Ok(Config { query, file_path, ignore_case })
Ok(Config {
query,
file_path,
ignore_case,
})
}
}
@ -49,17 +75,23 @@ pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
}
pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
// original that only can fail
// vec![]
let mut results = Vec::new();
// refacotr 15
// // original that only can fail
// // vec![]
// let mut results = Vec::new();
for line in contents.lines() {
if line.contains(query) {
// do something with line
results.push(line);
}
}
results
// for line in contents.lines() {
// if line.contains(query) {
// // do something with line
// results.push(line);
// }
// }
// results
contents
.lines()
.filter(|line| line.contains(query))
.collect()
}
pub fn search_case_insensitive<'a>(

View File

@ -6,7 +6,8 @@ use std::process;
use minigrep::Config;
fn main() {
let args: Vec<String> = env::args().collect();
// refactor 13
// let args: Vec<String> = env::args().collect();
// dbg!(args);
@ -22,11 +23,17 @@ fn main() {
// refactor 3
// let config = Config::new(&args);
// recfactor 6
let config = Config::build(&args).unwrap_or_else(|err| {
// refactor 14
// println!("Problem parsing arguments: {err}");
// process::exit(1);
// // recfactor 6
// let config = Config::build(&args).unwrap_or_else(|err| {
// // refactor 14
// // println!("Problem parsing arguments: {err}");
// // process::exit(1);
// eprintln!("Problem parsing arguments: {err}");
// process::exit(1);
// });
// refactor 13
let config = Config::build(env::args()).unwrap_or_else(|err| {
eprintln!("Problem parsing arguments: {err}");
process::exit(1);
});