From ce86d252e529385704fe9111e305ac0ec48c2de4 Mon Sep 17 00:00:00 2001 From: Denton24646 Date: Sat, 16 Jul 2022 15:31:37 -0400 Subject: [PATCH 01/28] feat: add rc1.rs exercise --- exercises/standard_library_types/rc1.rs | 98 +++++++++++++++++++++++++ info.toml | 14 ++++ 2 files changed, 112 insertions(+) create mode 100644 exercises/standard_library_types/rc1.rs diff --git a/exercises/standard_library_types/rc1.rs b/exercises/standard_library_types/rc1.rs new file mode 100644 index 00000000..9b907fde --- /dev/null +++ b/exercises/standard_library_types/rc1.rs @@ -0,0 +1,98 @@ +// rc1.rs +// In this exercise, we want to express the concept of multiple owners via the Rc type. +// This is a model of our solar system - there is a Sun type and multiple Planets. +// The Planets take ownership of the sun, indicating that they revolve around the sun. + +// Make this code compile by using the proper Rc primitives to express that the sun has multiple owners. + +// I AM NOT DONE +use std::rc::Rc; + +#[derive(Debug)] +struct Sun {} + +#[derive(Debug)] +enum Planet { + Mercury(Rc), + Venus(Rc), + Earth(Rc), + Mars(Rc), + Jupiter(Rc), + Saturn(Rc), + Uranus(Rc), + Neptune(Rc), +} + +impl Planet { + fn details(&self) { + println!("Hi from {:?}!", self) + } +} + +fn main() { + let sun = Rc::new(Sun {}); + println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference + + let mercury = Planet::Mercury(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 2 references + mercury.details(); + + let venus = Planet::Venus(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 3 references + venus.details(); + + let earth = Planet::Earth(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 4 references + earth.details(); + + let mars = Planet::Mars(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 5 references + mars.details(); + + let jupiter = Planet::Jupiter(Rc::clone(&sun)); + println!("reference count = {}", Rc::strong_count(&sun)); // 6 references + jupiter.details(); + + // TODO + let saturn = Planet::Saturn(Rc::new(Sun {})); + println!("reference count = {}", Rc::strong_count(&sun)); // 7 references + saturn.details(); + + // TODO + let uranus = Planet::Uranus(Rc::new(Sun {})); + println!("reference count = {}", Rc::strong_count(&sun)); // 8 references + uranus.details(); + + // TODO + let neptune = Planet::Neptune(Rc::new(Sun {})); + println!("reference count = {}", Rc::strong_count(&sun)); // 9 references + neptune.details(); + + assert_eq!(Rc::strong_count(&sun), 9); + + drop(neptune); + println!("reference count = {}", Rc::strong_count(&sun)); // 8 references + + drop(uranus); + println!("reference count = {}", Rc::strong_count(&sun)); // 7 references + + drop(saturn); + println!("reference count = {}", Rc::strong_count(&sun)); // 6 references + + drop(jupiter); + println!("reference count = {}", Rc::strong_count(&sun)); // 5 references + + drop(mars); + println!("reference count = {}", Rc::strong_count(&sun)); // 4 references + + // TODO + println!("reference count = {}", Rc::strong_count(&sun)); // 3 references + + // TODO + println!("reference count = {}", Rc::strong_count(&sun)); // 2 references + + // TODO + println!("reference count = {}", Rc::strong_count(&sun)); // 1 reference + + assert_eq!(Rc::strong_count(&sun), 1); +} diff --git a/info.toml b/info.toml index 5b7b9b43..a72c0147 100644 --- a/info.toml +++ b/info.toml @@ -929,6 +929,20 @@ is too much of a struggle, consider reading through all of Chapter 16 in the boo https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html """ +[[exercises]] +name = "rc1" +path = "exercises/standard_library_types/rc1.rs" +mode = "compile" +hint = """ +This is a straightforward exercise to use the Rc type. Each Planet has +ownership of the Sun, and uses Rc::clone() to increment the reference count of the Sun. +After using drop() to move the Planets out of scope individually, the reference count goes down. +In the end the sun only has one reference again, to itself. See more at: +https://doc.rust-lang.org/book/ch15-04-rc.html + +* Unforunately Pluto is no longer considered a planet :( +""" + # THREADS [[exercises]] From 72e21a2a6c2654cb1d2e292291e2e40914957776 Mon Sep 17 00:00:00 2001 From: Denton24646 Date: Sat, 23 Jul 2022 17:57:03 -0400 Subject: [PATCH 02/28] feat: add cow1.rs exercise --- exercises/standard_library_types/cow1.rs | 48 ++++++++++++++++++++++++ info.toml | 11 ++++++ 2 files changed, 59 insertions(+) create mode 100644 exercises/standard_library_types/cow1.rs diff --git a/exercises/standard_library_types/cow1.rs b/exercises/standard_library_types/cow1.rs new file mode 100644 index 00000000..5fba2519 --- /dev/null +++ b/exercises/standard_library_types/cow1.rs @@ -0,0 +1,48 @@ +// cow1.rs + +// This exercise explores the Cow, or Clone-On-Write type. +// Cow is a clone-on-write smart pointer. +// It can enclose and provide immutable access to borrowed data, and clone the data lazily when mutation or ownership is required. +// The type is designed to work with general borrowed data via the Borrow trait. + +// I AM NOT DONE + +use std::borrow::Cow; + +fn abs_all<'a, 'b>(input: &'a mut Cow<'b, [i32]>) -> &'a mut Cow<'b, [i32]> { + for i in 0..input.len() { + let v = input[i]; + if v < 0 { + // Clones into a vector if not already owned. + input.to_mut()[i] = -v; + } + } + input +} + +fn main() { + // No clone occurs because `input` doesn't need to be mutated. + let slice = [0, 1, 2]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + Cow::Borrowed(_) => println!("I borrowed the slice!"), + _ => panic!("expected borrowed value"), + } + + // Clone occurs because `input` needs to be mutated. + let slice = [-1, 0, 1]; + let mut input = Cow::from(&slice[..]); + match abs_all(&mut input) { + Cow::Owned(_) => println!("I modified the slice and now own it!"), + _ => panic!("expected owned value"), + } + + // No clone occurs because `input` is already owned. + let slice = vec![-1, 0, 1]; + let mut input = Cow::from(slice); + match abs_all(&mut input) { + // TODO + Cow::Borrowed(_) => println!("I own this slice!"), + _ => panic!("expected borrowed value"), + } +} diff --git a/info.toml b/info.toml index 14031118..230fc724 100644 --- a/info.toml +++ b/info.toml @@ -932,6 +932,17 @@ is too much of a struggle, consider reading through all of Chapter 16 in the boo https://doc.rust-lang.org/stable/book/ch16-00-concurrency.html """ +[[exercises]] +name = "cow1" +path = "exercises/standard_library_types/cow1.rs" +mode = "compile" +hint = """ +Since the vector is already owned, the `Cow` type doesn't need to clone it. + +Checkout https://doc.rust-lang.org/std/borrow/enum.Cow.html for documentation +on the `Cow` type. +""" + # THREADS [[exercises]] From e8122daa8709274226c40fe8008fdfc86ad4493a Mon Sep 17 00:00:00 2001 From: Nico Vromans <48183857+nico-vromans@users.noreply.github.com> Date: Mon, 15 Aug 2022 10:05:50 +0200 Subject: [PATCH 03/28] Update options1.rs Added extra test for before 10PM and updated the test for at 10PM (when it's 10PM there should already not be any ice cream left, as per the description). Also fixed the `raw_value` test, as it is later than 10PM, so there should be no more ice cream left. --- exercises/options/options1.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs index 99c95911..022d3d66 100644 --- a/exercises/options/options1.rs +++ b/exercises/options/options1.rs @@ -19,7 +19,8 @@ mod tests { #[test] fn check_icecream() { - assert_eq!(maybe_icecream(10), Some(5)); + assert_eq!(maybe_icecream(9), Some(5)); + assert_eq!(maybe_icecream(10), Some(0)); assert_eq!(maybe_icecream(23), Some(0)); assert_eq!(maybe_icecream(22), Some(0)); assert_eq!(maybe_icecream(25), None); @@ -29,6 +30,6 @@ mod tests { fn raw_value() { // TODO: Fix this test. How do you get at the value contained in the Option? let icecreams = maybe_icecream(12); - assert_eq!(icecreams, 5); + assert_eq!(icecreams, 0); } } From 4400ce2892188044d510cbabdfead1f0c704bdf8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 07:32:31 +0000 Subject: [PATCH 04/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 9648f33c..0c07a933 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -212,6 +212,7 @@ authors.
Brian Fakhoury

