diff --git a/.all-contributorsrc b/.all-contributorsrc index bd4e390..be5dc21 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -1371,6 +1371,132 @@ "contributions": [ "content" ] + }, + { + "login": "wojexe", + "name": "wojexe", + "avatar_url": "https://avatars.githubusercontent.com/u/21208490?v=4", + "profile": "https://wojexe.com", + "contributions": [ + "content" + ] + }, + { + "login": "Tostapunk", + "name": "Mattia Schiavon", + "avatar_url": "https://avatars.githubusercontent.com/u/25140297?v=4", + "profile": "https://github.com/Tostapunk", + "contributions": [ + "content" + ] + }, + { + "login": "PrettyWood", + "name": "Eric Jolibois", + "avatar_url": "https://avatars.githubusercontent.com/u/18406791?v=4", + "profile": "http://toucantoco.com", + "contributions": [ + "content" + ] + }, + { + "login": "EdwinChang24", + "name": "Edwin Chang", + "avatar_url": "https://avatars.githubusercontent.com/u/88263098?v=4", + "profile": "http://edwinchang.vercel.app", + "contributions": [ + "content" + ] + }, + { + "login": "saikatdas0790", + "name": "Saikat Das", + "avatar_url": "https://avatars.githubusercontent.com/u/7412443?v=4", + "profile": "https://saikat.dev/", + "contributions": [ + "content" + ] + }, + { + "login": "thatlittleboy", + "name": "Jeremy Goh", + "avatar_url": "https://avatars.githubusercontent.com/u/30731072?v=4", + "profile": "https://github.com/thatlittleboy", + "contributions": [ + "content" + ] + }, + { + "login": "Lioness100", + "name": "Lioness100", + "avatar_url": "https://avatars.githubusercontent.com/u/65814829?v=4", + "profile": "https://github.com/Lioness100", + "contributions": [ + "content" + ] + }, + { + "login": "tvkn", + "name": "Tristan Nicholls", + "avatar_url": "https://avatars.githubusercontent.com/u/79277926?v=4", + "profile": "https://github.com/tvkn", + "contributions": [ + "content" + ] + }, + { + "login": "clairew", + "name": "Claire", + "avatar_url": "https://avatars.githubusercontent.com/u/9344258?v=4", + "profile": "http://clairewang.net", + "contributions": [ + "content" + ] + }, + { + "login": "Mouwrice", + "name": "Maurice Van Wassenhove", + "avatar_url": "https://avatars.githubusercontent.com/u/56763273?v=4", + "profile": "https://github.com/Mouwrice", + "contributions": [ + "content" + ] + }, + { + "login": "johnmendel", + "name": "John Mendelewski", + "avatar_url": "https://avatars.githubusercontent.com/u/77524?v=4", + "profile": "http://jmthree.com", + "contributions": [ + "code" + ] + }, + { + "login": "brianfakhoury", + "name": "Brian Fakhoury", + "avatar_url": "https://avatars.githubusercontent.com/u/20828724?v=4", + "profile": "http://fakhoury.xyz", + "contributions": [ + "content" + ] + }, + { + "login": "markusboehme", + "name": "Markus Boehme", + "avatar_url": "https://avatars.githubusercontent.com/u/5074759?v=4", + "profile": "https://github.com/markusboehme", + "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, diff --git a/.editorconfig b/.editorconfig index 89cf181..aab09aa 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,6 +2,6 @@ root = true [*.rs] end_of_line = lf -insert_final_newfile = true +insert_final_newline = true indent_style = space indent_size = 4 diff --git a/AUTHORS.md b/AUTHORS.md index 1a0c167..0c07a93 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -195,6 +195,24 @@ authors.
James Bromley

🖋
swhiteCQC

🖋
Neil Pate

🖋 +
wojexe

🖋 +
Mattia Schiavon

🖋 +
Eric Jolibois

🖋 + + +
Edwin Chang

🖋 +
Saikat Das

🖋 +
Jeremy Goh

🖋 +
Lioness100

🖋 +
Tristan Nicholls

🖋 +
Claire

🖋 +
Maurice Van Wassenhove

🖋 +
John Mendelewski

💻 + + +
Brian Fakhoury

🖋 +
Markus Boehme

💻 +
Nico Vromans

🖋 diff --git a/CHANGELOG.md b/CHANGELOG.md index 095877b..8aae313 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,76 @@ + +## 5.0.0 (2022-07-16) + +#### Features + +- Hint comments in exercises now also include a reference to the + `hint` watch mode subcommand. +- **intro1**: Added more hints to point the user to the source file. +- **variables**: Switched variables3 and variables4. +- Moved `vec` and `primitive_types` exercises before `move_semantics`. +- Renamed `vec` to `vecs` to be more in line with the naming in general. +- Split up the `collections` exercises in their own folders. +- **vec2**: Added a second part of the function that provides an alternative, + immutable way of modifying vec values. +- **enums3**: Added a hint. +- Moved `strings` before `modules`. +- Added a `strings3` exercise to teach modifying strings. +- Added a `hashmaps3` exercise for some advanced usage of hashmaps. +- Moved the original `quiz2` to be `strings4`, since it only tested strings + anyways. +- Reworked `quiz2` into a new exercise that tests more chapters. +- Renamed `option` to `options`. +- **options1**: Rewrote parts of the exercise to remove the weird array + iteration stuff. +- Moved `generics3` to be `quiz3`. +- Moved box/arc exercises behind `iterators`. +- **iterators4**: Added a test for factorials of zero. +- Split `threads1` between two exercises, the first one focusing more on + `JoinHandle`s. +- Added a `threads3` exercises that uses `std::sync::mpsc`. +- Added a `clippy3` exercises with some more interesting checks. +- **as_ref_mut**: Added a section that actually tests `AsMut`. +- Added 3 new lifetimes exercises. +- Added 3 new traits exercises. + +#### Bug Fixes + +- **variables2**: Made output messages more verbose. +- **variables5**: Added a nudging hint about shadowing. +- **variables6**: Fixed link to book. +- **functions**: Clarified the README wording. Generally cleaned up + some hints and added some extra comments. +- **if2**: Renamed function name to `foo_if_fizz`. +- **move_semantics**: Clarified some hints. +- **quiz1**: Renamed the function name to be more verbose. +- **structs1**: Use an integer type instead of strings. Renamed "unit structs" + to "unit-like structs", as is used in the book. +- **structs3**: Added the `panic!` statement in from the beginning. +- **errors1**: Use `is_empty()` instead of `len() > 0` +- **errors3**: Improved the hint. +- **errors5**: Improved exercise instructions and the hint. +- **errors6**: Provided the skeleton of one of the functions that's supposed + to be implemented. +- **iterators3**: Inserted `todo!` into `divide()` to keep a compiler error + from happening. +- **from_str**: Added a hint comment about string error message conversion with + `Box`. +- **try_from_into**: Fixed the function name in comment. + +#### Removed + +- Removed the legacy LSP feature that was using `mod.rs` files. +- Removed `quiz4`. +- Removed `advanced_errs`. These were the last exercises in the recommended + order, and I've always felt like they didn't quite fit in with the mostly + simple, book-following style we've had in Rustlings. + +#### Housekeeping + +- Added missing exercises to the book index. +- Updated spacing in Cargo.toml. +- Added a GitHub actions config so that tests run on every PR/commit. + ## 4.8.0 (2022-07-01) diff --git a/Cargo.lock b/Cargo.lock index df190ad..862a8a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -459,7 +459,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rustlings" -version = "4.8.0" +version = "5.0.0" dependencies = [ "argh", "assert_cmd", diff --git a/Cargo.toml b/Cargo.toml index 8a3264d..910b538 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustlings" -version = "4.8.0" +version = "5.0.0" authors = ["Liv ", "Carol (Nichols || Goulding) "] edition = "2021" diff --git a/README.md b/README.md index 103aec8..afa55c8 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ If you get a permission denied message, you might have to exclude the directory ## Manually -Basically: Clone the repository at the latest tag, run `cargo install`. +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 4.7.1) -git clone -b 4.7.1 --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.0.0) +git clone -b 5.0.0 --depth 1 https://github.com/rust-lang/rustlings cd rustlings cargo install --force --path . ``` diff --git a/exercises/README.md b/exercises/README.md index 2ea2990..e52137c 100644 --- a/exercises/README.md +++ b/exercises/README.md @@ -5,20 +5,22 @@ | variables | §3.1 | | functions | §3.3 | | if | §3.5 | -| move_semantics | §4.1, §4.2 | | primitive_types | §3.2, §4.3 | +| vecs | §8.1 | +| move_semantics | §4.1, §4.2 | | structs | §5.1, §5.3 | | enums | §6, §18.3 | -| modules | §7 | -| collections | §8.1, §8.3 | | strings | §8.2 | +| modules | §7 | +| hashmaps | §8.3 | +| options | §10.1 | | error_handling | §9 | | generics | §10 | -| option | §10.1 | | traits | §10.2 | | tests | §11.1 | +| lifetimes | §10.3 | | standard_library_types | §13.2, §15.1, §16.3 | -| threads | §16.1 | +| threads | §16.1, §16.2, §16.3 | | macros | §19.6 | | clippy | n/a | | conversions | n/a | diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs index 67411c5..2ba8f90 100644 --- a/exercises/error_handling/errors5.rs +++ b/exercises/error_handling/errors5.rs @@ -4,6 +4,8 @@ // This exercise uses some concepts that we won't get to until later in the course, like `Box` and the // `From` trait. It's not important to understand them in detail right now, but you can read ahead if you like. +// For now, think of the `Box` type as an "I want anything that does ???" type, which, given +// Rust's usual standards for runtime safety, should strike you as somewhat lenient! // In short, this particular use case for boxes is for when you want to own a value and you care only that it is a // type which implements a particular trait. To do so, The Box is declared as of type Box where Trait is the trait diff --git a/exercises/macros/README.md b/exercises/macros/README.md index 319d840..31a941b 100644 --- a/exercises/macros/README.md +++ b/exercises/macros/README.md @@ -7,4 +7,4 @@ macros. Instead, we'll show you how to use and create them. ## Further information - [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html) -- [The Little Book of Rust Macros](https://danielkeep.github.io/tlborm/book/index.html) +- [The Little Book of Rust Macros](https://veykril.github.io/tlborm/) diff --git a/exercises/options/options1.rs b/exercises/options/options1.rs index 038fb48..022d3d6 100644 --- a/exercises/options/options1.rs +++ b/exercises/options/options1.rs @@ -3,17 +3,13 @@ // I AM NOT DONE -// you can modify anything EXCEPT for this function's signature -fn print_number(maybe_number: Option) { - println!("printing: {}", maybe_number.unwrap()); -} - // This function returns how much icecream there is left in the fridge. // If it's before 10PM, there's 5 pieces left. At 10PM, someone eats them // all, so there'll be no more left :( // TODO: Return an Option! fn maybe_icecream(time_of_day: u16) -> Option { // We use the 24-hour system here, so 10PM is a value of 22 + // The Option output should gracefully handle cases where time_of_day > 24. ??? } @@ -23,15 +19,17 @@ mod tests { #[test] fn check_icecream() { - assert_eq!(maybe_icecream(10), Some(5)); - assert_eq!(maybe_icecream(23), None); - assert_eq!(maybe_icecream(22), None); + 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); } #[test] 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); } } diff --git a/exercises/quiz2.rs b/exercises/quiz2.rs index f7437fd..d8fa954 100644 --- a/exercises/quiz2.rs +++ b/exercises/quiz2.rs @@ -42,7 +42,7 @@ mod my_module { #[cfg(test)] mod tests { - // TODO: What to we have to import to have `transformer` in scope? + // TODO: What do we have to import to have `transformer` in scope? use ???; use super::Command; diff --git a/exercises/standard_library_types/box1.rs b/exercises/standard_library_types/box1.rs index 9d9237c..66cf00f 100644 --- a/exercises/standard_library_types/box1.rs +++ b/exercises/standard_library_types/box1.rs @@ -10,7 +10,7 @@ // elements: the value of the current item and the next item. The last item is a value called `Nil`. // // Step 1: use a `Box` in the enum definition to make the code compile -// Step 2: create both empty and non-empty cons lists by replacing `unimplemented!()` +// Step 2: create both empty and non-empty cons lists by replacing `todo!()` // // Note: the tests should not be changed // @@ -33,11 +33,11 @@ fn main() { } pub fn create_empty_list() -> List { - unimplemented!() + todo!() } pub fn create_non_empty_list() -> List { - unimplemented!() + todo!() } #[cfg(test)] diff --git a/exercises/standard_library_types/cow1.rs b/exercises/standard_library_types/cow1.rs new file mode 100644 index 0000000..5fba251 --- /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/exercises/strings/strings3.rs b/exercises/strings/strings3.rs index 9e25d30..e2353ae 100644 --- a/exercises/strings/strings3.rs +++ b/exercises/strings/strings3.rs @@ -4,7 +4,7 @@ // I AM NOT DONE fn trim_me(input: &str) -> String { - // TODO: Remove whitespace from the end of a string! + // TODO: Remove whitespace from both ends of a string! ??? } diff --git a/exercises/traits/traits4.rs b/exercises/traits/traits4.rs index 280aaad..6b54166 100644 --- a/exercises/traits/traits4.rs +++ b/exercises/traits/traits4.rs @@ -1,7 +1,7 @@ // traits4.rs // // Your task is to replace the '??' sections so the code compiles. -// Don't change any line other than 21. +// Don't change any line other than the marked one. // Execute `rustlings hint traits4` or use the `hint` watch subcommand for a hint. // I AM NOT DONE @@ -19,6 +19,7 @@ struct OtherSoftware {} impl Licensed for SomeSoftware {} impl Licensed for OtherSoftware {} +// YOU MAY ONLY CHANGE THE NEXT LINE fn compare_license_types(software: ??, software_two: ??) -> bool { software.licensing_info() == software_two.licensing_info() } diff --git a/exercises/traits/traits5.rs b/exercises/traits/traits5.rs index 290c047..0fbca28 100644 --- a/exercises/traits/traits5.rs +++ b/exercises/traits/traits5.rs @@ -1,7 +1,7 @@ // traits5.rs // // Your task is to replace the '??' sections so the code compiles. -// Don't change any line other than 27. +// Don't change any line other than the marked one. // Execute `rustlings hint traits5` or use the `hint` watch subcommand for a hint. // I AM NOT DONE @@ -18,15 +18,20 @@ pub trait OtherTrait { } } -struct SomeStruct { - name: String, -} +struct SomeStruct {} +struct OtherStruct {} impl SomeTrait for SomeStruct {} impl OtherTrait for SomeStruct {} +impl SomeTrait for OtherStruct {} +impl OtherTrait for OtherStruct {} +// YOU MAY ONLY CHANGE THE NEXT LINE fn some_func(item: ??) -> bool { item.some_function() && item.other_function() } -fn main() {} +fn main() { + some_func(SomeStruct {}); + some_func(OtherStruct {}); +} diff --git a/info.toml b/info.toml index a72c014..9aa11e8 100644 --- a/info.toml +++ b/info.toml @@ -63,7 +63,7 @@ name = "variables5" path = "exercises/variables/variables5.rs" mode = "compile" hint = """ -In variables3 we already learned how to make an immutable variable mutable +In variables4 we already learned how to make an immutable variable mutable using a special keyword. Unfortunately this doesn't help us much in this exercise because we want to assign a different typed value to an existing variable. Sometimes you may also like to reuse existing variable names because you are just converting @@ -123,8 +123,8 @@ name = "functions4" path = "exercises/functions/functions4.rs" mode = "compile" hint = """ -The error message points to line 14 and says it expects a type after the -`->`. This is where the function's return type should be-- take a look at +The error message points to line 17 and says it expects a type after the +`->`. This is where the function's return type should be -- take a look at the `is_even` function for an example! Also: Did you figure out that, technically, u32 would be the more fitting type @@ -732,7 +732,7 @@ name = "traits5" path = "exercises/traits/traits5.rs" mode = "compile" hint = """ -To ensure a paramter implements multiple traits use the '+ syntax'. Try replacing the +To ensure a parameter implements multiple traits use the '+ syntax'. Try replacing the '??' with 'impl <> + <>'. See the documentation at: https://doc.rust-lang.org/book/ch10-02-traits.html#specifying-multiple-trait-bounds-with-the--syntax @@ -746,7 +746,7 @@ path = "exercises/quiz3.rs" mode = "test" hint = """ To find the best solution to this challenge you're going to need to think back to your -knowledge of traits, specifically Trait Bound Syntax - you may also need this: "use std::fmt::Display;"""" +knowledge of traits, specifically Trait Bound Syntax - you may also need this: `use std::fmt::Display;`.""" # TESTS @@ -795,7 +795,10 @@ name = "lifetimes2" path = "exercises/lifetimes/lifetimes2.rs" mode = "compile" hint = """ -What is the compiler checking? How could you change how long an owned variable lives?""" +Remember that the generic lifetime 'a will get the concrete lifetime that is equal to the smaller of the lifetimes of x and y. +You can take at least two paths to achieve the desired result while keeping the inner block: +1. Move the string2 declaration to make it live as long as string1 (how is result declared?) +2. Move println! into the inner block""" [[exercises]] name = "lifetimes3" @@ -943,6 +946,17 @@ https://doc.rust-lang.org/book/ch15-04-rc.html * Unforunately Pluto is no longer considered a planet :( """ +[[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]] @@ -999,7 +1013,7 @@ 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. -Multiple producers are possibile by using clone() to create a duplicate +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. """ diff --git a/src/main.rs b/src/main.rs index 15c3095..0ddb733 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 = "4.8.0"; +const VERSION: &str = "5.0.0"; #[derive(FromArgs, PartialEq, Debug)] /// Rustlings is a collection of small exercises to get you used to writing and reading Rust code diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index fc46b98..0be191f 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -176,7 +176,7 @@ fn run_single_test_success_with_output() { .current_dir("tests/fixture/success/") .assert() .code(0) - .stdout(predicates::str::contains("THIS TEST TOO SHALL PAS")); + .stdout(predicates::str::contains("THIS TEST TOO SHALL PASS")); } #[test] @@ -187,7 +187,7 @@ fn run_single_test_success_without_output() { .current_dir("tests/fixture/success/") .assert() .code(0) - .stdout(predicates::str::contains("THIS TEST TOO SHALL PAS").not()); + .stdout(predicates::str::contains("THIS TEST TOO SHALL PASS").not()); } #[test]