Skip to content

Commit 9b06f59

Browse files
committed
feat: add async exercises
1 parent e73fff3 commit 9b06f59

35 files changed

+268
-36
lines changed

dev/Cargo.toml

Lines changed: 31 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -164,30 +164,34 @@ bin = [
164164
{ name = "threads2_sol", path = "../solutions/20_threads/threads2.rs" },
165165
{ name = "threads3", path = "../exercises/20_threads/threads3.rs" },
166166
{ name = "threads3_sol", path = "../solutions/20_threads/threads3.rs" },
167-
{ name = "macros1", path = "../exercises/21_macros/macros1.rs" },
168-
{ name = "macros1_sol", path = "../solutions/21_macros/macros1.rs" },
169-
{ name = "macros2", path = "../exercises/21_macros/macros2.rs" },
170-
{ name = "macros2_sol", path = "../solutions/21_macros/macros2.rs" },
171-
{ name = "macros3", path = "../exercises/21_macros/macros3.rs" },
172-
{ name = "macros3_sol", path = "../solutions/21_macros/macros3.rs" },
173-
{ name = "macros4", path = "../exercises/21_macros/macros4.rs" },
174-
{ name = "macros4_sol", path = "../solutions/21_macros/macros4.rs" },
175-
{ name = "clippy1", path = "../exercises/22_clippy/clippy1.rs" },
176-
{ name = "clippy1_sol", path = "../solutions/22_clippy/clippy1.rs" },
177-
{ name = "clippy2", path = "../exercises/22_clippy/clippy2.rs" },
178-
{ name = "clippy2_sol", path = "../solutions/22_clippy/clippy2.rs" },
179-
{ name = "clippy3", path = "../exercises/22_clippy/clippy3.rs" },
180-
{ name = "clippy3_sol", path = "../solutions/22_clippy/clippy3.rs" },
181-
{ name = "using_as", path = "../exercises/23_conversions/using_as.rs" },
182-
{ name = "using_as_sol", path = "../solutions/23_conversions/using_as.rs" },
183-
{ name = "from_into", path = "../exercises/23_conversions/from_into.rs" },
184-
{ name = "from_into_sol", path = "../solutions/23_conversions/from_into.rs" },
185-
{ name = "from_str", path = "../exercises/23_conversions/from_str.rs" },
186-
{ name = "from_str_sol", path = "../solutions/23_conversions/from_str.rs" },
187-
{ name = "try_from_into", path = "../exercises/23_conversions/try_from_into.rs" },
188-
{ name = "try_from_into_sol", path = "../solutions/23_conversions/try_from_into.rs" },
189-
{ name = "as_ref_mut", path = "../exercises/23_conversions/as_ref_mut.rs" },
190-
{ name = "as_ref_mut_sol", path = "../solutions/23_conversions/as_ref_mut.rs" },
167+
{ name = "async1", path = "../exercises/21_async/async1.rs" },
168+
{ name = "async1_sol", path = "../solutions/21_async/async1.rs" },
169+
{ name = "async2", path = "../exercises/21_async/async2.rs" },
170+
{ name = "async2_sol", path = "../solutions/21_async/async2.rs" },
171+
{ name = "macros1", path = "../exercises/22_macros/macros1.rs" },
172+
{ name = "macros1_sol", path = "../solutions/22_macros/macros1.rs" },
173+
{ name = "macros2", path = "../exercises/22_macros/macros2.rs" },
174+
{ name = "macros2_sol", path = "../solutions/22_macros/macros2.rs" },
175+
{ name = "macros3", path = "../exercises/22_macros/macros3.rs" },
176+
{ name = "macros3_sol", path = "../solutions/22_macros/macros3.rs" },
177+
{ name = "macros4", path = "../exercises/22_macros/macros4.rs" },
178+
{ name = "macros4_sol", path = "../solutions/22_macros/macros4.rs" },
179+
{ name = "clippy1", path = "../exercises/23_clippy/clippy1.rs" },
180+
{ name = "clippy1_sol", path = "../solutions/23_clippy/clippy1.rs" },
181+
{ name = "clippy2", path = "../exercises/23_clippy/clippy2.rs" },
182+
{ name = "clippy2_sol", path = "../solutions/23_clippy/clippy2.rs" },
183+
{ name = "clippy3", path = "../exercises/23_clippy/clippy3.rs" },
184+
{ name = "clippy3_sol", path = "../solutions/23_clippy/clippy3.rs" },
185+
{ name = "using_as", path = "../exercises/24_conversions/using_as.rs" },
186+
{ name = "using_as_sol", path = "../solutions/24_conversions/using_as.rs" },
187+
{ name = "from_into", path = "../exercises/24_conversions/from_into.rs" },
188+
{ name = "from_into_sol", path = "../solutions/24_conversions/from_into.rs" },
189+
{ name = "from_str", path = "../exercises/24_conversions/from_str.rs" },
190+
{ name = "from_str_sol", path = "../solutions/24_conversions/from_str.rs" },
191+
{ name = "try_from_into", path = "../exercises/24_conversions/try_from_into.rs" },
192+
{ name = "try_from_into_sol", path = "../solutions/24_conversions/try_from_into.rs" },
193+
{ name = "as_ref_mut", path = "../exercises/24_conversions/as_ref_mut.rs" },
194+
{ name = "as_ref_mut_sol", path = "../solutions/24_conversions/as_ref_mut.rs" },
191195
]
192196

