diff --git a/.all-contributorsrc b/.all-contributorsrc
index bd4e3902..be5dc21a 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 89cf181d..aab09aa3 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 1a0c167f..0c07a933 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 095877b6..8aae3138 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 df190ad8..862a8a2e 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 8a3264d9..910b5389 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 103aec8b..afa55c86 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 2ea29909..e52137ca 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 67411c58..2ba8f903 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 319d8408..31a941b7 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 038fb48e..022d3d66 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 f7437fd2..d8fa954a 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 9d9237c1..66cf00f3 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 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/exercises/strings/strings3.rs b/exercises/strings/strings3.rs
index 9e25d307..e2353aec 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 280aaade..6b541665 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 290c0479..0fbca28a 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 a72c0147..9aa11e8a 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 15c3095e..0ddb7331 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 fc46b983..0be191f0 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]