diff --git a/.all-contributorsrc b/.all-contributorsrc
index d18743c2..26fd5c99 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1,6 +1,6 @@
{
"files": [
- "README.md"
+ "AUTHORS.md"
],
"imageSize": 100,
"commit": false,
@@ -1002,6 +1002,150 @@
"contributions": [
"content"
]
+ },
+ {
+ "login": "EmisonLu",
+ "name": "Zhenghao Lu",
+ "avatar_url": "https://avatars.githubusercontent.com/u/54395432?v=4",
+ "profile": "https://github.com/EmisonLu",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "fredr",
+ "name": "Fredrik Enestad",
+ "avatar_url": "https://avatars.githubusercontent.com/u/762956?v=4",
+ "profile": "https://soundtrackyourbrand.com",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "xuesongbj",
+ "name": "xuesong",
+ "avatar_url": "https://avatars.githubusercontent.com/u/18476085?v=4",
+ "profile": "http://xuesong.pydevops.com",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "MpdWalsh",
+ "name": "Michael Walsh",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48160144?v=4",
+ "profile": "https://github.com/MpdWalsh",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "alirezaghey",
+ "name": "alirezaghey",
+ "avatar_url": "https://avatars.githubusercontent.com/u/26653424?v=4",
+ "profile": "https://github.com/alirezaghey",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "frvannes16",
+ "name": "Franklin van Nes",
+ "avatar_url": "https://avatars.githubusercontent.com/u/3188475?v=4",
+ "profile": "https://github.com/frvannes16",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "nekonako",
+ "name": "nekonako",
+ "avatar_url": "https://avatars.githubusercontent.com/u/46141275?v=4",
+ "profile": "https://nekonako.github.io",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "tan-zx",
+ "name": "ZX",
+ "avatar_url": "https://avatars.githubusercontent.com/u/67887489?v=4",
+ "profile": "https://github.com/tan-zx",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "sundevilyang",
+ "name": "Yang Wen",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1499214?v=4",
+ "profile": "https://github.com/sundevilyang",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "highb",
+ "name": "Brandon High",
+ "avatar_url": "https://avatars.githubusercontent.com/u/759848?v=4",
+ "profile": "https://brandon-high.com",
+ "contributions": [
+ "doc"
+ ]
+ },
+ {
+ "login": "x-hgg-x",
+ "name": "x-hgg-x",
+ "avatar_url": "https://avatars.githubusercontent.com/u/39058530?v=4",
+ "profile": "https://github.com/x-hgg-x",
+ "contributions": [
+ "code"
+ ]
+ },
+ {
+ "login": "KisaragiEffective",
+ "name": "Kisaragi",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48310258?v=4",
+ "profile": "http://kisaragieffective.github.io",
+ "contributions": [
+ "doc"
+ ]
+ },
+ {
+ "login": "Kallu-A",
+ "name": "Lucas Aries",
+ "avatar_url": "https://avatars.githubusercontent.com/u/73198738?v=4",
+ "profile": "https://github.com/Kallu-A",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "ragreenburg",
+ "name": "ragreenburg",
+ "avatar_url": "https://avatars.githubusercontent.com/u/24358100?v=4",
+ "profile": "https://github.com/ragreenburg",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "stevenfukase",
+ "name": "stevenfukase",
+ "avatar_url": "https://avatars.githubusercontent.com/u/66785624?v=4",
+ "profile": "https://github.com/stevenfukase",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "J-S-Kim",
+ "name": "J-S-Kim",
+ "avatar_url": "https://avatars.githubusercontent.com/u/17569303?v=4",
+ "profile": "https://github.com/J-S-Kim",
+ "contributions": [
+ "content"
+ ]
}
],
"contributorsPerLine": 8,
diff --git a/AUTHORS.md b/AUTHORS.md
new file mode 100644
index 00000000..1dc56475
--- /dev/null
+++ b/AUTHORS.md
@@ -0,0 +1,175 @@
+## Authors
+
+This file lists the people that have contributed to this project.
+
+Excluded from this list are @carols10cents and @diannasoreil, the principal
+authors.
+
+
+
+
+
+
+
+
+
+
+
+This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fcc39e42..24da1bc0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,46 @@
+
+## 4.7.0 (2022-04-14)
+
+
+#### Features
+
+* Add move_semantics6.rs exercise (#908) ([3f0e1303](https://github.com/rust-lang/rustlings/commit/3f0e1303e0b3bf3fecc0baced3c8b8a37f83c184))
+* **intro:** Add intro section. ([21c9f441](https://github.com/rust-lang/rustlings/commit/21c9f44168394e08338fd470b5f49b1fd235986f))
+* Include exercises folder in the project structure behind a feature, enabling rust-analyzer to work (#917) ([179a75a6](https://github.com/rust-lang/rustlings/commit/179a75a68d03ac9518dec2297fb17f91a4fc506b))
+
+#### Bug Fixes
+
+* Fix a few spelling mistakes ([1c0fe3cb](https://github.com/rust-lang/rustlings/commit/1c0fe3cbcca85f90b3985985b8e265ee872a2ab2))
+* **cli:**
+ * Move long text strings into constants. ([f78c4802](https://github.com/rust-lang/rustlings/commit/f78c48020830d7900dd8d81f355606581670446d))
+ * Replace `filter_map()` with `find_map()` ([9b27e8d](https://github.com/rust-lang/rustlings/commit/9b27e8d993ca20232fe38a412750c3f845a83b65))
+* **clippy1:**
+ * Set clippy::float_cmp lint to deny (#907) ([71a06044](https://github.com/rust-lang/rustlings/commit/71a06044e6a96ff756dc31d7b0ed665ae4badb57))
+ * Updated code to test correctness clippy lint with approx_constant lint rule ([f2650de3](https://github.com/rust-lang/rustlings/commit/f2650de369810867d2763e935ac0963c32ec420e))
+* **errors1:**
+ * Add a comment to make the purpose more clear (#486) ([cbcde345](https://github.com/rust-lang/rustlings/commit/cbcde345409c3e550112e449242848eaa3391bb6))
+ * Don't modify tests (#958) ([60bb7cc](https://github.com/rust-lang/rustlings/commit/60bb7cc3931d21d3986ad52b2b302e632a93831c))
+* **errors6:** Remove existing answer code ([43d0623](https://github.com/rust-lang/rustlings/commit/43d0623086edbc46fe896ba59c7afa22c3da9f7a))
+* **functions5:** Remove wrong new line and small English improvements (#885) ([8ef4869b](https://github.com/rust-lang/rustlings/commit/8ef4869b264094e5a9b50452b4534823a9df19c3))
+* **install:** protect path with whitespaces using quotes and stop at the first error ([d114847f](https://github.com/rust-lang/rustlings/commit/d114847f256c5f571c0b4c87e04b04bce3435509))
+* **intro1:** Add compiler error explanation. ([9b8de655](https://github.com/rust-lang/rustlings/commit/9b8de65525a5576b78cf0c8e4098cdd34296338f))
+* **iterators1:** reorder TODO steps ([0bd7a063](https://github.com/rust-lang/rustlings/commit/0bd7a0631a17a9d69af5746795a30efc9cf64e6e))
+* **move_semantics2:** Add comment ([89650f80](https://github.com/rust-lang/rustlings/commit/89650f808af23a32c9a2c6d46592b77547a6a464))
+* **move_semantics5:** correct typo (#857) ([46c28d5c](https://github.com/rust-lang/rustlings/commit/46c28d5cef3d8446b5a356b19d8dbc725f91a3a0))
+* **quiz1:** update to say quiz covers "If" ([1622e8c1](https://github.com/rust-lang/rustlings/commit/1622e8c198d89739765c915203efff0091bdeb78))
+* **structs3:**
+ * Add a hint for panic (#608) ([4f7ff5d9](https://github.com/rust-lang/rustlings/commit/4f7ff5d9c7b2d8b045194c1a9469d37e30257c4a))
+ * remove redundant 'return' (#852) ([bf33829d](https://github.com/rust-lang/rustlings/commit/bf33829da240375d086f96267fc2e02fa6b07001))
+ * Assigned value to `cents_per_gram` in test ([d1ee2da](https://github.com/rust-lang/rustlings/commit/d1ee2daf14f19105e6db3f9c610f44293d688532))
+* **structs3.rs:** assigned value to cents_per_gram in test ([d1ee2daf](https://github.com/rust-lang/rustlings/commit/d1ee2daf14f19105e6db3f9c610f44293d688532))
+* **traits1:** rename test functions to snake case (#854) ([1663a16e](https://github.com/rust-lang/rustlings/commit/1663a16eade6ca646b6ed061735f7982434d530d))
+
+#### Documentation improvements
+
+* Add hints on how to get GCC installed (#741) ([bc56861](https://github.com/rust-lang/rustlings/commit/bc5686174463ad6f4f6b824b0e9b97c3039d4886))
+* Fix some code blocks that were not highlighted ([17f9d74](https://github.com/rust-lang/rustlings/commit/17f9d7429ccd133a72e815fb5618e0ce79560929))
+
+
## 4.6.0 (2021-09-25)
diff --git a/Cargo.lock b/Cargo.lock
index e536d1b7..c3e8290f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -541,7 +541,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
name = "rustlings"
-version = "4.6.0"
+version = "4.7.0"
dependencies = [
"argh",
"assert_cmd",
diff --git a/Cargo.toml b/Cargo.toml
index 3b2a85a7..a340cd21 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,8 +1,8 @@
[package]
name = "rustlings"
-version = "4.6.0"
-authors = ["anastasie ", "Carol (Nichols || Goulding) "]
-edition = "2018"
+version = "4.7.0"
+authors = ["mokou ", "Carol (Nichols || Goulding) "]
+edition = "2021"
[dependencies]
argh = "0.1.4"
@@ -11,7 +11,7 @@ console = "0.7.7"
notify = "4.0.15"
toml = "0.4.10"
regex = "1.1.6"
-serde = {version = "1.0.10", features = ["derive"]}
+serde = { version = "1.0.10", features = ["derive"] }
[[bin]]
name = "rustlings"
@@ -21,3 +21,6 @@ path = "src/main.rs"
assert_cmd = "0.11.0"
predicates = "1.0.1"
glob = "0.3.0"
+
+[features]
+exercises = []
diff --git a/README.md b/README.md
index 18e0b73a..876578ee 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,3 @@
-
-[](#contributors-)
-
-
# rustlings π¦β€οΈ
Greetings and welcome to `rustlings`. This project contains small exercises to get you used to reading and writing Rust code. This includes reading and responding to compiler messages!
@@ -16,6 +12,7 @@ Alternatively, for a first-time Rust learner, there are several other resources:
## Getting Started
_Note: If you're on MacOS, make sure you've installed Xcode and its developer tools by typing `xcode-select --install`._
+_Note: If you're on Linux, make sure you've installed gcc. Deb: `sudo apt install gcc`. Yum: `sudo yum -y install gcc`._
You will need to have Rust installed. You can get it by visiting https://rustup.rs. This'll also install Cargo, Rust's package/project manager.
@@ -35,13 +32,13 @@ This will install Rustlings and give you access to the `rustlings` command. Run
In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
-```ps
+```ps1
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
```
Then, you can run:
-```ps
+```ps1
Start-BitsTransfer -Source https://git.io/JTL5v -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
```
@@ -67,6 +64,7 @@ cargo install --force --path .
```
If there are installation errors, ensure that your toolchain is up to date. For the latest, run:
+
```bash
rustup update
```
@@ -106,17 +104,18 @@ rustlings run next
In case you get stuck, you can run the following command to get a hint for your
exercise:
-``` bash
+```bash
rustlings hint myExercise1
```
You can also get the hint for the next unsolved exercise with the following command:
-``` bash
+```bash
rustlings hint next
```
To check your progress, you can run the following command:
+
```bash
rustlings list
```
@@ -125,6 +124,27 @@ rustlings list
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once. These quizzes are found in `exercises/quizN.rs`.
+## Enabling `rust-analyzer`
+
+`rust-analyzer` support is provided, but it depends on your editor
+whether it's enabled by default. (RLS support is not provided)
+
+To enable `rust-analyzer`, you'll need to make Cargo build the project
+with the `exercises` feature, which will automatically include the `exercises/`
+subfolder in the project. The easiest way to do this is to tell your editor to
+build the project with all features (the equivalent of `cargo build --all-features`).
+For specific editor instructions:
+
+- **VSCode**: Add a `.vscode/settings.json` file with the following:
+```json
+{
+ "rust-analyzer.cargo.features": ["exercises"]
+}
+```
+- **IntelliJ-based Editors**: Using the Rust plugin, everything should work
+ by default.
+- _Missing your editor? Feel free to contribute more instructions!_
+
## Continuing On
Once you've completed Rustlings, put your new knowledge to good use! Continue practicing your Rust skills by building your own projects, contributing to Rustlings, or finding other open-source projects to contribute to.
@@ -134,14 +154,14 @@ Once you've completed Rustlings, put your new knowledge to good use! Continue pr
If you want to remove Rustlings from your system, there's two steps. First, you'll need to remove the exercises folder that the install script created
for you:
-``` bash
+```bash
rm -rf rustlings # or your custom folder name, if you chose and or renamed it
```
Second, since Rustlings got installed via `cargo install`, it's only reasonable to assume that you can also remove it using Cargo, and
exactly that is the case. Run `cargo uninstall` to remove the `rustlings` binary:
-``` bash
+```bash
cargo uninstall rustlings
```
@@ -171,153 +191,4 @@ See [CONTRIBUTING.md](./CONTRIBUTING.md).
## Contributors β¨
-Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):
-
-
-
-
-
-
-
-
-
-
-
-This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
+Thanks goes to the wonderful people listed in [AUTHORS.md](./AUTHORS.md) π
diff --git a/default_out.txt b/default_out.txt
deleted file mode 100644
index b90d1e3a..00000000
--- a/default_out.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-Thanks for installing Rustlings!
-
-Is this your first time? Don't worry, Rustlings was made for beginners! We are
-going to teach you a lot of things about Rust, but before we can get
-started, here's a couple of notes about how Rustlings operates:
-
-1. The central concept behind Rustlings is that you solve exercises. These
- exercises usually have some sort of syntax error in them, which will cause
- them to fail compilation or testing. Sometimes there's a logic error instead
- of a syntax error. No matter what error, it's your job to find it and fix it!
- You'll know when you fixed it because then, the exercise will compile and
- Rustlings will be able to move on to the next exercise.
-2. If you run Rustlings in watch mode (which we recommend), it'll automatically
- start with the first exercise. Don't get confused by an error message popping
- up as soon as you run Rustlings! This is part of the exercise that you're
- supposed to solve, so open the exercise file in an editor and start your
- detective work!
-3. If you're stuck on an exercise, there is a helpful hint you can view by typing
- 'hint' (in watch mode), or running `rustlings hint myexercise`.
-4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
- (https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
- and sometimes, other learners do too so you can help each other out!
-
-Got all that? Great! To get started, run `rustlings watch` in order to get the first
-exercise. Make sure to have your editor open!
diff --git a/exercises/advanced_errors/advanced_errs2.rs b/exercises/advanced_errors/advanced_errs2.rs
index d9d44d06..54e669fd 100644
--- a/exercises/advanced_errors/advanced_errs2.rs
+++ b/exercises/advanced_errors/advanced_errs2.rs
@@ -64,7 +64,6 @@ impl Display for ParseClimateError {
match self {
NoCity => write!(f, "no city name"),
ParseFloat(e) => write!(f, "error parsing temperature: {}", e),
- _ => write!(f, "unhandled error!"),
}
}
}
diff --git a/exercises/advanced_errors/mod.rs b/exercises/advanced_errors/mod.rs
new file mode 100644
index 00000000..e33fb80d
--- /dev/null
+++ b/exercises/advanced_errors/mod.rs
@@ -0,0 +1,2 @@
+mod advanced_errs1;
+mod advanced_errs2;
diff --git a/exercises/clippy/clippy1.rs b/exercises/clippy/clippy1.rs
index bdb5dd2c..c5f84a9c 100644
--- a/exercises/clippy/clippy1.rs
+++ b/exercises/clippy/clippy1.rs
@@ -8,10 +8,16 @@
// I AM NOT DONE
+use std::f32;
+
fn main() {
- let x = 1.2331f64;
- let y = 1.2332f64;
- if y != x {
- println!("Success!");
- }
+ let pi = 3.14f32;
+ let radius = 5.00f32;
+
+ let area = pi * f32::powi(radius, 2);
+
+ println!(
+ "The area of a circle with radius {:.2} is {:.5}!",
+ radius, area
+ )
}
diff --git a/exercises/clippy/mod.rs b/exercises/clippy/mod.rs
new file mode 100644
index 00000000..689dc95f
--- /dev/null
+++ b/exercises/clippy/mod.rs
@@ -0,0 +1,2 @@
+mod clippy1;
+mod clippy2;
diff --git a/exercises/collections/mod.rs b/exercises/collections/mod.rs
new file mode 100644
index 00000000..f46c1424
--- /dev/null
+++ b/exercises/collections/mod.rs
@@ -0,0 +1,4 @@
+mod hashmap1;
+mod hashmap2;
+mod vec1;
+mod vec2;
diff --git a/exercises/conversions/mod.rs b/exercises/conversions/mod.rs
new file mode 100644
index 00000000..69f66ae4
--- /dev/null
+++ b/exercises/conversions/mod.rs
@@ -0,0 +1,5 @@
+mod as_ref_mut;
+mod from_into;
+mod from_str;
+mod try_from_into;
+mod using_as;
diff --git a/exercises/enums/mod.rs b/exercises/enums/mod.rs
new file mode 100644
index 00000000..a23fd6e5
--- /dev/null
+++ b/exercises/enums/mod.rs
@@ -0,0 +1,3 @@
+mod enums1;
+mod enums2;
+mod enums3;
diff --git a/exercises/error_handling/errors1.rs b/exercises/error_handling/errors1.rs
index 9c24d85d..c417fb26 100644
--- a/exercises/error_handling/errors1.rs
+++ b/exercises/error_handling/errors1.rs
@@ -1,9 +1,8 @@
// errors1.rs
// This function refuses to generate text to be printed on a nametag if
// you pass it an empty string. It'd be nicer if it explained what the problem
-// was, instead of just sometimes returning `None`. The 2nd test currently
-// does not compile or pass, but it illustrates the behavior we would like
-// this function to have.
+// was, instead of just sometimes returning `None`. Thankfully, Rust has a similar
+// construct to `Option` that can be used to express error conditions. Let's use it!
// Execute `rustlings hint errors1` for hints!
// I AM NOT DONE
@@ -21,14 +20,11 @@ pub fn generate_nametag_text(name: String) -> Option {
mod tests {
use super::*;
- // This test passes initially if you comment out the 2nd test.
- // You'll need to update what this test expects when you change
- // the function under test!
#[test]
fn generates_nametag_text_for_a_nonempty_name() {
assert_eq!(
generate_nametag_text("BeyoncΓ©".into()),
- Some("Hi! My name is BeyoncΓ©".into())
+ Ok("Hi! My name is BeyoncΓ©".into())
);
}
@@ -36,6 +32,7 @@ mod tests {
fn explains_why_generating_nametag_text_fails() {
assert_eq!(
generate_nametag_text("".into()),
+ // Don't change this line
Err("`name` was empty; it must be nonempty.".into())
);
}
diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs
index 0f6b27a6..847a049a 100644
--- a/exercises/error_handling/errors6.rs
+++ b/exercises/error_handling/errors6.rs
@@ -20,9 +20,6 @@ enum ParsePosNonzeroError {
}
impl ParsePosNonzeroError {
- fn from_creation(err: CreationError) -> ParsePosNonzeroError {
- ParsePosNonzeroError::Creation(err)
- }
// TODO: add another error conversion function here.
}
diff --git a/exercises/error_handling/mod.rs b/exercises/error_handling/mod.rs
new file mode 100644
index 00000000..539fa23d
--- /dev/null
+++ b/exercises/error_handling/mod.rs
@@ -0,0 +1,6 @@
+mod errors1;
+mod errors2;
+mod errors3;
+mod errors4;
+mod errors5;
+mod errors6;
diff --git a/exercises/functions/mod.rs b/exercises/functions/mod.rs
new file mode 100644
index 00000000..445b6f58
--- /dev/null
+++ b/exercises/functions/mod.rs
@@ -0,0 +1,5 @@
+mod functions1;
+mod functions2;
+mod functions3;
+mod functions4;
+mod functions5;
diff --git a/exercises/generics/mod.rs b/exercises/generics/mod.rs
new file mode 100644
index 00000000..5b93555c
--- /dev/null
+++ b/exercises/generics/mod.rs
@@ -0,0 +1,3 @@
+mod generics1;
+mod generics2;
+mod generics3;
diff --git a/exercises/if/mod.rs b/exercises/if/mod.rs
new file mode 100644
index 00000000..c5d02445
--- /dev/null
+++ b/exercises/if/mod.rs
@@ -0,0 +1,2 @@
+mod if1;
+mod if2;
diff --git a/exercises/intro/README.md b/exercises/intro/README.md
new file mode 100644
index 00000000..d32e4a8b
--- /dev/null
+++ b/exercises/intro/README.md
@@ -0,0 +1,8 @@
+# Intro
+
+Rust uses the `print!` and `println!` macros to print text to the console.
+
+## Further information
+
+- [Hello World](https://doc.rust-lang.org/rust-by-example/hello.html)
+- [Formatted print](https://doc.rust-lang.org/rust-by-example/hello/print.html)
diff --git a/exercises/intro/intro1.rs b/exercises/intro/intro1.rs
new file mode 100644
index 00000000..1c4582de
--- /dev/null
+++ b/exercises/intro/intro1.rs
@@ -0,0 +1,23 @@
+// intro1.rs
+// About this `I AM NOT DONE` thing:
+// We sometimes encourage you to keep trying things on a given exercise, even
+// after you already figured it out. If you got everything working and feel
+// ready for the next exercise, remove the `I AM NOT DONE` comment below.
+// Execute the command `rustlings hint intro1` for a hint.
+
+// I AM NOT DONE
+
+fn main() {
+ println!("Hello and");
+ println!(r#" welcome to... "#);
+ println!(r#" _ _ _ "#);
+ println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
+ println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
+ println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
+ println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
+ println!(r#" |___/ "#);
+ println!();
+ println!("This exercise compiles successfully. The remaining exercises contain a compiler");
+ println!("or logic error. The central concept behind Rustlings is to fix these errors and");
+ println!("solve the exercises. Good luck!");
+}
diff --git a/exercises/intro/intro2.rs b/exercises/intro/intro2.rs
new file mode 100644
index 00000000..97a073f0
--- /dev/null
+++ b/exercises/intro/intro2.rs
@@ -0,0 +1,9 @@
+// intro2.rs
+// Make the code print a greeting to the world.
+// Execute `rustlings hint intro2` for a hint.
+
+// I AM NOT DONE
+
+fn main() {
+ println!("Hello {}!");
+}
diff --git a/exercises/intro/mod.rs b/exercises/intro/mod.rs
new file mode 100644
index 00000000..445c47ab
--- /dev/null
+++ b/exercises/intro/mod.rs
@@ -0,0 +1,2 @@
+mod intro1;
+mod intro2;
diff --git a/exercises/macros/mod.rs b/exercises/macros/mod.rs
new file mode 100644
index 00000000..9f65acf5
--- /dev/null
+++ b/exercises/macros/mod.rs
@@ -0,0 +1,4 @@
+mod macros1;
+mod macros2;
+mod macros3;
+mod macros4;
diff --git a/exercises/mod.rs b/exercises/mod.rs
new file mode 100644
index 00000000..6a143b56
--- /dev/null
+++ b/exercises/mod.rs
@@ -0,0 +1,26 @@
+mod advanced_errors;
+mod clippy;
+mod collections;
+mod conversions;
+mod enums;
+mod error_handling;
+mod functions;
+mod generics;
+mod r#if;
+mod intro;
+mod macros;
+mod modules;
+mod move_semantics;
+mod option;
+mod primitive_types;
+mod quiz1;
+mod quiz2;
+mod quiz3;
+mod quiz4;
+mod standard_library_types;
+mod strings;
+mod structs;
+mod tests;
+mod threads;
+mod traits;
+mod variables;
diff --git a/exercises/modules/mod.rs b/exercises/modules/mod.rs
new file mode 100644
index 00000000..35f96af5
--- /dev/null
+++ b/exercises/modules/mod.rs
@@ -0,0 +1,3 @@
+mod modules1;
+mod modules2;
+mod modules3;
diff --git a/exercises/move_semantics/mod.rs b/exercises/move_semantics/mod.rs
new file mode 100644
index 00000000..e8eecf0a
--- /dev/null
+++ b/exercises/move_semantics/mod.rs
@@ -0,0 +1,6 @@
+mod move_semantics1;
+mod move_semantics2;
+mod move_semantics3;
+mod move_semantics4;
+mod move_semantics5;
+mod move_semantics6;
diff --git a/exercises/move_semantics/move_semantics2.rs b/exercises/move_semantics/move_semantics2.rs
index df682899..9993bb8f 100644
--- a/exercises/move_semantics/move_semantics2.rs
+++ b/exercises/move_semantics/move_semantics2.rs
@@ -1,5 +1,5 @@
// move_semantics2.rs
-// Make me compile without changing line 13!
+// Make me compile without changing line 13 or moving line 10!
// Execute `rustlings hint move_semantics2` for hints :)
fn main() {
diff --git a/exercises/move_semantics/move_semantics5.rs b/exercises/move_semantics/move_semantics5.rs
index 1bd93e42..d9da5ffc 100644
--- a/exercises/move_semantics/move_semantics5.rs
+++ b/exercises/move_semantics/move_semantics5.rs
@@ -1,5 +1,5 @@
// move_semantics5.rs
-// Make me compile only be reordering the lines in `main()`, but without
+// Make me compile only by reordering the lines in `main()`, but without
// adding, changing or removing any of them.
// Execute `rustlings hint move_semantics5` for hints :)
diff --git a/exercises/move_semantics/move_semantics6.rs b/exercises/move_semantics/move_semantics6.rs
new file mode 100644
index 00000000..457e7ae7
--- /dev/null
+++ b/exercises/move_semantics/move_semantics6.rs
@@ -0,0 +1,25 @@
+// move_semantics6.rs
+// Make me compile! `rustlings hint move_semantics6` for hints
+// You can't change anything except adding or removing references
+
+// I AM NOT DONE
+
+fn main() {
+ let data = "Rust is great!".to_string();
+
+ get_char(data);
+
+ string_uppercase(&data);
+}
+
+// Should not take ownership
+fn get_char(data: String) -> char {
+ data.chars().last().unwrap()
+}
+
+// Should take ownership
+fn string_uppercase(mut data: &String) {
+ data = &data.to_uppercase();
+
+ println!("{}", data);
+}
diff --git a/exercises/option/README.md b/exercises/option/README.md
index a304bb44..89c00289 100644
--- a/exercises/option/README.md
+++ b/exercises/option/README.md
@@ -16,3 +16,5 @@ Option types are very common in Rust code, as they have a number of uses:
- [Option Enum Format](https://doc.rust-lang.org/stable/book/ch10-01-syntax.html#in-enum-definitions)
- [Option Module Documentation](https://doc.rust-lang.org/std/option/)
- [Option Enum Documentation](https://doc.rust-lang.org/std/option/enum.Option.html)
+- [if let](https://doc.rust-lang.org/rust-by-example/flow_control/if_let.html)
+- [while let](https://doc.rust-lang.org/rust-by-example/flow_control/while_let.html)
diff --git a/exercises/option/mod.rs b/exercises/option/mod.rs
new file mode 100644
index 00000000..b3cdb13d
--- /dev/null
+++ b/exercises/option/mod.rs
@@ -0,0 +1,3 @@
+mod option1;
+mod option2;
+mod option3;
diff --git a/exercises/option/option1.rs b/exercises/option/option1.rs
index 602ff1a9..17cf4f60 100644
--- a/exercises/option/option1.rs
+++ b/exercises/option/option1.rs
@@ -3,7 +3,7 @@
// I AM NOT DONE
-// you can modify anything EXCEPT for this function's sig
+// you can modify anything EXCEPT for this function's signature
fn print_number(maybe_number: Option) {
println!("printing: {}", maybe_number.unwrap());
}
diff --git a/exercises/primitive_types/mod.rs b/exercises/primitive_types/mod.rs
new file mode 100644
index 00000000..23355239
--- /dev/null
+++ b/exercises/primitive_types/mod.rs
@@ -0,0 +1,6 @@
+mod primitive_types1;
+mod primitive_types2;
+mod primitive_types3;
+mod primitive_types4;
+mod primitive_types5;
+mod primitive_types6;
diff --git a/exercises/quiz1.rs b/exercises/quiz1.rs
index 0e36a069..b904de1d 100644
--- a/exercises/quiz1.rs
+++ b/exercises/quiz1.rs
@@ -2,6 +2,7 @@
// This is a quiz for the following sections:
// - Variables
// - Functions
+// - 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
diff --git a/exercises/standard_library_types/iterators1.rs b/exercises/standard_library_types/iterators1.rs
index 4606ad35..5aa49b64 100644
--- a/exercises/standard_library_types/iterators1.rs
+++ b/exercises/standard_library_types/iterators1.rs
@@ -18,7 +18,7 @@ fn main () {
assert_eq!(my_iterable_fav_fruits.next(), Some(&"banana"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2
assert_eq!(my_iterable_fav_fruits.next(), Some(&"avocado"));
- assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 2.1
- assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 3
+ assert_eq!(my_iterable_fav_fruits.next(), Some(&"raspberry"));
+ assert_eq!(my_iterable_fav_fruits.next(), ???); // TODO: Step 4
}
diff --git a/exercises/standard_library_types/mod.rs b/exercises/standard_library_types/mod.rs
new file mode 100644
index 00000000..b03acb92
--- /dev/null
+++ b/exercises/standard_library_types/mod.rs
@@ -0,0 +1,7 @@
+mod arc1;
+mod box1;
+mod iterators1;
+mod iterators2;
+mod iterators3;
+mod iterators4;
+mod iterators5;
diff --git a/exercises/strings/mod.rs b/exercises/strings/mod.rs
new file mode 100644
index 00000000..b1b460bc
--- /dev/null
+++ b/exercises/strings/mod.rs
@@ -0,0 +1,2 @@
+mod strings1;
+mod strings2;
diff --git a/exercises/structs/mod.rs b/exercises/structs/mod.rs
new file mode 100644
index 00000000..214fed16
--- /dev/null
+++ b/exercises/structs/mod.rs
@@ -0,0 +1,3 @@
+mod structs1;
+mod structs2;
+mod structs3;
diff --git a/exercises/structs/structs3.rs b/exercises/structs/structs3.rs
index b1c79d2f..23f95b33 100644
--- a/exercises/structs/structs3.rs
+++ b/exercises/structs/structs3.rs
@@ -14,13 +14,14 @@ struct Package {
impl Package {
fn new(sender_country: String, recipient_country: String, weight_in_grams: i32) -> Package {
if weight_in_grams <= 0 {
+ personal
panic!("Weight is 0 or less.");
} else {
- return Package {
+ Package {
sender_country,
recipient_country,
weight_in_grams,
- };
+ }
}
}
diff --git a/exercises/tests/mod.rs b/exercises/tests/mod.rs
new file mode 100644
index 00000000..489541be
--- /dev/null
+++ b/exercises/tests/mod.rs
@@ -0,0 +1,3 @@
+mod tests1;
+mod tests2;
+mod tests3;
diff --git a/exercises/threads/mod.rs b/exercises/threads/mod.rs
new file mode 100644
index 00000000..24d54007
--- /dev/null
+++ b/exercises/threads/mod.rs
@@ -0,0 +1 @@
+mod threads1;
diff --git a/exercises/traits/mod.rs b/exercises/traits/mod.rs
new file mode 100644
index 00000000..6f0a9c3f
--- /dev/null
+++ b/exercises/traits/mod.rs
@@ -0,0 +1,2 @@
+mod traits1;
+mod traits2;
diff --git a/exercises/traits/traits1.rs b/exercises/traits/traits1.rs
index 2ef9e11b..15e08f24 100644
--- a/exercises/traits/traits1.rs
+++ b/exercises/traits/traits1.rs
@@ -29,12 +29,12 @@ mod tests {
use super::*;
#[test]
- fn is_FooBar() {
+ fn is_foo_bar() {
assert_eq!(String::from("Foo").append_bar(), String::from("FooBar"));
}
#[test]
- fn is_BarBar() {
+ fn is_bar_bar() {
assert_eq!(
String::from("").append_bar().append_bar(),
String::from("BarBar")
diff --git a/exercises/variables/mod.rs b/exercises/variables/mod.rs
new file mode 100644
index 00000000..a25f477e
--- /dev/null
+++ b/exercises/variables/mod.rs
@@ -0,0 +1,6 @@
+mod variables1;
+mod variables2;
+mod variables3;
+mod variables4;
+mod variables5;
+mod variables6;
diff --git a/exercises/variables/variables1.rs b/exercises/variables/variables1.rs
index db85e7e4..f41da792 100644
--- a/exercises/variables/variables1.rs
+++ b/exercises/variables/variables1.rs
@@ -1,10 +1,6 @@
// variables1.rs
-// Make me compile! Execute the command `rustlings hint variables1` if you want a hint :)
-
-// About this `I AM NOT DONE` thing:
-// We sometimes encourage you to keep trying things on a given exercise,
-// even after you already figured it out. If you got everything working and
-// feel ready for the next exercise, remove the `I AM NOT DONE` comment below.
+// Make me compile!
+// Execute the command `rustlings hint variables1` if you want a hint :)
fn main() {
let x = 5;
diff --git a/info.toml b/info.toml
index 21406630..56fa7ec5 100644
--- a/info.toml
+++ b/info.toml
@@ -1,3 +1,19 @@
+# INTRO
+
+[[exercises]]
+name = "intro1"
+path = "exercises/intro/intro1.rs"
+mode = "compile"
+hint = """
+Remove the I AM NOT DONE comment to move on to the next exercise."""
+
+[[exercises]]
+name = "intro2"
+path = "exercises/intro/intro2.rs"
+mode = "compile"
+hint = """
+Add an argument after the format string."""
+
# VARIABLES
[[exercises]]
@@ -114,8 +130,7 @@ path = "exercises/functions/functions5.rs"
mode = "compile"
hint = """
This is a really common error that can be fixed by removing one character.
-It happens because Rust distinguishes between expressions and statements: expressions return
-a value based on its operand, and statements simply return a () type which behaves just like `void` in C/C++ language.
+It happens because Rust distinguishes between expressions and statements: expressions return a value based on their operand(s), and statements simply return a () type which behaves just like `void` in C/C++ language.
We want to return a value of `i32` type from the `square` function, but it is returning a `()` type...
They are not the same. There are two solutions:
1. Add a `return` ahead of `num * num;`
@@ -222,6 +237,21 @@ in the book's section References and Borrowing':
https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html#mutable-references.
"""
+[[exercises]]
+name = "move_semantics6"
+path = "exercises/move_semantics/move_semantics6.rs"
+mode = "compile"
+hint = """
+To find the answer, you can consult the book section "References and Borrowing":
+https://doc.rust-lang.org/stable/book/ch04-02-references-and-borrowing.html
+The first problem is that `get_char` is taking ownership of the string.
+So `data` is moved and can't be used for `string_uppercase`
+`data` is moved to `get_char` first, meaning that `string_uppercase` cannot manipulate the data.
+Once you've fixed that, `string_uppercase`'s function signature will also need to be adjusted.
+Can you figure out how?
+
+Another hint: it has to do with the `&` character."""
+
# PRIMITIVE TYPES
[[exercises]]
@@ -364,7 +394,7 @@ mode = "compile"
hint = """
The delicious_snacks module is trying to present an external interface that is
different than its internal structure (the `fruits` and `veggies` modules and
-associated constants). Complete the `use` statemants to fit the uses in main and
+associated constants). Complete the `use` statements to fit the uses in main and
find the one keyword missing for both constants."""
[[exercises]]
@@ -460,7 +490,7 @@ name = "errors1"
path = "exercises/error_handling/errors1.rs"
mode = "test"
hint = """
-`Err` is one of the variants of `Result`, so what the 2nd test is saying
+`Ok` and `Err` are one of the variants of `Result`, so what the tests are saying
is that `generate_nametag_text` should return a `Result` instead of an
`Option`.
@@ -470,9 +500,7 @@ To make this change, you'll need to:
- change the body of the function to return `Ok(stuff)` where it currently
returns `Some(stuff)`
- change the body of the function to return `Err(error message)` where it
- currently returns `None`
- - change the first test to expect `Ok(stuff)` where it currently expects
- `Some(stuff)`."""
+ currently returns `None`"""
[[exercises]]
name = "errors2"
@@ -907,15 +935,15 @@ name = "clippy1"
path = "exercises/clippy/clippy1.rs"
mode = "clippy"
hint = """
-Not every floating point value can be represented exactly in binary values in
-memory. Take a look at the description of
-https://doc.rust-lang.org/stable/std/primitive.f32.html
-When using the binary compare operators with floating points you won't compare
-the floating point values but the binary representation in memory. This is
-usually not what you would like to do.
+Rust stores the highest precision version of any long or inifinite precision
+mathematical constants in the rust standard library.
+https://doc.rust-lang.org/stable/std/f32/consts/index.html
+
+We may be tempted to use our own approximations for certain mathematical constants,
+but clippy recognizes those imprecise mathematical constants as a source of
+potential error.
See the suggestions of the clippy warning in compile output and use the
-machine epsilon value...
-https://doc.rust-lang.org/stable/std/primitive.f32.html#associatedconstant.EPSILON"""
+appropriate replacement constant from std::f32::consts..."""
[[exercises]]
name = "clippy2"
diff --git a/install.sh b/install.sh
index e986e741..1d9cff27 100755
--- a/install.sh
+++ b/install.sh
@@ -1,4 +1,5 @@
#!/usr/bin/env bash
+set -euo pipefail
echo "Let's get you set up with Rustlings!"
@@ -12,6 +13,18 @@ else
exit 1
fi
+if [ -x "$(command -v cc)" ]
+then
+ echo "SUCCESS: cc is installed"
+else
+ echo "ERROR: cc does not seem to be installed."
+ echo "Please download (g)cc using your package manager."
+ echo "OSX: xcode-select --install"
+ echo "Deb: sudo apt install gcc"
+ echo "Yum: sudo yum -y install gcc"
+ exit 1
+fi
+
if [ -x "$(command -v rustc)" ]
then
echo "SUCCESS: Rust is installed"
@@ -88,8 +101,8 @@ function vercomp() {
RustVersion=$(rustc --version | cut -d " " -f 2)
MinRustVersion=1.39
-vercomp $RustVersion $MinRustVersion
-if [ $? -eq 2 ]
+vercomp "$RustVersion" $MinRustVersion || ec=$?
+if [ ${ec:-0} -eq 2 ]
then
echo "ERROR: Rust version is too old: $RustVersion - needs at least $MinRustVersion"
echo "Please update Rust with 'rustup update'"
@@ -100,9 +113,9 @@ fi
Path=${1:-rustlings/}
echo "Cloning Rustlings at $Path..."
-git clone -q https://github.com/rust-lang/rustlings $Path
+git clone -q https://github.com/rust-lang/rustlings "$Path"
-cd $Path
+cd "$Path"
Version=$(curl -s https://api.github.com/repos/rust-lang/rustlings/releases/latest | ${PY} -c "import json,sys;obj=json.load(sys.stdin);print(obj['tag_name']);")
CargoBin="${CARGO_HOME:-$HOME/.cargo}/bin"
diff --git a/src/exercise.rs b/src/exercise.rs
index ec694df9..6e49a9aa 100644
--- a/src/exercise.rs
+++ b/src/exercise.rs
@@ -154,7 +154,7 @@ path = "{}.rs""#,
Command::new("cargo")
.args(&["clippy", "--manifest-path", CLIPPY_CARGO_TOML_PATH])
.args(RUSTC_COLOR_ARGS)
- .args(&["--", "-D", "warnings"])
+ .args(&["--", "-D", "warnings","-D","clippy::float_cmp"])
.output()
}
}
@@ -217,8 +217,7 @@ path = "{}.rs""#,
let matched_line_index = source
.lines()
.enumerate()
- .filter_map(|(i, line)| if re.is_match(line) { Some(i) } else { None })
- .next()
+ .find_map(|(i, line)| if re.is_match(line) { Some(i) } else { None })
.expect("This should not happen at all");
let min_line = ((matched_line_index as i32) - (CONTEXT as i32)).max(0) as usize;
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 00000000..82c1e7e4
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,3 @@
+#[cfg(feature = "exercises")]
+#[path = "../exercises/mod.rs"]
+mod exercises;
diff --git a/src/main.rs b/src/main.rs
index 32e7bba2..e8591f7d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,7 +24,7 @@ mod run;
mod verify;
// In sync with crate version
-const VERSION: &str = "4.6.0";
+const VERSION: &str = "4.7.0";
#[derive(FromArgs, PartialEq, Debug)]
/// Rustlings is a collection of small exercises to get you used to writing and reading Rust code
@@ -108,15 +108,7 @@ fn main() {
}
if args.nested.is_none() {
- println!();
- println!(r#" welcome to... "#);
- println!(r#" _ _ _ "#);
- println!(r#" _ __ _ _ ___| |_| (_)_ __ __ _ ___ "#);
- println!(r#" | '__| | | / __| __| | | '_ \ / _` / __| "#);
- println!(r#" | | | |_| \__ \ |_| | | | | | (_| \__ \ "#);
- println!(r#" |_| \__,_|___/\__|_|_|_| |_|\__, |___/ "#);
- println!(r#" |___/ "#);
- println!();
+ println!("\n{}\n", WELCOME);
}
if !Path::new("info.toml").exists() {
@@ -140,8 +132,7 @@ fn main() {
let verbose = args.nocapture;
let command = args.nested.unwrap_or_else(|| {
- let text = fs::read_to_string("default_out.txt").unwrap();
- println!("{}", text);
+ println!("{}\n", DEFAULT_OUT);
std::process::exit(0);
});
match command {
@@ -164,9 +155,7 @@ 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 {
@@ -219,49 +208,13 @@ 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!();
- println!("+----------------------------------------------------+");
- println!("| You made it to the Fe-nish line! |");
- println!("+-------------------------- ------------------------+");
- println!(" \\/ ");
- println!(" ββ ββββββββ ββββββββ ββ ");
- println!(" ββββ ββ ββ ββ ββ ββ ββ ββββ ");
- println!(" ββββ ββ ββ ββ ββ ββ ββββ ");
- println!(" ββββββββββ ββ ββ ββ ββββββββ ");
- println!(" ββββββββ ββ ββββ ββ ββββ ββ ββββββββ ");
- println!(" ββββ ββ ββββ ββ ββββ ββββ ββββ ");
- println!(" ββ ββββββ ββββββ ββββββ ββ ");
- println!(" ββββββββββββββββββββββββββββββββββββββ ");
- println!(" ββββββββββββββββββββββββββββββββββ ");
- println!(" ββββββββββββββββββββββββββββββ ");
- println!(" ββ ββββββββββββββββββββββββββ ββ ");
- println!(" ββ ββββββββββββββββββββββββββ ββ ");
- println!(" ββ ββ ββββββββββββββββββ ββ ββ ");
- println!(" ββ ββ ββ ββ ββ ββ ");
- println!(" ββ ββ ββ ββ ");
- println!();
- println!("We hope you enjoyed learning about the various aspects of Rust!");
- println!(
- "If you noticed any issues, please don't hesitate to report them to our repo."
- );
- println!(
- "You can also contribute your own exercises to help the greater community!"
- );
- println!();
- println!("Before reporting an issue or contributing, please read our guidelines:");
- println!("https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md");
+ println!("{emoji} All exercises completed! {emoji}", emoji = Emoji("π", "β
"));
+ println!("\n{}\n", FENISH_LINE);
}
Ok(WatchStatus::Unfinished) => {
println!("We hope you're enjoying learning about Rust!");
@@ -271,10 +224,7 @@ 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 {
@@ -311,22 +261,16 @@ fn spawn_watch_shell(
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)
+ })
}
}
@@ -366,11 +310,7 @@ fn watch(exercises: &[Exercise], verbose: bool) -> notify::Result {
.iter()
.skip_while(|e| !filepath.ends_with(&e.path))
// .filter(|e| filepath.ends_with(&e.path))
- .chain(
- exercises
- .iter()
- .filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)),
- );
+ .chain(exercises.iter().filter(|e| !e.looks_done() && !filepath.ends_with(&e.path)));
clear_screen();
match verify(pending_exercises, verbose) {
Ok(_) => return Ok(WatchStatus::Finished),
@@ -404,3 +344,64 @@ fn rustc_exists() -> bool {
.map(|status| status.success())
.unwrap_or(false)
}
+
+const DEFAULT_OUT: &str = r#"Thanks for installing Rustlings!
+
+Is this your first time? Don't worry, Rustlings was made for beginners! We are
+going to teach you a lot of things about Rust, but before we can get
+started, here's a couple of notes about how Rustlings operates:
+
+1. The central concept behind Rustlings is that you solve exercises. These
+ exercises usually have some sort of syntax error in them, which will cause
+ them to fail compilation or testing. Sometimes there's a logic error instead
+ of a syntax error. No matter what error, it's your job to find it and fix it!
+ You'll know when you fixed it because then, the exercise will compile and
+ Rustlings will be able to move on to the next exercise.
+2. If you run Rustlings in watch mode (which we recommend), it'll automatically
+ start with the first exercise. Don't get confused by an error message popping
+ up as soon as you run Rustlings! This is part of the exercise that you're
+ supposed to solve, so open the exercise file in an editor and start your
+ detective work!
+3. If you're stuck on an exercise, there is a helpful hint you can view by typing
+ 'hint' (in watch mode), or running `rustlings hint exercise_name`.
+4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
+ (https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
+ and sometimes, other learners do too so you can help each other out!
+
+Got all that? Great! To get started, run `rustlings watch` in order to get the first
+exercise. Make sure to have your editor open!"#;
+
+const FENISH_LINE: &str = r#"+----------------------------------------------------+
+| You made it to the Fe-nish line! |
++-------------------------- ------------------------+
+ \\/
+ ββ ββββββββ ββββββββ ββ
+ ββββ ββ ββ ββ ββ ββ ββ ββββ
+ ββββ ββ ββ ββ ββ ββ ββββ
+ ββββββββββ ββ ββ ββ ββββββββ
+ ββββββββ ββ ββββ ββ ββββ ββ ββββββββ
+ ββββ ββ ββββ ββ ββββ ββββ ββββ
+ ββ ββββββ ββββββ ββββββ ββ
+ ββββββββββββββββββββββββββββββββββββββ
+ ββββββββββββββββββββββββββββββββββ
+ ββββββββββββββββββββββββββββββ
+ ββ ββββββββββββββββββββββββββ ββ
+ ββ ββββββββββββββββββββββββββ ββ
+ ββ ββ ββββββββββββββββββ ββ ββ
+ ββ ββ ββ ββ ββ ββ
+ ββ ββ ββ ββ
+
+We hope you enjoyed learning about the various aspects of Rust!
+If you noticed any issues, please don't hesitate to report them to our repo.
+You can also contribute your own exercises to help the greater community!
+
+Before reporting an issue or contributing, please read our guidelines:
+https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md"#;
+
+const WELCOME: &str = r#" welcome to...
+ _ _ _
+ _ __ _ _ ___| |_| (_)_ __ __ _ ___
+ | '__| | | / __| __| | | '_ \ / _` / __|
+ | | | |_| \__ \ |_| | | | | | (_| \__ \
+ |_| \__,_|___/\__|_|_|_| |_|\__, |___/
+ |___/"#;
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index be9af965..fc46b983 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -125,6 +125,9 @@ fn get_hint_for_single_test() {
fn all_exercises_require_confirmation() {
for exercise in glob("exercises/**/*.rs").unwrap() {
let path = exercise.unwrap();
+ if path.file_name().unwrap() == "mod.rs" {
+ continue
+ }
let source = {
let mut file = File::open(&path).unwrap();
let mut s = String::new();