193197
[package]
@@ -196,6 +200,9 @@ edition = "2024"
196200
# Don't publish the exercises on crates.io!
197201
publish = false
198202

203+
[dependencies]
204+
tokio = { version = "1.45.0", features = ["rt-multi-thread", "macros"] }
205+
199206
[profile.release]
200207
panic = "abort"
201208

exercises/21_async/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Async
2+
3+
Rust includes built-in support for asynchronous programming. In other languages, this might be known as Promises or
4+
Coroutines. async programming uses async functions, which are powerful, but may require some getting used to,
5+
especially if you haven't used something similar in another language.
6+
7+
The [relevant book chapter][1] is essential reading. The [tokio docs][2] are also very helpful!
8+
9+
[1]: https://doc.rust-lang.org/book/ch17-00-async-await.html
10+
[2]: https://tokio.rs/tokio/tutorial

exercises/21_async/async1.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Our loyal worker works hard to create a new number.
2+
#[derive(Default)]
3+
struct Worker;
4+
5+
struct NumberContainer {
6+
number: i32,
7+
}
8+
9+
impl Worker {
10+
async fn work(&self) -> NumberContainer {
11+
// Pretend this takes a while...
12+
let new_number = 32;
13+
NumberContainer { number: new_number }
14+
}
15+
}
16+
17+
impl NumberContainer {
18+
async fn extract_number(&self) -> i32 {
19+
// And this too...
20+
self.number
21+
}
22+
}
23+
24+
// TODO: Fix the function signature!
25+
fn run_worker() -> i32 {
26+
// TODO: Make our worker create a new number and return it.
27+
}
28+
29+
fn main() {
30+
// Feel free to experiment here. You may need to make some adjustments
31+
// to this function, though.
32+
}
33+
34+
mod tests {
35+
use super::*;
36+
37+
// Don't worry about this attribute for now.
38+
// If you want to know what this does, read the hint!
39+
#[tokio::test]
40+
async fn test_if_it_works() {
41+
let number = run_worker().await;
42+
assert_eq!(number, 32);
43+
}
44+
}

exercises/21_async/async2.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
use tokio::task::JoinSet;
2+
3+
// A MultiWorker can work with the power of 5 normal workers,
4+
// allowing us to create 5 new numbers at once!
5+
struct MultiWorker;
6+
7+
impl MultiWorker {
8+
async fn start_work(&self) -> JoinSet<i32> {
9+
let mut set = JoinSet::new();
10+
11+
for i in 30..35 {
12+
// TODO: `set.spawn` accepts an async function that will return the number
13+
// we want. Implement this function as a closure!
14+
set.spawn(???);
15+
}
16+
17+
set
18+
}
19+
}
20+
21+
async fn run_multi_worker() -> Vec<i32> {
22+
let tasks = MultiWorker.start_work().await;
23+
24+
// TODO: We have a bunch of tasks, how do we run them to completion
25+
// to get at the i32s they create?
26+
}
27+
28+
fn main() {
29+
// Feel free to experiment here. You may need to make some adjustments
30+
// to this function, though.
31+
}
32+
33+
mod tests {
34+
use super::*;
35+
36+
#[tokio::test]
37+
async fn test_if_it_works() {
38+
let mut numbers = run_multi_worker().await;
39+
numbers.sort(); // in case tasks run out-of-order
40+
assert_eq!(numbers, vec![30, 31, 32, 33, 34]);
41+
}
42+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)