Compare commits

..

3 Commits

Author SHA1 Message Date
47ed183cfe cargo fmt 2026-05-26 14:42:05 +04:00
76cb232b1e Complete exercise: threads_channels 2026-05-26 14:38:45 +04:00
621fb6bb59 Complete exercise: logging 2026-05-26 00:08:56 +04:00
11 changed files with 103 additions and 64 deletions

View File

@@ -41,7 +41,11 @@ fn main() {
// Hint: .to_uppercase() is a method on `str` which returns a String // Hint: .to_uppercase() is a method on `str` which returns a String
let words = vec!["autobot", "beach", "car", "decepticon", "energon", "frothy"]; let words = vec!["autobot", "beach", "car", "decepticon", "energon", "frothy"];
let transformed = words.into_iter().filter(|w| !w.contains("h")).map(|w| w.to_uppercase()).collect::<Vec<String>>(); let transformed = words
.into_iter()
.filter(|w| !w.contains("h"))
.map(|w| w.to_uppercase())
.collect::<Vec<String>>();
println!("Transformed: {:?}", transformed); println!("Transformed: {:?}", transformed);
// Challenge: // Challenge:

View File

@@ -24,7 +24,7 @@ pub enum DolphinError {
#[error("The dolphin is too young")] #[error("The dolphin is too young")]
TooYoung, TooYoung,
#[error("The dolphin's name is too long and annoying to say")] #[error("The dolphin's name is too long and annoying to say")]
LongName LongName,
} }
pub struct Dolphin { pub struct Dolphin {

View File

@@ -3,14 +3,12 @@
use aquarium::Dolphin; use aquarium::Dolphin;
// Silence some warnings so they don't distract from the exercise. // Silence some warnings so they don't distract from the exercise.
#[allow(clippy::vec_init_then_push)] #[allow(clippy::vec_init_then_push)]
// (You already did #1 in lib.rs, right?) // (You already did #1 in lib.rs, right?)
// //
// 2a. Uncomment and finish the play_time function below // 2a. Uncomment and finish the play_time function below
// - Bring anyhow::Result into scope with a `use` statement // - Bring anyhow::Result into scope with a `use` statement
// - Have the play_time function return a `Result<Vec<String>>`. The vector of Strings will // - Have the play_time function return a `Result<Vec<String>>`. The vector of Strings will
// represent successful outcomes of various dolphin tricks. // represent successful outcomes of various dolphin tricks.
use anyhow::Result; use anyhow::Result;
fn play_time(dolphin: &Dolphin) -> Result<Vec<String>> { fn play_time(dolphin: &Dolphin) -> Result<Vec<String>> {

View File

@@ -4,10 +4,5 @@ version = "0.1.0"
edition = "2021" edition = "2021"
[dependencies] [dependencies]
# I'm glad you came to add the `log` dependency! I got it all ready for you, just uncomment: log = "0.4" # I'm glad you came to add the `log` dependency! I got it all ready for you, just uncomment:
# env_logger = "0.9" # And here's the env_logger dependency that you'll need in main.rs
# log = "0.4"
# And here's the env_logger dependency that you'll need in main.rs
#
# env_logger = "0.9"

View File

@@ -6,6 +6,8 @@
// //
// Hint: You need to update Cargo.toml to add the `log` dependency, first. // Hint: You need to update Cargo.toml to add the `log` dependency, first.
use log::{debug, error, info, trace, warn};
#[derive(Debug)] #[derive(Debug)]
pub struct Frog { pub struct Frog {
energy: u8, energy: u8,
@@ -15,19 +17,23 @@ pub struct Frog {
impl Frog { impl Frog {
pub fn new() -> Self { pub fn new() -> Self {
// 2. Use debug!() to log "A new Frog has been created" // 2. Use debug!() to log "A new Frog has been created"
debug!(target: "Frog::new", "A new Frog has been created");
Default::default() Default::default()
} }
pub fn hop(&mut self) { pub fn hop(&mut self) {
self.energy -= 1; self.energy -= 1;
// 3. Use info!() to log that a Frog hopped, and how much energy is left // 3. Use info!() to log that a Frog hopped, and how much energy is left
info!(target: "Frog::hop", "A frog hopped! It has {} energy left", self.energy);
if self.energy == 0 { if self.energy == 0 {
// 4. Use warn!() to warn that the frog will go to sleep since he ran out of energy // 4. Use warn!() to warn that the frog will go to sleep since he ran out of energy
warn!(target: "Frog::hop", "The frog will go to sleep since he ran out of energy");
self.sleep(); self.sleep();
} }
} }
pub fn sleep(&mut self) { pub fn sleep(&mut self) {
if self.sleeping { if self.sleeping {
// 5. Use error!() to log a (non-fatal) error stating that the Frog is already asleep // 5. Use error!() to log a (non-fatal) error stating that the Frog is already asleep
error!(target: "Frog::sleep", "The frog is already asleep");
} else { } else {
self.sleeping = true; self.sleeping = true;
} }
@@ -37,9 +43,12 @@ impl Frog {
impl Default for Frog { impl Default for Frog {
fn default() -> Self { fn default() -> Self {
// 6. Use trace!() to log that a default value was generated, with the debug representation // 6. Use trace!() to log that a default value was generated, with the debug representation
Frog { let frog = Frog {
energy: 5, energy: 5,
sleeping: false, sleeping: false,
} };
trace!(target: "Frog::Default", "A default Frog value was generated: {:?}", frog);
frog
} }
} }

View File

@@ -8,6 +8,7 @@ use frogger::Frog;
fn main() { fn main() {
// 8. Initialize env_logger using the init() function at the top level of the library // 8. Initialize env_logger using the init() function at the top level of the library
env_logger::init();
// 9. Run this program with `cargo run` and take a look at the default output. // 9. Run this program with `cargo run` and take a look at the default output.
// - Now run it again with an explicit log level, like `RUST_LOG=info cargo run` // - Now run it again with an explicit log level, like `RUST_LOG=info cargo run`

View File

@@ -2,7 +2,9 @@ use criterion::{black_box, criterion_group, criterion_main, Criterion};
use testing::sploosh; use testing::sploosh;
pub fn sploosh_benchmark(c: &mut Criterion) { pub fn sploosh_benchmark(c: &mut Criterion) {
c.bench_function("sploosh", |b| b.iter(|| sploosh(black_box(8), black_box(9), black_box(10)))); c.bench_function("sploosh", |b| {
b.iter(|| sploosh(black_box(8), black_box(9), black_box(10)))
});
} }
criterion_group!(benches, sploosh_benchmark); criterion_group!(benches, sploosh_benchmark);

View File

@@ -1,4 +1,4 @@
use testing::{sploosh, splish}; use testing::{splish, sploosh};
#[test] #[test]
pub fn test_sploosh_splish() { pub fn test_sploosh_splish() {

View File

@@ -22,8 +22,8 @@ fn main() {
// join handle in a variable called `handle`. Once you've done this you should be able to run // join handle in a variable called `handle`. Once you've done this you should be able to run
// the code and see the output from the child thread's expensive sum in the middle of the main // the code and see the output from the child thread's expensive sum in the middle of the main
// thread's processing of letters. // thread's processing of letters.
//
//let handle = ... let handle = thread::spawn(|| expensive_sum(my_vector));
// While the child thread is running, the main thread will also do some work // While the child thread is running, the main thread will also do some work
for letter in vec!["a", "b", "c", "d", "e", "f"] { for letter in vec!["a", "b", "c", "d", "e", "f"] {
@@ -37,17 +37,16 @@ fn main() {
// to a variable named `result` // to a variable named `result`
// - Get the i32 out of `result` and store it in a `sum` variable. // - Get the i32 out of `result` and store it in a `sum` variable.
// let result = let result = handle.join();
// let sum = let sum = result.unwrap();
// println!("The child thread's expensive sum is {}", sum); println!("The child thread's expensive sum is {}", sum);
// 3. Time for some fun with channels! // 3. Time for some fun with channels!
// - Uncomment the block comment below (Find and remove the `/*` and `*/`). // - Uncomment the block comment below (Find and remove the `/*` and `*/`).
// - Create variables `tx` and `rx` and assign them to the sending and receiving ends of an // - Create variables `tx` and `rx` and assign them to the sending and receiving ends of an
// unbounded channel. Hint: An unbounded channel can be created with `channel::unbounded()` // unbounded channel. Hint: An unbounded channel can be created with `channel::unbounded()`
/* let (tx, rx) = channel::unbounded();
// let ...
// Cloning a channel makes another variable connected to that end of the channel so that you can // Cloning a channel makes another variable connected to that end of the channel so that you can
// send it to another thread. We want another variable that can be used for sending... // send it to another thread. We want another variable that can be used for sending...
@@ -62,7 +61,7 @@ fn main() {
// Thread A // Thread A
let handle_a = thread::spawn(move || { let handle_a = thread::spawn(move || {
sleep_ms(0); sleep_ms(500);
tx2.send("Thread A: 1").unwrap(); tx2.send("Thread A: 1").unwrap();
sleep_ms(200); sleep_ms(200);
tx2.send("Thread A: 2").unwrap(); tx2.send("Thread A: 2").unwrap();
@@ -88,12 +87,40 @@ fn main() {
// 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene! // 5. Oops, we forgot to join "Thread A" and "Thread B". That's bad hygiene!
// - Use the thread handles to join both threads without getting any compiler warnings. // - Use the thread handles to join both threads without getting any compiler warnings.
*/ let _ = handle_a.join();
let _ = handle_b.join();
// Challenge: Make two child threads and give them each a receiving end to a channel. From the // Challenge: Make two child threads and give them each a receiving end to a channel. From the
// main thread loop through several values and print each out and then send it to the channel. // main thread loop through several values and print each out and then send it to the channel.
// On the child threads print out the values you receive. Close the sending side in the main // On the child threads print out the values you receive. Close the sending side in the main
// thread by calling `drop(tx)` (assuming you named your sender channel variable `tx`). Join // thread by calling `drop(tx)` (assuming you named your sender channel variable `tx`). Join
// the child threads. // the child threads.
let (tx, rx) = channel::unbounded();
let rx2 = rx.clone();
let thread_a_handle = thread::spawn(move || {
for n in rx {
println!("Thread A received: {}", n);
sleep_ms(10);
}
});
let thread_b_handle = thread::spawn(move || {
for n in rx2 {
println!("Thread B received: {}", n);
sleep_ms(10);
}
});
for number in vec![1, 2, 3, 4, 5] {
println!("NUMBER: {}", number);
let _ = tx.send(number);
}
drop(tx);
let _ = thread_a_handle.join();
let _ = thread_b_handle.join();
println!("Main thread: Exiting.") println!("Main thread: Exiting.")
} }

View File

@@ -17,7 +17,7 @@ impl Default for Party {
Self { Self {
at_restaurant: true, at_restaurant: true,
num_people: 8, num_people: 8,
cake: Cake::Chocolate cake: Cake::Chocolate,
} }
} }
} }
@@ -110,7 +110,10 @@ fn main() {
// consuming it. Change the code above to pass in a &party. Then uncomment and run the code // consuming it. Change the code above to pass in a &party. Then uncomment and run the code
// below. After all, you want to smell your cake and eat it, too! // below. After all, you want to smell your cake and eat it, too!
println!("Yum! I'm eating this cake: {:?}. Oops, I dropped it on the floor.", party.cake); println!(
"Yum! I'm eating this cake: {:?}. Oops, I dropped it on the floor.",
party.cake
);
} }
pub fn admire_cake(cake: Cake) { pub fn admire_cake(cake: Cake) {