πŸ–‹
Markus Boehme

πŸ’» +
Nico Vromans

πŸ–‹ From 2f2f141564f3bfc34c9a0a0d5449ea376f7835f8 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Tue, 16 Aug 2022 07:32:32 +0000 Subject: [PATCH 05/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 0df89f7e..be5dc21a 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1488,6 +1488,15 @@ "contributions": [ "code" ] + }, + { + "login": "nico-vromans", + "name": "Nico Vromans", + "avatar_url": "https://avatars.githubusercontent.com/u/48183857?v=4", + "profile": "https://github.com/nico-vromans", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From bb6b9e1704a5bbe16a57adc95616409c8c3ea0e2 Mon Sep 17 00:00:00 2001 From: mokou Date: Tue, 16 Aug 2022 09:41:41 +0200 Subject: [PATCH 06/28] doc: add zulip link --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index afa55c86..b2ac6b92 100644 --- a/README.md +++ b/README.md @@ -154,6 +154,10 @@ Now you should be done! See [CONTRIBUTING.md](./CONTRIBUTING.md). +Development-focused discussion about Rustlings happens in the [**rustlings** stream](https://rust-lang.zulipchat.com/#narrow/stream/334454-rustlings) +on the [Rust Project Zulip](https://rust-lang.zulipchat.com). Feel free to start a new thread there +if you have ideas or suggestions! + ## Contributors ✨ Thanks goes to the wonderful people listed in [AUTHORS.md](./AUTHORS.md) πŸŽ‰ From 0a9d34a25a6a262b3f947625a3fa87e8fa10ed7e Mon Sep 17 00:00:00 2001 From: mokou Date: Tue, 16 Aug 2022 09:53:40 +0200 Subject: [PATCH 07/28] doc: update changelog --- CHANGELOG.md | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8aae3138..8c782c86 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,38 @@ + +## 5.1.0 (2022-08-16) + +#### Features + +- Added a new `rc1` exercise. +- Added a new `cow1` exercise. + +#### Bug Fixes + +- **variables5**: Corrected reference to previous exercise +- **functions4**: Fixed line number reference +- **strings3**: Clarified comment wording +- **traits4, traits5**: Fixed line number reference +- **traits5**: + - Fixed typo in "parameter" + - Made exercise prefer a traits-based solution +- **lifetimes2**: Improved hint +- **threads3**: Fixed typo in hint +- **box1**: Replaced `unimplemented!` with `todo!` +- **errors5**: Provided an explanation for usage of `Box` +- **quiz2**: Fixed a typo +- **macros**: Updated the macros book link +- **options1**: + - Removed unused code + - Added more granular tests +- Fixed some comment syntax shenanigans in info.toml + +#### Housekeeping + +- Fixed a typo in .editorconfig +- Fixed a typo in integration_tests.rs +- Clarified manual installation instructions using `cargo install --path .` +- Added a link to our Zulip in the readme file + ## 5.0.0 (2022-07-16) From 714a8075cc34e3823513cd3ea26bd4a92c1c1129 Mon Sep 17 00:00:00 2001 From: mokou Date: Tue, 16 Aug 2022 09:54:25 +0200 Subject: [PATCH 08/28] chore: bump version --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- src/main.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 862a8a2e..d28d2c82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "5.0.0" +version = "5.1.0" dependencies = [ "argh", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 910b5389..ae01278b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustlings" -version = "5.0.0" +version = "5.1.0" authors = ["Liv ", "Carol (Nichols || Goulding) "] edition = "2021" diff --git a/README.md b/README.md index b2ac6b92..f7ed07ca 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ If you get a permission denied message, you might have to exclude the directory Basically: Clone the repository at the latest tag, run `cargo install --path .`. ```bash -# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.0.0) -git clone -b 5.0.0 --depth 1 https://github.com/rust-lang/rustlings +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.1.0) +git clone -b 5.1.0 --depth 1 https://github.com/rust-lang/rustlings cd rustlings cargo install --force --path . ``` diff --git a/src/main.rs b/src/main.rs index 0ddb7331..3719f66a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ mod run; mod verify; // In sync with crate version -const VERSION: &str = "5.0.0"; +const VERSION: &str = "5.1.0"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code From 4455c22b9aa5e4a6735e3ae67a4c9e75af24128a Mon Sep 17 00:00:00 2001 From: vostok92 Date: Wed, 17 Aug 2022 13:51:17 +0900 Subject: [PATCH 09/28] Update options1.rs Fix assertions --- exercises/options/options1.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs index 022d3d66..d1735c2f 100644 --- a/exercises/options/options1.rs +++ b/exercises/options/options1.rs @@ -20,7 +20,7 @@ mod tests { #[test] fn check_icecream() { assert_eq!(maybe_icecream(9), Some(5)); - assert_eq!(maybe_icecream(10), Some(0)); + assert_eq!(maybe_icecream(10), Some(5)); assert_eq!(maybe_icecream(23), Some(0)); assert_eq!(maybe_icecream(22), Some(0)); assert_eq!(maybe_icecream(25), None); @@ -30,6 +30,6 @@ mod tests { fn raw_value() { // TODO: Fix this test. How do you get at the value contained in the Option? let icecreams = maybe_icecream(12); - assert_eq!(icecreams, 0); + assert_eq!(icecreams, 5); } } From 3c1fe226f0a4e651bdb498330ca3ded6ffb477c4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 08:41:49 +0000 Subject: [PATCH 10/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 0c07a933..b7bf94b0 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -213,6 +213,7 @@ authors.
Brian Fakhoury

πŸ–‹
Markus Boehme

πŸ’»
Nico Vromans

πŸ–‹ +
vostok92

πŸ–‹ From 34392662a635f56fc59901f51f92b906f44e822d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 17 Aug 2022 08:41:50 +0000 Subject: [PATCH 11/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index be5dc21a..c5d783f1 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1497,6 +1497,15 @@ "contributions": [ "content" ] + }, + { + "login": "vostok92", + "name": "vostok92", + "avatar_url": "https://avatars.githubusercontent.com/u/540339?v=4", + "profile": "https://github.com/vostok92", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From d0c7b06eff3e8959b261145e10f1aaa57ba1e4c3 Mon Sep 17 00:00:00 2001 From: mokou Date: Wed, 17 Aug 2022 10:43:50 +0200 Subject: [PATCH 12/28] chore: release 5.1.1 --- CHANGELOG.md | 7 +++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 4 ++-- src/main.rs | 2 +- 5 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c782c86..cec41c59 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ + +## 5.1.1 (2022-08-17) + +#### Bug Fixes + +- Fixed an incorrect assertion in options1 + ## 5.1.0 (2022-08-16) diff --git a/Cargo.lock b/Cargo.lock index d28d2c82..2370e8dc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "5.1.0" +version = "5.1.1" dependencies = [ "argh", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index ae01278b..d5fd93c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustlings" -version = "5.1.0" +version = "5.1.1" authors = ["Liv ", "Carol (Nichols || Goulding) "] edition = "2021" diff --git a/README.md b/README.md index f7ed07ca..2392ba9d 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,8 @@ If you get a permission denied message, you might have to exclude the directory Basically: Clone the repository at the latest tag, run `cargo install --path .`. ```bash -# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.1.0) -git clone -b 5.1.0 --depth 1 https://github.com/rust-lang/rustlings +# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.1.1) +git clone -b 5.1.1 --depth 1 https://github.com/rust-lang/rustlings cd rustlings cargo install --force --path . ``` diff --git a/src/main.rs b/src/main.rs index 3719f66a..531533ea 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ mod run; mod verify; // In sync with crate version -const VERSION: &str = "5.1.0"; +const VERSION: &str = "5.1.1"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code From 52a29aa84be2a89894f2ad1f5ebdcf153c49f399 Mon Sep 17 00:00:00 2001 From: magnusrodseth <59113973+magnusrodseth@users.noreply.github.com> Date: Wed, 17 Aug 2022 12:50:34 +0200 Subject: [PATCH 13/28] test: Convert main function to working tests --- exercises/options/options2.rs | 41 ++++++++++++++++++++++------------- info.toml | 2 +- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/exercises/options/options2.rs b/exercises/options/options2.rs index 75b66a37..eca03f0d 100644 --- a/exercises/options/options2.rs +++ b/exercises/options/options2.rs @@ -3,23 +3,34 @@ // I AM NOT DONE -fn main() { - let optional_word = Some(String::from("rustlings")); - // TODO: Make this an if let statement whose value is "Some" type - word = optional_word { - println!("The word is: {}", word); - } else { - println!("The optional word doesn't contain anything"); +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn simple_option() { + let target = "rustlings"; + let optional_target = Some(target); + + // TODO: Make this an if let statement whose value is "Some" type + if let Some(word) = optional_target { + assert_eq!(word, target); + } } - let mut optional_integers_vec: Vec> = Vec::new(); - for x in 1..10 { - optional_integers_vec.push(Some(x)); - } + #[test] + fn layered_option() { + let mut range = 10; + let mut optional_integers: Vec> = Vec::new(); + for i in 0..(range + 1) { + optional_integers.push(Some(i)); + } - // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option - // You can stack `Option`'s into while let and if let - integer = optional_integers_vec.pop() { - println!("current value: {}", integer); + // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option + // You can stack `Option`'s into while let and if let + while let Some(Some(integer)) = optional_integers.pop() { + assert_eq!(integer, range); + range -= 1; + } } } diff --git a/info.toml b/info.toml index 9aa11e8a..8bce7216 100644 --- a/info.toml +++ b/info.toml @@ -545,7 +545,7 @@ is the easiest, but how do you do it safely so that it doesn't panic in your fac [[exercises]] name = "options2" path = "exercises/options/options2.rs" -mode = "compile" +mode = "test" hint = """ check out: https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html From 6f44cb1dd237f4d53aa3ecd4676e50cf850c99fe Mon Sep 17 00:00:00 2001 From: magnusrodseth <59113973+magnusrodseth@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:31:53 +0200 Subject: [PATCH 14/28] feat: Add reset command, given a filename --- src/main.rs | 78 ++++++++++++++++++++++++++++++++++++++++------------- src/run.rs | 15 +++++++++++ 2 files changed, 74 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 531533ea..3610f827 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,10 @@ -use crate::exercise::{Exercise, ExerciseList}; use crate::project::RustAnalyzerProject; use crate::run::run; use crate::verify::verify; +use crate::{ + exercise::{Exercise, ExerciseList}, + run::reset, +}; use argh::FromArgs; use console::Emoji; use notify::DebouncedEvent; @@ -47,6 +50,7 @@ enum Subcommands { Verify(VerifyArgs), Watch(WatchArgs), Run(RunArgs), + Reset(ResetArgs), Hint(HintArgs), List(ListArgs), Lsp(LspArgs), @@ -71,6 +75,15 @@ struct RunArgs { name: String, } +#[derive(FromArgs, PartialEq, Debug)] +#[argh(subcommand, name = "reset")] +/// Resets a single exercise +struct ResetArgs { + #[argh(positional)] + /// the name of the exercise + name: String, +} + #[derive(FromArgs, PartialEq, Debug)] #[argh(subcommand, name = "hint")] /// Returns a hint for the given exercise @@ -85,7 +98,6 @@ struct HintArgs { /// Enable rust-analyzer for exercises struct LspArgs {} - #[derive(FromArgs, PartialEq, Debug)] #[argh(subcommand, name = "list")] /// Lists the exercises available in Rustlings @@ -164,7 +176,9 @@ fn main() { "Pending" }; let solve_cond = { - (e.looks_done() && subargs.solved) || (!e.looks_done() && subargs.unsolved) || (!subargs.solved && !subargs.unsolved) + (e.looks_done() && subargs.solved) + || (!e.looks_done() && subargs.unsolved) + || (!subargs.solved && !subargs.unsolved) }; if solve_cond && (filter_cond || subargs.filter.is_none()) { let line = if subargs.paths { @@ -205,6 +219,12 @@ fn main() { run(exercise, verbose).unwrap_or_else(|_| std::process::exit(1)); } + Subcommands::Reset(subargs) => { + let exercise = find_exercise(&subargs.name, &exercises); + + reset(exercise).unwrap_or_else(|_| std::process::exit(1)); + } + Subcommands::Hint(subargs) => { let exercise = find_exercise(&subargs.name, &exercises); @@ -212,7 +232,8 @@ fn main() { } Subcommands::Verify(_subargs) => { - verify(&exercises, (0, exercises.len()), verbose).unwrap_or_else(|_| std::process::exit(1)); + verify(&exercises, (0, exercises.len()), verbose) + .unwrap_or_else(|_| std::process::exit(1)); } Subcommands::Lsp(_subargs) => { @@ -236,12 +257,18 @@ fn main() { Subcommands::Watch(_subargs) => match watch(&exercises, verbose) { Err(e) => { - println!("Error: Could not watch your progress. Error message was {:?}.", e); + println!( + "Error: Could not watch your progress. Error message was {:?}.", + e + ); println!("Most likely you've run out of disk space or your 'inotify limit' has been reached."); std::process::exit(1); } Ok(WatchStatus::Finished) => { - println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("πŸŽ‰", "β˜…")); + println!( + "{emoji} All exercises completed! {emoji}", + emoji = Emoji("πŸŽ‰", "β˜…") + ); println!("\n{}\n", FENISH_LINE); } Ok(WatchStatus::Unfinished) => { @@ -252,8 +279,10 @@ fn main() { } } - -fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_quit: Arc) { +fn spawn_watch_shell( + failed_exercise_hint: &Arc>>, + should_quit: Arc, +) { let failed_exercise_hint = Arc::clone(failed_exercise_hint); println!("Welcome to watch mode! You can type 'help' to get an overview of the commands you can use here."); thread::spawn(move || loop { @@ -290,16 +319,22 @@ fn spawn_watch_shell(failed_exercise_hint: &Arc>>, should_q fn find_exercise<'a>(name: &str, exercises: &'a [Exercise]) -> &'a Exercise { if name.eq("next") { - exercises.iter().find(|e| !e.looks_done()).unwrap_or_else(|| { - println!("πŸŽ‰ Congratulations! You have done all the exercises!"); - println!("πŸ”š There are no more exercises to do next!"); - std::process::exit(1) - }) + exercises + .iter() + .find(|e| !e.looks_done()) + .unwrap_or_else(|| { + println!("πŸŽ‰ Congratulations! You have done all the exercises!"); + println!("πŸ”š There are no more exercises to do next!"); + std::process::exit(1) + }) } else { - exercises.iter().find(|e| e.name == name).unwrap_or_else(|| { - println!("No exercise found for '{}'!", name); - std::process::exit(1) - }) + exercises + .iter() + .find(|e| e.name == name) + .unwrap_or_else(|| { + println!("No exercise found for '{}'!", name); + std::process::exit(1) + }) } } @@ -337,8 +372,13 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result { let filepath = b.as_path().canonicalize().unwrap(); let pending_exercises = exercises .iter() - .find(|e| filepath.ends_with(&e.path)).into_iter() - .chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path))); + .find(|e| filepath.ends_with(&e.path)) + .into_iter() + .chain( + exercises + .iter() + .filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)), + ); let num_done = exercises.iter().filter(|e| e.looks_done()).count(); clear_screen(); match verify(pending_exercises, (num_done, exercises.len()), verbose) { diff --git a/src/run.rs b/src/run.rs index eb558850..826f00a6 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,3 +1,5 @@ +use std::process::Command; + use crate::exercise::{Exercise, Mode}; use crate::verify::test; use indicatif::ProgressBar; @@ -15,6 +17,19 @@ pub fn run(exercise: &Exercise, verbose: bool) -> Result<(), ()> { Ok(()) } +// Resets the exercise by stashing the changes. +pub fn reset(exercise: &Exercise) -> Result<(), ()> { + let command = Command::new("git") + .args(["stash", "--"]) + .arg(&exercise.path) + .spawn(); + + match command { + Ok(_) => Ok(()), + Err(_) => Err(()), + } +} + // Invoke the rust compiler on the path of the given exercise // and run the ensuing binary. // This is strictly for non-test binaries, so output is displayed From 0aff5340b5e225b394ac0fdf496824eaa201e19c Mon Sep 17 00:00:00 2001 From: magnusrodseth <59113973+magnusrodseth@users.noreply.github.com> Date: Wed, 17 Aug 2022 16:43:48 +0200 Subject: [PATCH 15/28] test: Add integration tests --- tests/integration_tests.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 0be191f0..1a729232 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -110,6 +110,27 @@ fn run_single_test_no_exercise() { .code(1); } +#[test] +fn reset_single_exercise() { + Command::cargo_bin("rustlings") + .unwrap() + .args(&["reset", "intro1"]) + .assert() + .code(0); +} + +#[test] +fn reset_no_exercise() { + Command::cargo_bin("rustlings") + .unwrap() + .arg("reset") + .assert() + .code(1) + .stderr(predicates::str::contains( + "positional arguments not provided", + )); +} + #[test] fn get_hint_for_single_test() { Command::cargo_bin("rustlings") @@ -126,7 +147,7 @@ fn all_exercises_require_confirmation() { for exercise in glob("exercises/**/*.rs").unwrap() { let path = exercise.unwrap(); if path.file_name().unwrap() == "mod.rs" { - continue + continue; } let source = { let mut file = File::open(&path).unwrap(); From 99ea2cbba7dabb011fc76e4480e27f0bbc6149ad Mon Sep 17 00:00:00 2001 From: magnusrodseth <59113973+magnusrodseth@users.noreply.github.com> Date: Wed, 17 Aug 2022 12:54:23 +0200 Subject: [PATCH 16/28] chore: make options2 not compile deliberately --- exercises/options/options2.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/exercises/options/options2.rs b/exercises/options/options2.rs index eca03f0d..b1120471 100644 --- a/exercises/options/options2.rs +++ b/exercises/options/options2.rs @@ -13,7 +13,7 @@ mod tests { let optional_target = Some(target); // TODO: Make this an if let statement whose value is "Some" type - if let Some(word) = optional_target { + word = optional_target { assert_eq!(word, target); } } @@ -28,7 +28,7 @@ mod tests { // TODO: make this a while let statement - remember that vector.pop also adds another layer of Option // You can stack `Option`'s into while let and if let - while let Some(Some(integer)) = optional_integers.pop() { + integer = optional_integers.pop() { assert_eq!(integer, range); range -= 1; } From e889c5bb60a123c62b9cb4acbab84c817a2fecfa Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 09:53:54 +0000 Subject: [PATCH 17/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index b7bf94b0..09a77046 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -214,6 +214,7 @@ authors.
Markus Boehme

πŸ’»
Nico Vromans

πŸ–‹
vostok92

πŸ–‹ +
Magnus RΓΈdseth

πŸ–‹ From 2088dfbaf6944b637c436a92a5f2a1e290390aec Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 09:53:55 +0000 Subject: [PATCH 18/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index c5d783f1..0792bd27 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1506,6 +1506,15 @@ "contributions": [ "content" ] + }, + { + "login": "magnusrodseth", + "name": "Magnus RΓΈdseth", + "avatar_url": "https://avatars.githubusercontent.com/u/59113973?v=4", + "profile": "http://magnusrodseth.vercel.app", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 93f60d3f8d31c209a1e49d1dd149dbe964b1d2a2 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 09:54:29 +0000 Subject: [PATCH 19/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 09a77046..868f0c8e 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -215,6 +215,7 @@ authors.
Nico Vromans

πŸ–‹
vostok92

πŸ–‹
Magnus RΓΈdseth

πŸ–‹ +
rubiesonthesky

πŸ–‹ From 50272a58e2a86537a558c0e93d02e6c9ef44a3f2 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 18 Aug 2022 09:54:30 +0000 Subject: [PATCH 20/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 0792bd27..6b811617 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1515,6 +1515,15 @@ "contributions": [ "content" ] + }, + { + "login": "rubiesonthesky", + "name": "rubiesonthesky", + "avatar_url": "https://avatars.githubusercontent.com/u/2591240?v=4", + "profile": "https://github.com/rubiesonthesky", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From d59dde320b90ac5f5679a8f044746e37faa7289f Mon Sep 17 00:00:00 2001 From: magnusrodseth <59113973+magnusrodseth@users.noreply.github.com> Date: Thu, 18 Aug 2022 12:47:26 +0200 Subject: [PATCH 21/28] chore: Add suggested changes --- src/main.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index 3610f827..9bf75e38 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,7 @@ +use crate::exercise::{Exercise, ExerciseList}; use crate::project::RustAnalyzerProject; -use crate::run::run; +use crate::run::{reset, run}; use crate::verify::verify; -use crate::{ - exercise::{Exercise, ExerciseList}, - run::reset, -}; use argh::FromArgs; use console::Emoji; use notify::DebouncedEvent; @@ -77,7 +74,7 @@ struct RunArgs { #[derive(FromArgs, PartialEq, Debug)] #[argh(subcommand, name = "reset")] -/// Resets a single exercise +/// Resets a single exercise using "git stash -- " struct ResetArgs { #[argh(positional)] /// the name of the exercise From 86506fa5fd5441c98e4ac74169d10578b77cd770 Mon Sep 17 00:00:00 2001 From: Gabriel Bianconi <1275491+GabrielBianconi@users.noreply.github.com> Date: Mon, 22 Aug 2022 23:47:23 -0400 Subject: [PATCH 22/28] Fix typo in `threads3` hint --- info.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info.toml b/info.toml index 8bce7216..060643d7 100644 --- a/info.toml +++ b/info.toml @@ -1012,7 +1012,7 @@ hint = """ An alternate way to handle concurrency between threads is to use a mpsc (multiple producer, single consumer) channel to communicate. With both a sending end and a receiving end, it's possible to -send values in one thread and receieve them in another. +send values in one thread and receive them in another. Multiple producers are possible by using clone() to create a duplicate of the original sending end. See https://doc.rust-lang.org/book/ch16-02-message-passing.html for more info. From 6c2630afcff34b634cdf0843d6b01cade2efc622 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 09:15:51 +0000 Subject: [PATCH 23/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 868f0c8e..02cbf0ed 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -216,6 +216,7 @@ authors.
vostok92

πŸ–‹
Magnus RΓΈdseth

πŸ–‹
rubiesonthesky

πŸ–‹ +
Gabriel Bianconi

πŸ–‹ From b92e7b968ffb1343f6ee11c392c29099afbdae66 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Wed, 24 Aug 2022 09:15:52 +0000 Subject: [PATCH 24/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index 6b811617..e061d153 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1524,6 +1524,15 @@ "contributions": [ "content" ] + }, + { + "login": "GabrielBianconi", + "name": "Gabriel Bianconi", + "avatar_url": "https://avatars.githubusercontent.com/u/1275491?v=4", + "profile": "http://www.gabrielbianconi.com/", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From d6e26bb350e423a8f2a90d9405060fdaf9893736 Mon Sep 17 00:00:00 2001 From: Kody Low Date: Wed, 24 Aug 2022 08:33:17 -0700 Subject: [PATCH 25/28] 2nd assert is for greater than or equal to, not "more than" like it says in the instructions --- exercises/quiz1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs index 8d05b110..d1e76e59 100644 --- a/exercises/quiz1.rs +++ b/exercises/quiz1.rs @@ -5,7 +5,7 @@ // - If // Mary is buying apples. One apple usually costs 2 Rustbucks, but if you buy -// more than 40 at once, each apple only costs 1! Write a function that calculates +// 40 or more at once, each apple only costs 1! Write a function that calculates // the price of an order of apples given the quantity bought. No hints this time! // I AM NOT DONE From 33e501981aa71a986db5db72fea5e6635e6c58b4 Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 10:12:14 +0000 Subject: [PATCH 26/28] docs: update AUTHORS.md [skip ci] --- AUTHORS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS.md b/AUTHORS.md index 02cbf0ed..8edf09bf 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -217,6 +217,7 @@ authors.
Magnus RΓΈdseth

πŸ–‹
rubiesonthesky

πŸ–‹
Gabriel Bianconi

πŸ–‹ +
Kody Low

πŸ–‹ From bf95a345533605d8fec4dbd011d4269961ed415d Mon Sep 17 00:00:00 2001 From: "allcontributors[bot]" <46447321+allcontributors[bot]@users.noreply.github.com> Date: Thu, 25 Aug 2022 10:12:15 +0000 Subject: [PATCH 27/28] docs: update .all-contributorsrc [skip ci] --- .all-contributorsrc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.all-contributorsrc b/.all-contributorsrc index e061d153..f2033dcd 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1533,6 +1533,15 @@ "contributions": [ "content" ] + }, + { + "login": "Kodylow", + "name": "Kody Low", + "avatar_url": "https://avatars.githubusercontent.com/u/74332828?v=4", + "profile": "https://github.com/Kodylow", + "contributions": [ + "content" + ] } ], "contributorsPerLine": 8, From 3309a01b5e7f18da6409435151e8ebe0c0a697dc Mon Sep 17 00:00:00 2001 From: mokou Date: Sat, 27 Aug 2022 19:48:15 +0100 Subject: [PATCH 28/28] chore: release 5.2.0 --- CHANGELOG.md | 17 +++++++++++++++++ Cargo.toml | 2 +- src/main.rs | 2 +- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cec41c59..0b15cf99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ + +## 5.2.0 (2022-08-27) + +#### Added + +- Added a `reset` command + +#### Changed + +- **options2**: Convert the exercise to use tests + +#### Fixed + +- **threads3**: Fixed a typo +- **quiz1**: Adjusted the explanations to be consistent with + the tests + ## 5.1.1 (2022-08-17) diff --git a/Cargo.toml b/Cargo.toml index d5fd93c7..25cd7bfe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustlings" -version = "5.1.1" +version = "5.2.0" authors = ["Liv ", "Carol (Nichols || Goulding) "] edition = "2021" diff --git a/src/main.rs b/src/main.rs index 9bf75e38..8eebc086 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,7 +26,7 @@ mod run; mod verify; // In sync with crate version -const VERSION: &str = "5.1.1"; +const VERSION: &str = "5.2.0"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code