-
-
-
-
-
-
-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 a199e4de..11502ed1 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,72 @@
+
+
+## 6.0.0 (2024-07-03)
+
+This release is the result of a complete rewrite to deliver a ton of new features and improvements ✨
+The most important changes are highlighted below.
+
+### Installation
+
+The installation has been simplified a lot!
+To install Rustlings after installing Rust, all what you need to do now is running the following command:
+
+```bash
+cargo install rustlings
+```
+
+Yes, this means that Rustlings is now on [crates.io](https://crates.io/crates/rustlings) 🎉
+
+You can read about the motivations of this change in [this issue](https://github.com/rust-lang/rustlings/issues/1919).
+
+### UI/UX
+
+- The UI is now responsive when the terminal is resized.
+- The progress bar was moved to the bottom so that you can always see your progress and the current exercise to work on.
+- The current exercise path is now a terminal link. It will open the exercise file in your default editor when you click on it.
+- A small prompt is now always shown at the bottom. It allows you to choose an action by entering a character. For example, entering `h` will show you the hint of the current exercise.
+- The comment "I AM NOT DONE!" doesn't exist anymore. Instead of needing to remove it to go to the next exercise, you need to enter `n` in the terminal.
+
+### List mode
+
+A list mode was added using [Ratatui](https://ratatui.rs).
+You can enter it by entering `l` in the watch mode.
+It offers the following features:
+
+- Browse all exercises and see their state (pending/done).
+- Filter exercises based on their state (pending/done).
+- Continue at another exercise. This allows you to skip some exercises or go back to previous ones.
+- Reset an exercise so you can start over and revert your changes.
+
+### Solutions
+
+After finishing an exercise, a solution file will be available and Rustlings will show you its path in green.
+This allows you to compare your solution with an idiomatic solution and maybe learn about other ways to solve a problem.
+
+While writing the solutions, all exercises have been polished 🌟
+For example, every exercise now contains `TODO` comments to highlight what the user needs to change and where.
+
+### LSP support out of the box
+
+Instead of creating a `project.json` file using `rustlings lsp`, Rustlings now works with a `Cargo.toml` file out of the box.
+No actions are needed to activate the language server `rust-analyzer`.
+
+This should avoid issues related to the language server or to running exercises, especially the ones with Clippy.
+
+### Clippy
+
+Clippy lints are now shown on all exercises, not only the Clippy exercises 📎
+Make Clippy your friend from early on 🥰
+
+### Third party exercises
+
+Rustlings now supports third-party exercises!
+
+Do you want to create your own set of Rustlings exercises to focus on some specific topic?
+Or do you want to translate the original Rustlings exercises?
+Then follow the link to the guide about [third-party exercises](THIRD_PARTY_EXERCISES.md)!
+
+
## 5.6.1 (2023-09-18)
#### Changed
@@ -15,6 +83,7 @@
- `enums3`: Fixed formatting with `rustfmt`.
+
## 5.6.0 (2023-09-04)
#### Added
@@ -30,7 +99,7 @@
- Swapped the order of threads and smart pointer exercises.
- Rewrote the CLI to use `clap` - it's matured much since we switched to `argh` :)
- `structs3`: Switched from i32 to u32.
-- `move_semantics`: Switched 1-4 to tests, and rewrote them to be way simpler, while still teaching about the same
+- `move_semantics`: Switched 1-4 to tests, and rewrote them to be way simpler, while still teaching about the same
concepts.
#### Fixed
@@ -55,6 +124,7 @@
- Improved CI workflows, we're now testing on multiple platforms at once.
+
## 5.5.1 (2023-05-17)
#### Fixed
@@ -62,6 +132,7 @@
- Reverted `rust-project.json` path generation due to an upstream `rust-analyzer` fix.
+
## 5.5.0 (2023-05-17)
#### Added
@@ -97,6 +168,7 @@
- Split quick installation section into two code blocks
+
## 5.4.1 (2023-03-10)
#### Changed
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 4fc7fb79..95605f70 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,129 +1,61 @@
-## Contributing to Rustlings
+# Contributing to Rustlings
-First off, thanks for taking the time to contribute!! ❤️
+First off, thanks for taking the time to contribute! ❤️
-### Quick Reference
+## Quick Reference
-I want to...
+I want to …
-_add an exercise! ➡️ [read this](#addex) and then [open a Pull Request](#prs)_
+- _report a bug!_ ➡️ [open an issue](#issues)
+- _fix a bug!_ ➡️ [open a pull request](#pull-requests)
+- _implement a new feature!_ ➡️ [open an issue to discuss it first, then a pull request](#issues)
+- _add an exercise!_ ➡️ [read this](#adding-an-exercise)
+- _update an outdated exercise!_ ➡️ [open a pull request](#pull-requests)
-_update an outdated exercise! ➡️ [open a Pull Request](#prs)_
-
-_report a bug! ➡️ [open an Issue](#issues)_
-
-_fix a bug! ➡️ [open a Pull Request](#prs)_
-
-_implement a new feature! ➡️ [open an Issue to discuss it first, then a Pull Request](#issues)_
-
-
-### Working on the source code
-
-`rustlings` is basically a glorified `rustc` wrapper. Therefore the source code
-isn't really that complicated since the bulk of the work is done by `rustc`.
-
-
-### Adding an exercise
-
-The first step is to add the exercise! Name the file `exercises/yourTopic/yourTopicN.rs`, make sure to
-put in some helpful links, and link to sections of the book in `exercises/yourTopic/README.md`.
-
-Next make sure it runs with `rustlings`. The exercise metadata is stored in `info.toml`, under the `exercises` array. The order of the `exercises` array determines the order the exercises are run by `rustlings verify` and `rustlings watch`.
-
-Add the metadata for your exercise in the correct order in the `exercises` array. If you are unsure of the correct ordering, add it at the bottom and ask in your pull request. The exercise metadata should contain the following:
-```diff
- ...
-+ [[exercises]]
-+ name = "yourTopicN"
-+ path = "exercises/yourTopic/yourTopicN.rs"
-+ mode = "compile"
-+ hint = """
-+ Some kind of useful hint for your exercise."""
- ...
-```
-
-The `mode` attribute decides whether Rustlings will only compile your exercise, or compile and test it. If you have tests to verify in your exercise, choose `test`, otherwise `compile`. If you're working on a Clippy exercise, use `mode = "clippy"`.
-
-That's all! Feel free to put up a pull request.
-
-
-### Issues
+## Issues
You can open an issue [here](https://github.com/rust-lang/rustlings/issues/new).
If you're reporting a bug, please include the output of the following commands:
-- `rustc --version`
+- `cargo --version`
- `rustlings --version`
- `ls -la`
- Your OS name and version
-
-### Pull Requests
+## Pull Requests
-Opening a pull request is as easy as forking the repository and committing your
-changes. There's a couple of things to watch out for:
+You are welcome to open a pull request, but unless it is small and trivial, **please open an issue to discuss your idea first** 🙏🏼
-#### Write correct commit messages
+Opening a pull request is as easy as forking the repository and committing your changes.
+If you need any help with it or face any Git related problems, don't hesitate to ask for help 🤗
-We follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/)
-specification.
-This means that you have to format your commit messages in a specific way. Say
-you're working on adding a new exercise called `foobar1.rs`. You could write
-the following commit message:
+It may take time to review your pull request.
+Please be patient 😇
-```
-feat: add foobar1.rs exercise
+When updating an exercise, check if its solution needs to be updated.
+
+## Adding An Exercise
+
+- Name the file `exercises/yourTopic/yourTopicN.rs`.
+- Make sure to put in some helpful links, and link to sections of The Book in `exercises/yourTopic/README.md`.
+- In the exercise, add a `// TODO: …` comment where user changes are required.
+- Add a solution at `solutions/yourTopic/yourTopicN.rs` with comments explaining it.
+- Add the [metadata for your exercise](#exercise-metadata) in the `rustlings-macros/info.toml` file.
+- Make sure your exercise runs with `rustlings run yourTopicN`.
+- [Open a pull request](#pull-requests).
+
+### Exercise Metadata
+
+The exercise metadata should contain the following:
+
+```toml
+[[exercises]]
+name = "yourTopicN"
+dir = "yourTopic"
+hint = """
+A useful (multi-line) hint for your exercise.
+Include links to a section in The Book or a documentation page."""
```
-If you're just fixing a bug, please use the `fix` type:
-
-```
-fix(verify): make sure verify doesn't self-destruct
-```
-
-The scope within the brackets is optional, but should be any of these:
-
-- `installation` (for the installation script)
-- `cli` (for general CLI changes)
-- `verify` (for the verification source file)
-- `watch` (for the watch functionality source)
-- `run` (for the run functionality source)
-- `EXERCISENAME` (if you're changing a specific exercise, or set of exercises,
- substitute them here)
-
-When the commit also happens to close an existing issue, link it in the message
-body:
-
-```
-fix: update foobar
-
-closes #101029908
-```
-
-If you're doing simple changes, like updating a book link, use `chore`:
-
-```
-chore: update exercise1.rs book link
-```
-
-If you're updating documentation, use `docs`:
-
-```
-docs: add more information to Readme
-```
-
-If, and only if, you're absolutely sure you want to make a breaking change
-(please discuss this beforehand!), add an exclamation mark to the type and
-explain the breaking change in the message body:
-
-```
-fix!: completely change verification
-
-BREAKING CHANGE: This has to be done because lorem ipsum dolor
-```
-
-#### Pull Request Workflow
-
-Once you open a Pull Request, it may be reviewed or labeled (or both) until
-the maintainers accept your change. Please be patient, it may take some time
-for this to happen!
+If your exercise doesn't contain any test, add `test = false` to the exercise metadata.
+But adding tests is recommended.
diff --git a/Cargo.lock b/Cargo.lock
index 3d0b16b2..f5908cc4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,18 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
[[package]]
name = "aho-corasick"
version = "1.1.3"
@@ -11,6 +23,12 @@ dependencies = [
"memchr",
]
+[[package]]
+name = "allocator-api2"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
+
[[package]]
name = "anstream"
version = "0.6.14"
@@ -110,6 +128,21 @@ dependencies = [
"serde",
]
+[[package]]
+name = "cassowary"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53"
+
+[[package]]
+name = "castaway"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a17ed5635fc8536268e5d4de1e22e81ac34419e5f052d4d51f4e01dcc263fcc"
+dependencies = [
+ "rustversion",
+]
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -118,9 +151,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
-version = "4.5.7"
+version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5db83dced34638ad474f39f250d7fea9598bdd239eaced1bdf45d597da0f433f"
+checksum = "84b3edb18336f4df585bc9aa31dd99c036dfa5dc5e9a2939a722a188f3a8970d"
dependencies = [
"clap_builder",
"clap_derive",
@@ -128,9 +161,9 @@ dependencies = [
[[package]]
name = "clap_builder"
-version = "4.5.7"
+version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7e204572485eb3fbf28f871612191521df159bc3e15a9f5064c66dba3a8c05f"
+checksum = "c1c09dd5ada6c6c78075d6fd0da3f90d8080651e2d6cc8eb2f1aaa4034ced708"
dependencies = [
"anstream",
"anstyle",
@@ -140,9 +173,9 @@ dependencies = [
[[package]]
name = "clap_derive"
-version = "4.5.5"
+version = "4.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c780290ccf4fb26629baa7a1081e68ced113f1d3ec302fa5948f1c381ebf06c6"
+checksum = "2bac35c6dafb060fd4d275d9a4ffae97917c13a6327903a8be2153cd964f7085"
dependencies = [
"heck",
"proc-macro2",
@@ -163,16 +196,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
[[package]]
-name = "console"
-version = "0.15.8"
+name = "compact_str"
+version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb"
+checksum = "f86b9c4c00838774a6d902ef931eff7470720c51d90c2e32cfe15dc304737b3f"
dependencies = [
- "encode_unicode",
- "lazy_static",
- "libc",
- "unicode-width",
- "windows-sys 0.52.0",
+ "castaway",
+ "cfg-if",
+ "itoa",
+ "ryu",
+ "static_assertions",
]
[[package]]
@@ -190,6 +223,31 @@ version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+[[package]]
+name = "crossterm"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df"
+dependencies = [
+ "bitflags 2.6.0",
+ "crossterm_winapi",
+ "libc",
+ "mio",
+ "parking_lot",
+ "signal-hook",
+ "signal-hook-mio",
+ "winapi",
+]
+
+[[package]]
+name = "crossterm_winapi"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
+dependencies = [
+ "winapi",
+]
+
[[package]]
name = "difflib"
version = "0.4.0"
@@ -208,28 +266,12 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
-[[package]]
-name = "encode_unicode"
-version = "0.3.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
-
[[package]]
name = "equivalent"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-[[package]]
-name = "errno"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
-dependencies = [
- "libc",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "filetime"
version = "0.2.23"
@@ -238,7 +280,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.4.1",
"windows-sys 0.52.0",
]
@@ -260,17 +302,15 @@ dependencies = [
"libc",
]
-[[package]]
-name = "glob"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
-
[[package]]
name = "hashbrown"
version = "0.14.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+dependencies = [
+ "ahash",
+ "allocator-api2",
+]
[[package]]
name = "heck"
@@ -278,15 +318,6 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
-[[package]]
-name = "home"
-version = "0.5.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
-dependencies = [
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "indexmap"
version = "2.2.6"
@@ -297,19 +328,6 @@ dependencies = [
"hashbrown",
]
-[[package]]
-name = "indicatif"
-version = "0.17.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3"
-dependencies = [
- "console",
- "instant",
- "number_prefix",
- "portable-atomic",
- "unicode-width",
-]
-
[[package]]
name = "inotify"
version = "0.9.6"
@@ -330,21 +348,30 @@ dependencies = [
"libc",
]
-[[package]]
-name = "instant"
-version = "0.1.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222"
-dependencies = [
- "cfg-if",
-]
-
[[package]]
name = "is_terminal_polyfill"
version = "1.70.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
+[[package]]
+name = "itertools"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itertools"
+version = "0.13.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186"
+dependencies = [
+ "either",
+]
+
[[package]]
name = "itoa"
version = "1.0.11"
@@ -371,12 +398,6 @@ dependencies = [
"libc",
]
-[[package]]
-name = "lazy_static"
-version = "1.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
-
[[package]]
name = "libc"
version = "0.2.155"
@@ -384,16 +405,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
[[package]]
-name = "linux-raw-sys"
-version = "0.4.14"
+name = "lock_api"
+version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
[[package]]
name = "log"
-version = "0.4.21"
+version = "0.4.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
+
+[[package]]
+name = "lru"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3262e75e648fce39813cb56ac41f3c3e3f65217ebf3844d818d1f9398cfb0dc"
+dependencies = [
+ "hashbrown",
+]
[[package]]
name = "memchr"
@@ -444,7 +478,6 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d40b221972a1fc5ef4d858a2f671fb34c75983eb385463dff3780eeff6a9d43"
dependencies = [
- "crossbeam-channel",
"log",
"notify",
]
@@ -459,16 +492,49 @@ dependencies = [
]
[[package]]
-name = "number_prefix"
-version = "0.4.0"
+name = "once_cell"
+version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
[[package]]
-name = "portable-atomic"
-version = "1.6.0"
+name = "os_pipe"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
+checksum = "29d73ba8daf8fac13b0501d1abeddcfe21ba7401ada61a819144b6c2a4f32209"
+dependencies = [
+ "libc",
+ "windows-sys 0.52.0",
+]
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall 0.5.2",
+ "smallvec",
+ "windows-targets 0.52.5",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
[[package]]
name = "predicates"
@@ -518,6 +584,27 @@ dependencies = [
"proc-macro2",
]
+[[package]]
+name = "ratatui"
+version = "0.27.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d16546c5b5962abf8ce6e2881e722b4e0ae3b6f1a08a26ae3573c55853ca68d3"
+dependencies = [
+ "bitflags 2.6.0",
+ "cassowary",
+ "compact_str",
+ "crossterm",
+ "itertools 0.13.0",
+ "lru",
+ "paste",
+ "stability",
+ "strum",
+ "strum_macros",
+ "unicode-segmentation",
+ "unicode-truncate",
+ "unicode-width",
+]
+
[[package]]
name = "redox_syscall"
version = "0.4.1"
@@ -527,6 +614,15 @@ dependencies = [
"bitflags 1.3.2",
]
+[[package]]
+name = "redox_syscall"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
+dependencies = [
+ "bitflags 2.6.0",
+]
+
[[package]]
name = "regex"
version = "1.10.5"
@@ -556,39 +652,40 @@ version = "0.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
-[[package]]
-name = "rustix"
-version = "0.38.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
-dependencies = [
- "bitflags 2.6.0",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "rustlings"
-version = "5.6.1"
+version = "6.0.0-beta.10"
dependencies = [
"anyhow",
"assert_cmd",
"clap",
- "console",
- "glob",
- "indicatif",
+ "crossterm",
+ "hashbrown",
"notify-debouncer-mini",
+ "os_pipe",
"predicates",
+ "ratatui",
+ "rustlings-macros",
"serde",
"serde_json",
- "shlex",
"toml_edit",
- "which",
- "winnow",
]
+[[package]]
+name = "rustlings-macros"
+version = "6.0.0-beta.10"
+dependencies = [
+ "quote",
+ "serde",
+ "toml_edit",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+
[[package]]
name = "ryu"
version = "1.0.18"
@@ -604,6 +701,12 @@ dependencies = [
"winapi-util",
]
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
[[package]]
name = "serde"
version = "1.0.203"
@@ -626,9 +729,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.118"
+version = "1.0.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d947f6b3163d8857ea16c4fa0dd4840d52f3041039a85decd46867eb1abef2e4"
+checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5"
dependencies = [
"itoa",
"ryu",
@@ -645,10 +748,56 @@ dependencies = [
]
[[package]]
-name = "shlex"
-version = "1.3.0"
+name = "signal-hook"
+version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
+checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
+dependencies = [
+ "libc",
+ "signal-hook-registry",
+]
+
+[[package]]
+name = "signal-hook-mio"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af"
+dependencies = [
+ "libc",
+ "mio",
+ "signal-hook",
+]
+
+[[package]]
+name = "signal-hook-registry"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "stability"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ff9eaf853dec4c8802325d8b6d3dffa86cc707fd7a1a4cdbf416e13b061787a"
+dependencies = [
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "strsim"
@@ -656,6 +805,28 @@ version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+[[package]]
+name = "strum"
+version = "0.26.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06"
+dependencies = [
+ "strum_macros",
+]
+
+[[package]]
+name = "strum_macros"
+version = "0.26.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be"
+dependencies = [
+ "heck",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn",
+]
+
[[package]]
name = "syn"
version = "2.0.68"
@@ -701,6 +872,22 @@ version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "unicode-truncate"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a5fbabedabe362c618c714dbefda9927b5afc8e2a8102f47f081089a9019226"
+dependencies = [
+ "itertools 0.12.1",
+ "unicode-width",
+]
+
[[package]]
name = "unicode-width"
version = "0.1.13"
@@ -713,6 +900,12 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
[[package]]
name = "wait-timeout"
version = "0.2.0"
@@ -739,17 +932,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
[[package]]
-name = "which"
-version = "6.0.1"
+name = "winapi"
+version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8211e4f58a2b2805adfbefbc07bab82958fc91e3836339b1ab7ae32465dce0d7"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
- "either",
- "home",
- "rustix",
- "winsafe",
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
]
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
[[package]]
name = "winapi-util"
version = "0.1.8"
@@ -759,6 +956,12 @@ dependencies = [
"windows-sys 0.52.0",
]
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
[[package]]
name = "windows-sys"
version = "0.48.0"
@@ -908,7 +1111,21 @@ dependencies = [
]
[[package]]
-name = "winsafe"
-version = "0.0.19"
+name = "zerocopy"
+version = "0.7.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
+checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
diff --git a/Cargo.toml b/Cargo.toml
index 44409fcd..3455e2b4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,31 +1,72 @@
+[workspace]
+resolver = "2"
+exclude = [
+ "tests/fixture/failure",
+ "tests/fixture/state",
+ "tests/fixture/success",
+ "dev",
+]
+
+[workspace.package]
+version = "6.0.0-beta.10"
+authors = [
+ "Liv ",
+ "Mo Bitar ",
+ # Alumni
+ "Carol (Nichols || Goulding) ",
+]
+repository = "https://github.com/rust-lang/rustlings"
+license = "MIT"
+edition = "2021"
+
+[workspace.dependencies]
+serde = { version = "1.0.203", features = ["derive"] }
+toml_edit = { version = "0.22.14", default-features = false, features = ["parse", "serde"] }
+
[package]
name = "rustlings"
description = "Small exercises to get you used to reading and writing Rust code!"
-version = "5.6.1"
-authors = [
- "Liv ",
- "Carol (Nichols || Goulding) ",
+version.workspace = true
+authors.workspace = true
+repository.workspace = true
+license.workspace = true
+edition.workspace = true
+keywords = [
+ "exercise",
+ "learning",
+]
+include = [
+ "/src/",
+ "/exercises/",
+ "/solutions/",
+ # A symlink to be able to include `dev/Cargo.toml` although `dev` is excluded.
+ "/dev-Cargo.toml",
+ "/README.md",
+ "/LICENSE",
]
-edition = "2021"
[dependencies]
anyhow = "1.0.86"
-clap = { version = "4.5.7", features = ["derive"] }
-console = "0.15.8"
-indicatif = "0.17.8"
-notify-debouncer-mini = "0.4.1"
-serde_json = "1.0.118"
-serde = { version = "1.0.203", features = ["derive"] }
-shlex = "1.3.0"
-toml_edit = { version = "0.22.14", default-features = false, features = ["parse", "serde"] }
-which = "6.0.1"
-winnow = "0.6.13"
-
-[[bin]]
-name = "rustlings"
-path = "src/main.rs"
+clap = { version = "4.5.8", features = ["derive"] }
+crossterm = "0.27.0"
+hashbrown = "0.14.5"
+notify-debouncer-mini = { version = "0.4.1", default-features = false }
+os_pipe = "1.2.0"
+ratatui = { version = "0.27.0", default-features = false, features = ["crossterm"] }
+rustlings-macros = { path = "rustlings-macros", version = "=6.0.0-beta.10" }
+serde_json = "1.0.120"
+serde.workspace = true
+toml_edit.workspace = true
[dev-dependencies]
assert_cmd = "2.0.14"
-glob = "0.3.0"
predicates = "3.1.0"
+
+[profile.release]
+panic = "abort"
+
+[profile.dev]
+panic = "abort"
+
+[package.metadata.release]
+pre-release-hook = ["./release-hook.sh"]
diff --git a/README.md b/README.md
index 821d76cd..373b9c79 100644
--- a/README.md
+++ b/README.md
@@ -1,178 +1,143 @@
-# rustlings 🦀❤️
+# 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!
+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!
-Alternatively, for a first-time Rust learner, there are several other resources:
+It is recommended to do the Rustlings exercises in parallel to reading [the official Rust book](https://doc.rust-lang.org/book/), the most comprehensive resource for learning Rust 📚️
-- [The Book](https://doc.rust-lang.org/book/index.html) - The most comprehensive resource for learning Rust, but a bit theoretical sometimes. You will be using this along with Rustlings!
-- [Rust By Example](https://doc.rust-lang.org/rust-by-example/index.html) - Learn Rust by solving little exercises! It's almost like `rustlings`, but online
+[Rust By Example](https://doc.rust-lang.org/rust-by-example/) is another recommended resource that you might find helpful.
+It contains code examples and exercises similar to Rustlings, but online.
## 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`._
+### Installing Rust
-You will need to have Rust installed. You can get it by visiting . This'll also install Cargo, Rust's package/project manager.
+Before installing Rustlings, you need to have _Rust installed_.
+Visit [www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) for further instructions on installing Rust.
+This'll also install _Cargo_, Rust's package/project manager.
-## MacOS/Linux
+> 🐧 If you're on Linux, make sure you've installed `gcc` (for a linker).
+>
+> Deb: `sudo apt install gcc`.
+> Dnf: `sudo dnf install gcc`.
-Just run:
+> 🍎 If you're on MacOS, make sure you've installed Xcode and its developer tools by running `xcode-select --install`.
+
+### Installing Rustlings
+
+The following command will download and compile Rustlings:
```bash
-curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash
+cargo install rustlings
```
-Or if you want it to be installed to a different path:
+
+If the installation fails… (click to expand)
+
+- Make sure you have the latest Rust version by running `rustup update`
+- Try adding the `--locked` flag: `cargo install rustlings --locked`
+- Otherwise, please [report the issue](https://github.com/rust-lang/rustlings/issues/new)
+
+
+
+### Initialization
+
+After installing Rustlings, run the following command to initialize the `rustlings/` directory:
```bash
-curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash -s mypath/
+rustlings init
```
-This will install Rustlings and give you access to the `rustlings` command. Run it to get started!
-
-### Nix
-
-Basically: Clone the repository at the latest tag, finally run `nix develop` or `nix-shell`.
+Now, go into the newly initialized directory and launch Rustlings for further instructions on getting started with the exercises:
```bash
-# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1)
-git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings
-cd rustlings
-# if nix version > 2.3
-nix develop
-# if nix version <= 2.3
-nix-shell
+cd rustlings/
+rustlings
```
-## Windows
+## Working environment
-In PowerShell (Run as Administrator), set `ExecutionPolicy` to `RemoteSigned`:
+### Editor
-```ps1
-Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
-```
+Our general recommendation is [VS Code](https://code.visualstudio.com/) with the [rust-analyzer plugin](https://marketplace.visualstudio.com/items?itemName=rust-lang.rust-analyzer).
+But any editor that supports [rust-analyzer](https://rust-analyzer.github.io/) should be enough for working on the exercises.
-Then, you can run:
+### Terminal
-```ps1
-Start-BitsTransfer -Source https://raw.githubusercontent.com/rust-lang/rustlings/main/install.ps1 -Destination $env:TMP/install_rustlings.ps1; Unblock-File $env:TMP/install_rustlings.ps1; Invoke-Expression $env:TMP/install_rustlings.ps1
-```
+While working with Rustlings, please use a modern terminal for the best user experience.
+The default terminal on Linux and Mac should be sufficient.
+On Windows, we recommend the [Windows Terminal](https://aka.ms/terminal).
-To install Rustlings. Same as on MacOS/Linux, you will have access to the `rustlings` command after it. Keep in mind that this works best in PowerShell, and any other terminals may give you errors.
-
-If you get a permission denied message, you might have to exclude the directory where you cloned Rustlings in your antivirus.
-
-## Browser
-
-[![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/rust-lang/rustlings)
-
-[![Open Rustlings On Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new/?repo=rust-lang%2Frustlings&ref=main)
-
-## Manually
-
-Basically: Clone the repository at the latest tag, run `cargo install --locked --path .`.
-
-```bash
-# find out the latest version at https://github.com/rust-lang/rustlings/releases/latest (on edit 5.6.1)
-git clone -b 5.6.1 --depth 1 https://github.com/rust-lang/rustlings
-cd rustlings
-cargo install --locked --force --path .
-```
-
-If there are installation errors, ensure that your toolchain is up to date. For the latest, run:
-
-```bash
-rustup update
-```
-
-Then, same as above, run `rustlings` to get started.
+If you use VS Code, the builtin terminal should also be fine.
## Doing exercises
-The exercises are sorted by topic and can be found in the subdirectory `rustlings/exercises/`. For every topic there is an additional README file with some resources to get you started on the topic. We really recommend that you have a look at them before you start.
+The exercises are sorted by topic and can be found in the subdirectory `exercises/`.
+For every topic, there is an additional `README.md` file with some resources to get you started on the topic.
+We highly recommend that you have a look at them before you start 📚️
-The task is simple. Most exercises contain an error that keeps them from compiling, and it's up to you to fix it! Some exercises are also run as tests, but rustlings handles them all the same. To run the exercises in the recommended order, execute:
+Most exercises contain an error that keeps them from compiling, and it's up to you to fix it!
+Some exercises contain tests that need to pass for the exercise to be done ✅
-```bash
-rustlings watch
-```
+Search for `TODO` and `todo!()` to find out what you need to change.
+Ask for hints by entering `h` in the _watch mode_ 💡
-This will try to verify the completion of every exercise in a predetermined order (what we think is best for newcomers). It will also rerun automatically every time you change a file in the `exercises/` directory. If you want to only run it once, you can use:
+### Watch Mode
-```bash
-rustlings verify
-```
+After [initialization](#initialization), Rustlings can be launched by simply running the command `rustlings`.
-This will do the same as watch, but it'll quit after running.
+This will start the _watch mode_ which walks you through the exercises in a predefined order (what we think is best for newcomers).
+It will rerun the current exercise automatically every time you change the exercise's file in the `exercises/` directory.
-In case you want to go by your own order, or want to only verify a single exercise, you can run:
+
+If detecting file changes in the exercises/ directory fails… (click to expand)
-```bash
-rustlings run myExercise1
-```
+> You can add the **`--manual-run`** flag (`rustlings --manual-run`) to manually rerun the current exercise by entering `r` in the watch mode.
+>
+> Please [report the issue](https://github.com/rust-lang/rustlings/issues/new) with some information about your operating system and whether you run Rustlings in a container or virtual machine (e.g. WSL).
-Or simply use the following command to run the next unsolved exercise in the course:
+
-```bash
-rustlings run next
-```
+### Exercise List
-In case you get stuck, you can run the following command to get a hint for your
-exercise:
+In the [watch mode](#watch-mode) (after launching `rustlings`), you can enter `l` to open the interactive exercise list.
-```bash
-rustlings hint myExercise1
-```
+The list allows you to…
-You can also get the hint for the next unsolved exercise with the following command:
+- See the status of all exercises (done or pending)
+- `c`: Continue at another exercise (temporarily skip some exercises or go back to a previous one)
+- `r`: Reset status and file of an exercise (you need to _reload/reopen_ its file in your editor afterwards)
-```bash
-rustlings hint next
-```
-
-To check your progress, you can run the following command:
-
-```bash
-rustlings list
-```
-
-## Testing yourself
-
-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`
-
-Run the command `rustlings lsp` which will generate a `rust-project.json` at the root of the project, this allows [rust-analyzer](https://rust-analyzer.github.io/) to parse each exercise.
+See the footer of the list for all possible keys.
## 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.
+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.
+
+## Third-Party Exercises
+
+Do you want to create your own set of Rustlings exercises to focus on some specific topic?
+Or do you want to translate the original Rustlings exercises?
+Then follow the link to the guide about [third-party exercises](THIRD_PARTY_EXERCISES.md)!
## Uninstalling Rustlings
-If you want to remove Rustlings from your system, there are two steps. First, you'll need to remove the exercises folder that the install script created
-for you:
-
-```bash
-rm -rf rustlings # or your custom folder name, if you chose and or renamed it
-```
-
-Second, run `cargo uninstall` to remove the `rustlings` binary:
+If you want to remove Rustlings from your system, run the following command:
```bash
cargo uninstall rustlings
```
-Now you should be done!
-
## Contributing
-See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md).
+See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md) 🔗
## Contributors ✨
-Thanks goes to the wonderful people listed in [AUTHORS.md](https://github.com/rust-lang/rustlings/blob/main/AUTHORS.md) 🎉
+Thanks to [all the wonderful contributors](https://github.com/rust-lang/rustlings/graphs/contributors) 🎉
diff --git a/THIRD_PARTY_EXERCISES.md b/THIRD_PARTY_EXERCISES.md
new file mode 100644
index 00000000..5c066941
--- /dev/null
+++ b/THIRD_PARTY_EXERCISES.md
@@ -0,0 +1,53 @@
+# Third-Party Exercises
+
+The support of Rustlings for third-party exercises allows you to create your own set of Rustlings exercises to focus on some specific topic.
+You could also offer a translatation of the original Rustlings exercises as third-party exercises.
+
+## Getting started
+
+To create third-party exercises, install Rustlings and run `rustlings dev new PROJECT_NAME`.
+This command will, similar to `cargo new PROJECT_NAME`, create a template directory called `PROJECT_NAME` with all what you need to get started.
+
+Read the comments in the generated `info.toml` file to understand its format.
+It allows you to set a custom welcome and final message and specify the metadata of every exercise.
+
+## Create an exercise
+
+Here is an example of the metadata of one file:
+
+```toml
+[[exercises]]
+name = "intro1"
+hint = """
+To finish this exercise, you need to …
+This link might help you …"""
+```
+
+After entering this in `info.toml`, create the file `intro1.rs` in the `exercises/` directory.
+The exercise needs to contain a `main` function, but it can be empty.
+Adding tests is recommended.
+Look at the official Rustlings exercises for inspiration.
+
+You can optionally add a solution file `intro1.rs` to the `solutions/` directory.
+
+Now, run `rustlings dev check`.
+It will tell you about any issues with your exercises.
+For example, it will tell you to run `rustlings dev update` to update the `Cargo.toml` file to include the new exercise `intro1`.
+
+`rustlings dev check` will also run your solutions (if you have any) to make sure that they run successfully.
+
+That's it!
+You finished your first exercise 🎉
+
+## Publish
+
+Now, add more exercises and publish them as a Git repository.
+
+Users just have to clone that repository and run `rustlings` in it to start working on your set of exercises just like the official ones.
+
+One difference to the official exercises is that the solution files will not be hidden until the user finishes an exercise.
+But you can trust the users to not look at the solution too early 😉
+
+## Share
+
+After publishing your set of exercises, open an issue or a pull request in the official Rustlings repository to link to your project in the README 😃
diff --git a/dev-Cargo.toml b/dev-Cargo.toml
new file mode 120000
index 00000000..9230c2e9
--- /dev/null
+++ b/dev-Cargo.toml
@@ -0,0 +1 @@
+dev/Cargo.toml
\ No newline at end of file
diff --git a/dev/Cargo.toml b/dev/Cargo.toml
new file mode 100644
index 00000000..7f3acb51
--- /dev/null
+++ b/dev/Cargo.toml
@@ -0,0 +1,197 @@
+# Don't edit the `bin` list manually! It is updated by `cargo run -- dev update`. This comment line will be stripped in `rustlings init`.
+bin = [
+ { name = "intro1", path = "../exercises/00_intro/intro1.rs" },
+ { name = "intro1_sol", path = "../solutions/00_intro/intro1.rs" },
+ { name = "intro2", path = "../exercises/00_intro/intro2.rs" },
+ { name = "intro2_sol", path = "../solutions/00_intro/intro2.rs" },
+ { name = "variables1", path = "../exercises/01_variables/variables1.rs" },
+ { name = "variables1_sol", path = "../solutions/01_variables/variables1.rs" },
+ { name = "variables2", path = "../exercises/01_variables/variables2.rs" },
+ { name = "variables2_sol", path = "../solutions/01_variables/variables2.rs" },
+ { name = "variables3", path = "../exercises/01_variables/variables3.rs" },
+ { name = "variables3_sol", path = "../solutions/01_variables/variables3.rs" },
+ { name = "variables4", path = "../exercises/01_variables/variables4.rs" },
+ { name = "variables4_sol", path = "../solutions/01_variables/variables4.rs" },
+ { name = "variables5", path = "../exercises/01_variables/variables5.rs" },
+ { name = "variables5_sol", path = "../solutions/01_variables/variables5.rs" },
+ { name = "variables6", path = "../exercises/01_variables/variables6.rs" },
+ { name = "variables6_sol", path = "../solutions/01_variables/variables6.rs" },
+ { name = "functions1", path = "../exercises/02_functions/functions1.rs" },
+ { name = "functions1_sol", path = "../solutions/02_functions/functions1.rs" },
+ { name = "functions2", path = "../exercises/02_functions/functions2.rs" },
+ { name = "functions2_sol", path = "../solutions/02_functions/functions2.rs" },
+ { name = "functions3", path = "../exercises/02_functions/functions3.rs" },
+ { name = "functions3_sol", path = "../solutions/02_functions/functions3.rs" },
+ { name = "functions4", path = "../exercises/02_functions/functions4.rs" },
+ { name = "functions4_sol", path = "../solutions/02_functions/functions4.rs" },
+ { name = "functions5", path = "../exercises/02_functions/functions5.rs" },
+ { name = "functions5_sol", path = "../solutions/02_functions/functions5.rs" },
+ { name = "if1", path = "../exercises/03_if/if1.rs" },
+ { name = "if1_sol", path = "../solutions/03_if/if1.rs" },
+ { name = "if2", path = "../exercises/03_if/if2.rs" },
+ { name = "if2_sol", path = "../solutions/03_if/if2.rs" },
+ { name = "if3", path = "../exercises/03_if/if3.rs" },
+ { name = "if3_sol", path = "../solutions/03_if/if3.rs" },
+ { name = "quiz1", path = "../exercises/quizzes/quiz1.rs" },
+ { name = "quiz1_sol", path = "../solutions/quizzes/quiz1.rs" },
+ { name = "primitive_types1", path = "../exercises/04_primitive_types/primitive_types1.rs" },
+ { name = "primitive_types1_sol", path = "../solutions/04_primitive_types/primitive_types1.rs" },
+ { name = "primitive_types2", path = "../exercises/04_primitive_types/primitive_types2.rs" },
+ { name = "primitive_types2_sol", path = "../solutions/04_primitive_types/primitive_types2.rs" },
+ { name = "primitive_types3", path = "../exercises/04_primitive_types/primitive_types3.rs" },
+ { name = "primitive_types3_sol", path = "../solutions/04_primitive_types/primitive_types3.rs" },
+ { name = "primitive_types4", path = "../exercises/04_primitive_types/primitive_types4.rs" },
+ { name = "primitive_types4_sol", path = "../solutions/04_primitive_types/primitive_types4.rs" },
+ { name = "primitive_types5", path = "../exercises/04_primitive_types/primitive_types5.rs" },
+ { name = "primitive_types5_sol", path = "../solutions/04_primitive_types/primitive_types5.rs" },
+ { name = "primitive_types6", path = "../exercises/04_primitive_types/primitive_types6.rs" },
+ { name = "primitive_types6_sol", path = "../solutions/04_primitive_types/primitive_types6.rs" },
+ { name = "vecs1", path = "../exercises/05_vecs/vecs1.rs" },
+ { name = "vecs1_sol", path = "../solutions/05_vecs/vecs1.rs" },
+ { name = "vecs2", path = "../exercises/05_vecs/vecs2.rs" },
+ { name = "vecs2_sol", path = "../solutions/05_vecs/vecs2.rs" },
+ { name = "move_semantics1", path = "../exercises/06_move_semantics/move_semantics1.rs" },
+ { name = "move_semantics1_sol", path = "../solutions/06_move_semantics/move_semantics1.rs" },
+ { name = "move_semantics2", path = "../exercises/06_move_semantics/move_semantics2.rs" },
+ { name = "move_semantics2_sol", path = "../solutions/06_move_semantics/move_semantics2.rs" },
+ { name = "move_semantics3", path = "../exercises/06_move_semantics/move_semantics3.rs" },
+ { name = "move_semantics3_sol", path = "../solutions/06_move_semantics/move_semantics3.rs" },
+ { name = "move_semantics4", path = "../exercises/06_move_semantics/move_semantics4.rs" },
+ { name = "move_semantics4_sol", path = "../solutions/06_move_semantics/move_semantics4.rs" },
+ { name = "move_semantics5", path = "../exercises/06_move_semantics/move_semantics5.rs" },
+ { name = "move_semantics5_sol", path = "../solutions/06_move_semantics/move_semantics5.rs" },
+ { name = "structs1", path = "../exercises/07_structs/structs1.rs" },
+ { name = "structs1_sol", path = "../solutions/07_structs/structs1.rs" },
+ { name = "structs2", path = "../exercises/07_structs/structs2.rs" },
+ { name = "structs2_sol", path = "../solutions/07_structs/structs2.rs" },
+ { name = "structs3", path = "../exercises/07_structs/structs3.rs" },
+ { name = "structs3_sol", path = "../solutions/07_structs/structs3.rs" },
+ { name = "enums1", path = "../exercises/08_enums/enums1.rs" },
+ { name = "enums1_sol", path = "../solutions/08_enums/enums1.rs" },
+ { name = "enums2", path = "../exercises/08_enums/enums2.rs" },
+ { name = "enums2_sol", path = "../solutions/08_enums/enums2.rs" },
+ { name = "enums3", path = "../exercises/08_enums/enums3.rs" },
+ { name = "enums3_sol", path = "../solutions/08_enums/enums3.rs" },
+ { name = "strings1", path = "../exercises/09_strings/strings1.rs" },
+ { name = "strings1_sol", path = "../solutions/09_strings/strings1.rs" },
+ { name = "strings2", path = "../exercises/09_strings/strings2.rs" },
+ { name = "strings2_sol", path = "../solutions/09_strings/strings2.rs" },
+ { name = "strings3", path = "../exercises/09_strings/strings3.rs" },
+ { name = "strings3_sol", path = "../solutions/09_strings/strings3.rs" },
+ { name = "strings4", path = "../exercises/09_strings/strings4.rs" },
+ { name = "strings4_sol", path = "../solutions/09_strings/strings4.rs" },
+ { name = "modules1", path = "../exercises/10_modules/modules1.rs" },
+ { name = "modules1_sol", path = "../solutions/10_modules/modules1.rs" },
+ { name = "modules2", path = "../exercises/10_modules/modules2.rs" },
+ { name = "modules2_sol", path = "../solutions/10_modules/modules2.rs" },
+ { name = "modules3", path = "../exercises/10_modules/modules3.rs" },
+ { name = "modules3_sol", path = "../solutions/10_modules/modules3.rs" },
+ { name = "hashmaps1", path = "../exercises/11_hashmaps/hashmaps1.rs" },
+ { name = "hashmaps1_sol", path = "../solutions/11_hashmaps/hashmaps1.rs" },
+ { name = "hashmaps2", path = "../exercises/11_hashmaps/hashmaps2.rs" },
+ { name = "hashmaps2_sol", path = "../solutions/11_hashmaps/hashmaps2.rs" },
+ { name = "hashmaps3", path = "../exercises/11_hashmaps/hashmaps3.rs" },
+ { name = "hashmaps3_sol", path = "../solutions/11_hashmaps/hashmaps3.rs" },
+ { name = "quiz2", path = "../exercises/quizzes/quiz2.rs" },
+ { name = "quiz2_sol", path = "../solutions/quizzes/quiz2.rs" },
+ { name = "options1", path = "../exercises/12_options/options1.rs" },
+ { name = "options1_sol", path = "../solutions/12_options/options1.rs" },
+ { name = "options2", path = "../exercises/12_options/options2.rs" },
+ { name = "options2_sol", path = "../solutions/12_options/options2.rs" },
+ { name = "options3", path = "../exercises/12_options/options3.rs" },
+ { name = "options3_sol", path = "../solutions/12_options/options3.rs" },
+ { name = "errors1", path = "../exercises/13_error_handling/errors1.rs" },
+ { name = "errors1_sol", path = "../solutions/13_error_handling/errors1.rs" },
+ { name = "errors2", path = "../exercises/13_error_handling/errors2.rs" },
+ { name = "errors2_sol", path = "../solutions/13_error_handling/errors2.rs" },
+ { name = "errors3", path = "../exercises/13_error_handling/errors3.rs" },
+ { name = "errors3_sol", path = "../solutions/13_error_handling/errors3.rs" },
+ { name = "errors4", path = "../exercises/13_error_handling/errors4.rs" },
+ { name = "errors4_sol", path = "../solutions/13_error_handling/errors4.rs" },
+ { name = "errors5", path = "../exercises/13_error_handling/errors5.rs" },
+ { name = "errors5_sol", path = "../solutions/13_error_handling/errors5.rs" },
+ { name = "errors6", path = "../exercises/13_error_handling/errors6.rs" },
+ { name = "errors6_sol", path = "../solutions/13_error_handling/errors6.rs" },
+ { name = "generics1", path = "../exercises/14_generics/generics1.rs" },
+ { name = "generics1_sol", path = "../solutions/14_generics/generics1.rs" },
+ { name = "generics2", path = "../exercises/14_generics/generics2.rs" },
+ { name = "generics2_sol", path = "../solutions/14_generics/generics2.rs" },
+ { name = "traits1", path = "../exercises/15_traits/traits1.rs" },
+ { name = "traits1_sol", path = "../solutions/15_traits/traits1.rs" },
+ { name = "traits2", path = "../exercises/15_traits/traits2.rs" },
+ { name = "traits2_sol", path = "../solutions/15_traits/traits2.rs" },
+ { name = "traits3", path = "../exercises/15_traits/traits3.rs" },
+ { name = "traits3_sol", path = "../solutions/15_traits/traits3.rs" },
+ { name = "traits4", path = "../exercises/15_traits/traits4.rs" },
+ { name = "traits4_sol", path = "../solutions/15_traits/traits4.rs" },
+ { name = "traits5", path = "../exercises/15_traits/traits5.rs" },
+ { name = "traits5_sol", path = "../solutions/15_traits/traits5.rs" },
+ { name = "quiz3", path = "../exercises/quizzes/quiz3.rs" },
+ { name = "quiz3_sol", path = "../solutions/quizzes/quiz3.rs" },
+ { name = "lifetimes1", path = "../exercises/16_lifetimes/lifetimes1.rs" },
+ { name = "lifetimes1_sol", path = "../solutions/16_lifetimes/lifetimes1.rs" },
+ { name = "lifetimes2", path = "../exercises/16_lifetimes/lifetimes2.rs" },
+ { name = "lifetimes2_sol", path = "../solutions/16_lifetimes/lifetimes2.rs" },
+ { name = "lifetimes3", path = "../exercises/16_lifetimes/lifetimes3.rs" },
+ { name = "lifetimes3_sol", path = "../solutions/16_lifetimes/lifetimes3.rs" },
+ { name = "tests1", path = "../exercises/17_tests/tests1.rs" },
+ { name = "tests1_sol", path = "../solutions/17_tests/tests1.rs" },
+ { name = "tests2", path = "../exercises/17_tests/tests2.rs" },
+ { name = "tests2_sol", path = "../solutions/17_tests/tests2.rs" },
+ { name = "tests3", path = "../exercises/17_tests/tests3.rs" },
+ { name = "tests3_sol", path = "../solutions/17_tests/tests3.rs" },
+ { name = "iterators1", path = "../exercises/18_iterators/iterators1.rs" },
+ { name = "iterators1_sol", path = "../solutions/18_iterators/iterators1.rs" },
+ { name = "iterators2", path = "../exercises/18_iterators/iterators2.rs" },
+ { name = "iterators2_sol", path = "../solutions/18_iterators/iterators2.rs" },
+ { name = "iterators3", path = "../exercises/18_iterators/iterators3.rs" },
+ { name = "iterators3_sol", path = "../solutions/18_iterators/iterators3.rs" },
+ { name = "iterators4", path = "../exercises/18_iterators/iterators4.rs" },
+ { name = "iterators4_sol", path = "../solutions/18_iterators/iterators4.rs" },
+ { name = "iterators5", path = "../exercises/18_iterators/iterators5.rs" },
+ { name = "iterators5_sol", path = "../solutions/18_iterators/iterators5.rs" },
+ { name = "box1", path = "../exercises/19_smart_pointers/box1.rs" },
+ { name = "box1_sol", path = "../solutions/19_smart_pointers/box1.rs" },
+ { name = "rc1", path = "../exercises/19_smart_pointers/rc1.rs" },
+ { name = "rc1_sol", path = "../solutions/19_smart_pointers/rc1.rs" },
+ { name = "arc1", path = "../exercises/19_smart_pointers/arc1.rs" },
+ { name = "arc1_sol", path = "../solutions/19_smart_pointers/arc1.rs" },
+ { name = "cow1", path = "../exercises/19_smart_pointers/cow1.rs" },
+ { name = "cow1_sol", path = "../solutions/19_smart_pointers/cow1.rs" },
+ { name = "threads1", path = "../exercises/20_threads/threads1.rs" },
+ { name = "threads1_sol", path = "../solutions/20_threads/threads1.rs" },
+ { name = "threads2", path = "../exercises/20_threads/threads2.rs" },
+ { name = "threads2_sol", path = "../solutions/20_threads/threads2.rs" },
+ { name = "threads3", path = "../exercises/20_threads/threads3.rs" },
+ { name = "threads3_sol", path = "../solutions/20_threads/threads3.rs" },
+ { name = "macros1", path = "../exercises/21_macros/macros1.rs" },
+ { name = "macros1_sol", path = "../solutions/21_macros/macros1.rs" },
+ { name = "macros2", path = "../exercises/21_macros/macros2.rs" },
+ { name = "macros2_sol", path = "../solutions/21_macros/macros2.rs" },
+ { name = "macros3", path = "../exercises/21_macros/macros3.rs" },
+ { name = "macros3_sol", path = "../solutions/21_macros/macros3.rs" },
+ { name = "macros4", path = "../exercises/21_macros/macros4.rs" },
+ { name = "macros4_sol", path = "../solutions/21_macros/macros4.rs" },
+ { name = "clippy1", path = "../exercises/22_clippy/clippy1.rs" },
+ { name = "clippy1_sol", path = "../solutions/22_clippy/clippy1.rs" },
+ { name = "clippy2", path = "../exercises/22_clippy/clippy2.rs" },
+ { name = "clippy2_sol", path = "../solutions/22_clippy/clippy2.rs" },
+ { name = "clippy3", path = "../exercises/22_clippy/clippy3.rs" },
+ { name = "clippy3_sol", path = "../solutions/22_clippy/clippy3.rs" },
+ { name = "using_as", path = "../exercises/23_conversions/using_as.rs" },
+ { name = "using_as_sol", path = "../solutions/23_conversions/using_as.rs" },
+ { name = "from_into", path = "../exercises/23_conversions/from_into.rs" },
+ { name = "from_into_sol", path = "../solutions/23_conversions/from_into.rs" },
+ { name = "from_str", path = "../exercises/23_conversions/from_str.rs" },
+ { name = "from_str_sol", path = "../solutions/23_conversions/from_str.rs" },
+ { name = "try_from_into", path = "../exercises/23_conversions/try_from_into.rs" },
+ { name = "try_from_into_sol", path = "../solutions/23_conversions/try_from_into.rs" },
+ { name = "as_ref_mut", path = "../exercises/23_conversions/as_ref_mut.rs" },
+ { name = "as_ref_mut_sol", path = "../solutions/23_conversions/as_ref_mut.rs" },
+]
+
+[package]
+name = "exercises"
+edition = "2021"
+# Don't publish the exercises on crates.io!
+publish = false
diff --git a/dev/rustlings-repo.txt b/dev/rustlings-repo.txt
new file mode 100644
index 00000000..62793612
--- /dev/null
+++ b/dev/rustlings-repo.txt
@@ -0,0 +1 @@
+This file is used to check if the user tries to run Rustlings in the repository (the method before v6)
diff --git a/exercises/00_intro/intro1.rs b/exercises/00_intro/intro1.rs
index 5dd18b45..22544cd4 100644
--- a/exercises/00_intro/intro1.rs
+++ b/exercises/00_intro/intro1.rs
@@ -1,19 +1,10 @@
-// intro1.rs
+// TODO: 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, enter `n` in the terminal.
//
-// 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.
-//
-// If you're running this using `rustlings watch`: The exercise file will be
-// reloaded when you change one of the lines below! Try adding a `println!`
-// line, or try changing what it outputs in your terminal. Try removing a
-// semicolon and see what happens!
-//
-// Execute `rustlings hint intro1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// The exercise file will be reloaded when you change one of the lines below!
+// Try adding a new `println!`.
+// Try removing a semicolon and see what happens in the terminal!
fn main() {
println!("Hello and");
@@ -29,13 +20,7 @@ fn main() {
println!("or logic error. The central concept behind Rustlings is to fix these errors and");
println!("solve the exercises. Good luck!");
println!();
- println!("The source for this exercise is in `exercises/00_intro/intro1.rs`. Have a look!");
- println!(
- "Going forward, the source of the exercises will always be in the success/failure output."
- );
- println!();
- println!(
- "If you want to use rust-analyzer, Rust's LSP implementation, make sure your editor is set"
- );
- println!("up, and then run `rustlings lsp` before continuing.")
+ println!("The file of this exercise is `exercises/00_intro/intro1.rs`. Have a look!");
+ println!("The current exercise path will be always shown under the progress bar.");
+ println!("You can click on the path to open the exercise file in your editor.");
}
diff --git a/exercises/00_intro/intro2.rs b/exercises/00_intro/intro2.rs
index a28ad3dc..c6cb6451 100644
--- a/exercises/00_intro/intro2.rs
+++ b/exercises/00_intro/intro2.rs
@@ -1,12 +1,4 @@
-// intro2.rs
-//
-// Make the code print a greeting to the world.
-//
-// Execute `rustlings hint intro2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
fn main() {
- printline!("Hello there!")
+ // TODO: Fix the code to print "Hello world!".
+ printline!("Hello world!");
}
diff --git a/exercises/01_variables/variables1.rs b/exercises/01_variables/variables1.rs
index b3e089a5..0a9e5548 100644
--- a/exercises/01_variables/variables1.rs
+++ b/exercises/01_variables/variables1.rs
@@ -1,13 +1,6 @@
-// variables1.rs
-//
-// Make me compile!
-//
-// Execute `rustlings hint variables1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
fn main() {
+ // TODO: Add missing keyword.
x = 5;
- println!("x has the value {}", x);
+
+ println!("x has the value {x}");
}
diff --git a/exercises/01_variables/variables2.rs b/exercises/01_variables/variables2.rs
index e1c23edf..e2a36035 100644
--- a/exercises/01_variables/variables2.rs
+++ b/exercises/01_variables/variables2.rs
@@ -1,12 +1,7 @@
-// variables2.rs
-//
-// Execute `rustlings hint variables2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
fn main() {
+ // TODO: Change the line below to fix the compiler error.
let x;
+
if x == 10 {
println!("x is ten!");
} else {
diff --git a/exercises/01_variables/variables3.rs b/exercises/01_variables/variables3.rs
index 86bed419..06f35bb1 100644
--- a/exercises/01_variables/variables3.rs
+++ b/exercises/01_variables/variables3.rs
@@ -1,11 +1,6 @@
-// variables3.rs
-//
-// Execute `rustlings hint variables3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
fn main() {
+ // TODO: Change the line below to fix the compiler error.
let x: i32;
- println!("Number {}", x);
+
+ println!("Number {x}");
}
diff --git a/exercises/01_variables/variables4.rs b/exercises/01_variables/variables4.rs
index 5394f394..6c138b18 100644
--- a/exercises/01_variables/variables4.rs
+++ b/exercises/01_variables/variables4.rs
@@ -1,13 +1,8 @@
-// variables4.rs
-//
-// Execute `rustlings hint variables4` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
+// TODO: Fix the compiler error.
fn main() {
let x = 3;
- println!("Number {}", x);
- x = 5; // don't change this line
- println!("Number {}", x);
+ println!("Number {x}");
+
+ x = 5; // Don't change this line
+ println!("Number {x}");
}
diff --git a/exercises/01_variables/variables5.rs b/exercises/01_variables/variables5.rs
index a29b38be..49db8e9e 100644
--- a/exercises/01_variables/variables5.rs
+++ b/exercises/01_variables/variables5.rs
@@ -1,13 +1,8 @@
-// variables5.rs
-//
-// Execute `rustlings hint variables5` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
fn main() {
- let number = "T-H-R-E-E"; // don't change this line
- println!("Spell a Number : {}", number);
- number = 3; // don't rename this variable
- println!("Number plus two is : {}", number + 2);
+ let number = "T-H-R-E-E"; // Don't change this line
+ println!("Spell a number: {}", number);
+
+ // TODO: Fix the compiler error by changing the line below without renaming the variable.
+ number = 3;
+ println!("Number plus two is: {}", number + 2);
}
diff --git a/exercises/01_variables/variables6.rs b/exercises/01_variables/variables6.rs
index 853183ba..4a040fdd 100644
--- a/exercises/01_variables/variables6.rs
+++ b/exercises/01_variables/variables6.rs
@@ -1,11 +1,6 @@
-// variables6.rs
-//
-// Execute `rustlings hint variables6` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
+// TODO: Change the line below to fix the compiler error.
const NUMBER = 3;
+
fn main() {
- println!("Number {}", NUMBER);
+ println!("Number: {NUMBER}");
}
diff --git a/exercises/02_functions/functions1.rs b/exercises/02_functions/functions1.rs
index 40ed9a07..a812c21b 100644
--- a/exercises/02_functions/functions1.rs
+++ b/exercises/02_functions/functions1.rs
@@ -1,10 +1,5 @@
-// functions1.rs
-//
-// Execute `rustlings hint functions1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// TODO: Add some function with the name `call_me` without arguments or a return value.
fn main() {
- call_me();
+ call_me(); // Don't change this line
}
diff --git a/exercises/02_functions/functions2.rs b/exercises/02_functions/functions2.rs
index 5154f34d..2c773c6b 100644
--- a/exercises/02_functions/functions2.rs
+++ b/exercises/02_functions/functions2.rs
@@ -1,16 +1,10 @@
-// functions2.rs
-//
-// Execute `rustlings hint functions2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-fn main() {
- call_me(3);
-}
-
+// TODO: Add the missing type of the argument `num` after the colon `:`.
fn call_me(num:) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
+
+fn main() {
+ call_me(3);
+}
diff --git a/exercises/02_functions/functions3.rs b/exercises/02_functions/functions3.rs
index 74f44d6d..5d5122af 100644
--- a/exercises/02_functions/functions3.rs
+++ b/exercises/02_functions/functions3.rs
@@ -1,16 +1,10 @@
-// functions3.rs
-//
-// Execute `rustlings hint functions3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-fn main() {
- call_me();
-}
-
fn call_me(num: u32) {
for i in 0..num {
println!("Ring! Call number {}", i + 1);
}
}
+
+fn main() {
+ // TODO: Fix the function call.
+ call_me();
+}
diff --git a/exercises/02_functions/functions4.rs b/exercises/02_functions/functions4.rs
index 77c4b2aa..b22bffda 100644
--- a/exercises/02_functions/functions4.rs
+++ b/exercises/02_functions/functions4.rs
@@ -1,21 +1,14 @@
-// functions4.rs
-//
// This store is having a sale where if the price is an even number, you get 10
-// Rustbucks off, but if it's an odd number, it's 3 Rustbucks off. (Don't worry
-// about the function bodies themselves, we're only interested in the signatures
-// for now. If anything, this is a good way to peek ahead to future exercises!)
-//
-// Execute `rustlings hint functions4` or use the `hint` watch subcommand for a
-// hint.
+// Rustbucks off, but if it's an odd number, it's 3 Rustbucks off.
+// Don't worry about the function bodies themselves, we are only interested in
+// the signatures for now.
-// I AM NOT DONE
-
-fn main() {
- let original_price = 51;
- println!("Your sale price is {}", sale_price(original_price));
+fn is_even(num: i64) -> bool {
+ num % 2 == 0
}
-fn sale_price(price: i32) -> {
+// TODO: Fix the function signature.
+fn sale_price(price: i64) -> {
if is_even(price) {
price - 10
} else {
@@ -23,6 +16,7 @@ fn sale_price(price: i32) -> {
}
}
-fn is_even(num: i32) -> bool {
- num % 2 == 0
+fn main() {
+ let original_price = 51;
+ println!("Your sale price is {}", sale_price(original_price));
}
diff --git a/exercises/02_functions/functions5.rs b/exercises/02_functions/functions5.rs
index f1b63f48..34a2ac7d 100644
--- a/exercises/02_functions/functions5.rs
+++ b/exercises/02_functions/functions5.rs
@@ -1,15 +1,9 @@
-// functions5.rs
-//
-// Execute `rustlings hint functions5` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-fn main() {
- let answer = square(3);
- println!("The square of 3 is {}", answer);
-}
-
+// TODO: Fix the function body without changing the signature.
fn square(num: i32) -> i32 {
num * num;
}
+
+fn main() {
+ let answer = square(3);
+ println!("The square of 3 is {answer}");
+}
diff --git a/exercises/03_if/if1.rs b/exercises/03_if/if1.rs
index d2afccf8..e5a3c5a5 100644
--- a/exercises/03_if/if1.rs
+++ b/exercises/03_if/if1.rs
@@ -1,17 +1,15 @@
-// if1.rs
-//
-// Execute `rustlings hint if1` or use the `hint` watch subcommand for a hint.
-
-// I AM NOT DONE
-
-pub fn bigger(a: i32, b: i32) -> i32 {
- // Complete this function to return the bigger number!
+fn bigger(a: i32, b: i32) -> i32 {
+ // TODO: Complete this function to return the bigger number!
// If both numbers are equal, any of them can be returned.
// Do not use:
// - another function call
// - additional variables
}
+fn main() {
+ // You can optionally experiment here.
+}
+
// Don't mind this for now :)
#[cfg(test)]
mod tests {
diff --git a/exercises/03_if/if2.rs b/exercises/03_if/if2.rs
index f512f13f..593a77a7 100644
--- a/exercises/03_if/if2.rs
+++ b/exercises/03_if/if2.rs
@@ -1,13 +1,5 @@
-// if2.rs
-//
-// Step 1: Make me compile!
-// Step 2: Get the bar_for_fuzz and default_to_baz tests passing!
-//
-// Execute `rustlings hint if2` or use the `hint` watch subcommand for a hint.
-
-// I AM NOT DONE
-
-pub fn foo_if_fizz(fizzish: &str) -> &str {
+// TODO: Fix the compiler error on this function.
+fn foo_if_fizz(fizzish: &str) -> &str {
if fizzish == "fizz" {
"foo"
} else {
@@ -15,23 +7,29 @@ pub fn foo_if_fizz(fizzish: &str) -> &str {
}
}
-// No test changes needed!
+fn main() {
+ // You can optionally experiment here.
+}
+
+// TODO: Read the tests to understand the desired behavior.
+// Make all tests pass without changing them.
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn foo_for_fizz() {
- assert_eq!(foo_if_fizz("fizz"), "foo")
+ // This means that calling `foo_if_fizz` with the argument "fizz" should return "foo".
+ assert_eq!(foo_if_fizz("fizz"), "foo");
}
#[test]
fn bar_for_fuzz() {
- assert_eq!(foo_if_fizz("fuzz"), "bar")
+ assert_eq!(foo_if_fizz("fuzz"), "bar");
}
#[test]
fn default_to_baz() {
- assert_eq!(foo_if_fizz("literally anything"), "baz")
+ assert_eq!(foo_if_fizz("literally anything"), "baz");
}
}
diff --git a/exercises/03_if/if3.rs b/exercises/03_if/if3.rs
index 16962740..89164eb2 100644
--- a/exercises/03_if/if3.rs
+++ b/exercises/03_if/if3.rs
@@ -1,10 +1,5 @@
-// if3.rs
-//
-// Execute `rustlings hint if3` or use the `hint` watch subcommand for a hint.
-
-// I AM NOT DONE
-
-pub fn animal_habitat(animal: &str) -> &'static str {
+fn animal_habitat(animal: &str) -> &str {
+ // TODO: Fix the compiler error in the statement below.
let identifier = if animal == "crab" {
1
} else if animal == "gopher" {
@@ -15,8 +10,8 @@ pub fn animal_habitat(animal: &str) -> &'static str {
"Unknown"
};
- // DO NOT CHANGE THIS STATEMENT BELOW
- let habitat = if identifier == 1 {
+ // Don't change the expression below!
+ if identifier == 1 {
"Beach"
} else if identifier == 2 {
"Burrow"
@@ -24,12 +19,14 @@ pub fn animal_habitat(animal: &str) -> &'static str {
"Desert"
} else {
"Unknown"
- };
-
- habitat
+ }
}
-// No test changes needed.
+fn main() {
+ // You can optionally experiment here.
+}
+
+// Don't change the tests!
#[cfg(test)]
mod tests {
use super::*;
diff --git a/exercises/04_primitive_types/primitive_types1.rs b/exercises/04_primitive_types/primitive_types1.rs
index 36633400..84923c75 100644
--- a/exercises/04_primitive_types/primitive_types1.rs
+++ b/exercises/04_primitive_types/primitive_types1.rs
@@ -1,19 +1,14 @@
-// primitive_types1.rs
-//
-// Fill in the rest of the line that has code missing! No hints, there's no
-// tricks, just get used to typing these :)
-
-// I AM NOT DONE
+// Booleans (`bool`)
fn main() {
- // Booleans (`bool`)
-
let is_morning = true;
if is_morning {
println!("Good morning!");
}
- let // Finish the rest of this line like the example! Or make it be false!
+ // TODO: Define a boolean variable with the name `is_evening` before the `if` statement below.
+ // The value of the variable should be the negation (opposite) of `is_morning`.
+ // let …
if is_evening {
println!("Good evening!");
}
diff --git a/exercises/04_primitive_types/primitive_types2.rs b/exercises/04_primitive_types/primitive_types2.rs
index f1616ed3..14018475 100644
--- a/exercises/04_primitive_types/primitive_types2.rs
+++ b/exercises/04_primitive_types/primitive_types2.rs
@@ -1,13 +1,6 @@
-// primitive_types2.rs
-//
-// Fill in the rest of the line that has code missing! No hints, there's no
-// tricks, just get used to typing these :)
-
-// I AM NOT DONE
+// Characters (`char`)
fn main() {
- // Characters (`char`)
-
// Note the _single_ quotes, these are different from the double quotes
// you've been seeing around.
let my_first_initial = 'C';
@@ -19,9 +12,12 @@ fn main() {
println!("Neither alphabetic nor numeric!");
}
- let // Finish this line like the example! What's your favorite character?
- // Try a letter, try a number, try a special character, try a character
- // from a different language than your own, try an emoji!
+ // TODO: Analogous to the example before, declare a variable called `your_character`
+ // below with your favorite character.
+ // Try a letter, try a digit (in single quotes), try a special character, try a character
+ // from a different language than your own, try an emoji 😉
+ // let your_character = '';
+
if your_character.is_alphabetic() {
println!("Alphabetical!");
} else if your_character.is_numeric() {
diff --git a/exercises/04_primitive_types/primitive_types3.rs b/exercises/04_primitive_types/primitive_types3.rs
index 8b0de44e..9b79c0cf 100644
--- a/exercises/04_primitive_types/primitive_types3.rs
+++ b/exercises/04_primitive_types/primitive_types3.rs
@@ -1,19 +1,11 @@
-// primitive_types3.rs
-//
-// Create an array with at least 100 elements in it where the ??? is.
-//
-// Execute `rustlings hint primitive_types3` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
fn main() {
- let a = ???
+ // TODO: Create an array called `a` with at least 100 elements in it.
+ // let a = ???
if a.len() >= 100 {
println!("Wow, that's a big array!");
} else {
println!("Meh, I eat arrays like that for breakfast.");
- panic!("Array not big enough, more elements needed")
+ panic!("Array not big enough, more elements needed");
}
}
diff --git a/exercises/04_primitive_types/primitive_types4.rs b/exercises/04_primitive_types/primitive_types4.rs
index d44d8776..16e4fd93 100644
--- a/exercises/04_primitive_types/primitive_types4.rs
+++ b/exercises/04_primitive_types/primitive_types4.rs
@@ -1,17 +1,16 @@
-// primitive_types4.rs
-//
-// Get a slice out of Array a where the ??? is so that the test passes.
-//
-// Execute `rustlings hint primitive_types4` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
-fn slice_out_of_array() {
- let a = [1, 2, 3, 4, 5];
-
- let nice_slice = ???
-
- assert_eq!([2, 3, 4], nice_slice)
+fn main() {
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn slice_out_of_array() {
+ let a = [1, 2, 3, 4, 5];
+
+ // TODO: Get a slice called `nice_slice` out of the array `a` so that the test passes.
+ // let nice_slice = ???
+
+ assert_eq!([2, 3, 4], nice_slice);
+ }
}
diff --git a/exercises/04_primitive_types/primitive_types5.rs b/exercises/04_primitive_types/primitive_types5.rs
index f646986e..6e00ef51 100644
--- a/exercises/04_primitive_types/primitive_types5.rs
+++ b/exercises/04_primitive_types/primitive_types5.rs
@@ -1,15 +1,8 @@
-// primitive_types5.rs
-//
-// Destructure the `cat` tuple so that the println will work.
-//
-// Execute `rustlings hint primitive_types5` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
fn main() {
let cat = ("Furry McFurson", 3.5);
- let /* your pattern here */ = cat;
- println!("{} is {} years old.", name, age);
+ // TODO: Destructure the `cat` tuple in one statement so that the println works.
+ // let /* your pattern here */ = cat;
+
+ println!("{name} is {age} years old");
}
diff --git a/exercises/04_primitive_types/primitive_types6.rs b/exercises/04_primitive_types/primitive_types6.rs
index 07cc46c6..a97e5311 100644
--- a/exercises/04_primitive_types/primitive_types6.rs
+++ b/exercises/04_primitive_types/primitive_types6.rs
@@ -1,19 +1,17 @@
-// primitive_types6.rs
-//
-// Use a tuple index to access the second element of `numbers`. You can put the
-// expression for the second element where ??? is so that the test passes.
-//
-// Execute `rustlings hint primitive_types6` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
-fn indexing_tuple() {
- let numbers = (1, 2, 3);
- // Replace below ??? with the tuple indexing syntax.
- let second = ???;
-
- assert_eq!(2, second,
- "This is not the 2nd number in the tuple!")
+fn main() {
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn indexing_tuple() {
+ let numbers = (1, 2, 3);
+
+ // TODO: Use a tuple index to access the second element of `numbers`
+ // and assign it to a variable called `second`.
+ // let second = ???;
+
+ assert_eq!(second, 2, "This is not the 2nd number in the tuple!");
+ }
}
diff --git a/exercises/05_vecs/vecs1.rs b/exercises/05_vecs/vecs1.rs
index 65b7a7f8..68e1affa 100644
--- a/exercises/05_vecs/vecs1.rs
+++ b/exercises/05_vecs/vecs1.rs
@@ -1,21 +1,17 @@
-// vecs1.rs
-//
-// Your task is to create a `Vec` which holds the exact same elements as in the
-// array `a`.
-//
-// Make me compile and pass the test!
-//
-// Execute `rustlings hint vecs1` or use the `hint` watch subcommand for a hint.
-
-// I AM NOT DONE
-
fn array_and_vec() -> ([i32; 4], Vec) {
- let a = [10, 20, 30, 40]; // a plain array
- let v = // TODO: declare your vector here with the macro for vectors
+ let a = [10, 20, 30, 40]; // Array
+
+ // TODO: Create a vector called `v` which contains the exact same elements as in the array `a`.
+ // Use the vector macro.
+ // let v = ???;
(a, v)
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -23,6 +19,6 @@ mod tests {
#[test]
fn test_array_and_vec_similarity() {
let (a, v) = array_and_vec();
- assert_eq!(a, v[..]);
+ assert_eq!(a, *v);
}
}
diff --git a/exercises/05_vecs/vecs2.rs b/exercises/05_vecs/vecs2.rs
index e92c970a..a9be2580 100644
--- a/exercises/05_vecs/vecs2.rs
+++ b/exercises/05_vecs/vecs2.rs
@@ -1,31 +1,36 @@
-// vecs2.rs
-//
-// A Vec of even numbers is given. Your task is to complete the loop so that
-// each number in the Vec is multiplied by 2.
-//
-// Make me pass the test!
-//
-// Execute `rustlings hint vecs2` or use the `hint` watch subcommand for a hint.
+fn vec_loop(input: &[i32]) -> Vec {
+ let mut output = Vec::new();
-// I AM NOT DONE
-
-fn vec_loop(mut v: Vec) -> Vec {
- for element in v.iter_mut() {
- // TODO: Fill this up so that each element in the Vec `v` is
- // multiplied by 2.
- ???
+ for element in input {
+ // TODO: Multiply each element in the `input` slice by 2 and push it to
+ // the `output` vector.
}
- // At this point, `v` should be equal to [4, 8, 12, 16, 20].
- v
+ output
}
-fn vec_map(v: &Vec) -> Vec {
- v.iter().map(|element| {
- // TODO: Do the same thing as above - but instead of mutating the
- // Vec, you can just return the new number!
- ???
- }).collect()
+fn vec_map_example(input: &[i32]) -> Vec {
+ // An example of collecting a vector after mapping.
+ // We map each element of the `input` slice to its value plus 1.
+ // If the input is `[1, 2, 3]`, the output is `[2, 3, 4]`.
+ input.iter().map(|element| element + 1).collect()
+}
+
+fn vec_map(input: &[i32]) -> Vec {
+ // TODO: Here, we also want to multiply each element in the `input` slice
+ // by 2, but with iterator mapping instead of manually pushing into an empty
+ // vector.
+ // See the example in the function `vec_map_example` above.
+ input
+ .iter()
+ .map(|element| {
+ // ???
+ })
+ .collect()
+}
+
+fn main() {
+ // You can optionally experiment here.
}
#[cfg(test)]
@@ -34,17 +39,22 @@ mod tests {
#[test]
fn test_vec_loop() {
- let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect();
- let ans = vec_loop(v.clone());
+ let input = [2, 4, 6, 8, 10];
+ let ans = vec_loop(&input);
+ assert_eq!(ans, [4, 8, 12, 16, 20]);
+ }
- assert_eq!(ans, v.iter().map(|x| x * 2).collect::>());
+ #[test]
+ fn test_vec_map_example() {
+ let input = [1, 2, 3];
+ let ans = vec_map_example(&input);
+ assert_eq!(ans, [2, 3, 4]);
}
#[test]
fn test_vec_map() {
- let v: Vec = (1..).filter(|x| x % 2 == 0).take(5).collect();
- let ans = vec_map(&v);
-
- assert_eq!(ans, v.iter().map(|x| x * 2).collect::>());
+ let input = [2, 4, 6, 8, 10];
+ let ans = vec_map(&input);
+ assert_eq!(ans, [4, 8, 12, 16, 20]);
}
}
diff --git a/exercises/06_move_semantics/move_semantics1.rs b/exercises/06_move_semantics/move_semantics1.rs
index e0639375..4eb3d618 100644
--- a/exercises/06_move_semantics/move_semantics1.rs
+++ b/exercises/06_move_semantics/move_semantics1.rs
@@ -1,19 +1,4 @@
-// move_semantics1.rs
-//
-// Execute `rustlings hint move_semantics1` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
-fn main() {
- let vec0 = vec![22, 44, 66];
-
- let vec1 = fill_vec(vec0);
-
- assert_eq!(vec1, vec![22, 44, 66, 88]);
-}
-
+// TODO: Fix the compiler error in this function.
fn fill_vec(vec: Vec) -> Vec {
let vec = vec;
@@ -21,3 +6,19 @@ fn fill_vec(vec: Vec) -> Vec {
vec
}
+
+fn main() {
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn move_semantics1() {
+ let vec0 = vec![22, 44, 66];
+ let vec1 = fill_vec(vec0);
+ assert_eq!(vec1, vec![22, 44, 66, 88]);
+ }
+}
diff --git a/exercises/06_move_semantics/move_semantics2.rs b/exercises/06_move_semantics/move_semantics2.rs
index dc58be50..a3ab7a0f 100644
--- a/exercises/06_move_semantics/move_semantics2.rs
+++ b/exercises/06_move_semantics/move_semantics2.rs
@@ -1,22 +1,3 @@
-// move_semantics2.rs
-//
-// Make the test pass by finding a way to keep both Vecs separate!
-//
-// Execute `rustlings hint move_semantics2` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
-fn main() {
- let vec0 = vec![22, 44, 66];
-
- let vec1 = fill_vec(vec0);
-
- assert_eq!(vec0, vec![22, 44, 66]);
- assert_eq!(vec1, vec![22, 44, 66, 88]);
-}
-
fn fill_vec(vec: Vec) -> Vec {
let mut vec = vec;
@@ -24,3 +5,24 @@ fn fill_vec(vec: Vec) -> Vec {
vec
}
+
+fn main() {
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ // TODO: Make both vectors `vec0` and `vec1` accessible at the same time to
+ // fix the compiler error in the test.
+ #[test]
+ fn move_semantics2() {
+ let vec0 = vec![22, 44, 66];
+
+ let vec1 = fill_vec(vec0);
+
+ assert_eq!(vec0, [22, 44, 66]);
+ assert_eq!(vec1, [22, 44, 66, 88]);
+ }
+}
diff --git a/exercises/06_move_semantics/move_semantics3.rs b/exercises/06_move_semantics/move_semantics3.rs
index 7152c716..11dbbbeb 100644
--- a/exercises/06_move_semantics/move_semantics3.rs
+++ b/exercises/06_move_semantics/move_semantics3.rs
@@ -1,24 +1,22 @@
-// move_semantics3.rs
-//
-// Make me compile without adding new lines -- just changing existing lines! (no
-// lines with multiple semicolons necessary!)
-//
-// Execute `rustlings hint move_semantics3` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
-fn main() {
- let vec0 = vec![22, 44, 66];
-
- let vec1 = fill_vec(vec0);
-
- assert_eq!(vec1, vec![22, 44, 66, 88]);
-}
-
+// TODO: Fix the compiler error in the function without adding any new line.
fn fill_vec(vec: Vec) -> Vec {
vec.push(88);
vec
}
+
+fn main() {
+ // You can optionally experiment here.
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn move_semantics3() {
+ let vec0 = vec![22, 44, 66];
+ let vec1 = fill_vec(vec0);
+ assert_eq!(vec1, [22, 44, 66, 88]);
+ }
+}
diff --git a/exercises/06_move_semantics/move_semantics4.rs b/exercises/06_move_semantics/move_semantics4.rs
index bfc917fa..c225f3ba 100644
--- a/exercises/06_move_semantics/move_semantics4.rs
+++ b/exercises/06_move_semantics/move_semantics4.rs
@@ -1,29 +1,18 @@
-// move_semantics4.rs
-//
-// Refactor this code so that instead of passing `vec0` into the `fill_vec`
-// function, the Vector gets created in the function itself and passed back to
-// the main function.
-//
-// Execute `rustlings hint move_semantics4` or use the `hint` watch subcommand
-// for a hint.
-
-// I AM NOT DONE
-
-#[test]
fn main() {
- let vec0 = vec![22, 44, 66];
-
- let vec1 = fill_vec(vec0);
-
- assert_eq!(vec1, vec![22, 44, 66, 88]);
+ // You can optionally experiment here.
}
-// `fill_vec()` no longer takes `vec: Vec` as argument - don't change this!
-fn fill_vec() -> Vec {
- // Instead, let's create and fill the Vec in here - how do you do that?
- let mut vec = vec;
-
- vec.push(88);
-
- vec
+#[cfg(test)]
+mod tests {
+ // TODO: Fix the compiler errors only by reordering the lines in the test.
+ // Don't add, change or remove any line.
+ #[test]
+ fn move_semantics5() {
+ let mut x = 100;
+ let y = &mut x;
+ let z = &mut x;
+ *y += 100;
+ *z += 1000;
+ assert_eq!(x, 1200);
+ }
}
diff --git a/exercises/06_move_semantics/move_semantics5.rs b/exercises/06_move_semantics/move_semantics5.rs
index 267bdccc..65065688 100644
--- a/exercises/06_move_semantics/move_semantics5.rs
+++ b/exercises/06_move_semantics/move_semantics5.rs
@@ -1,19 +1,22 @@
-// move_semantics5.rs
-//
-// Make me compile only by reordering the lines in `main()`, but without adding,
-// changing or removing any of them.
-//
-// Execute `rustlings hint move_semantics5` or use the `hint` watch subcommand
-// for a hint.
+// TODO: Fix the compiler errors without changing anything except adding or
+// removing references (the character `&`).
-// I AM NOT DONE
-
-#[test]
fn main() {
- let mut x = 100;
- let y = &mut x;
- let z = &mut x;
- *y += 100;
- *z += 1000;
- assert_eq!(x, 1200);
+ let data = "Rust is great!".to_string();
+
+ get_char(data);
+
+ string_uppercase(&data);
+}
+
+// Shouldn't 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/06_move_semantics/move_semantics6.rs b/exercises/06_move_semantics/move_semantics6.rs
deleted file mode 100644
index cace4ca6..00000000
--- a/exercises/06_move_semantics/move_semantics6.rs
+++ /dev/null
@@ -1,28 +0,0 @@
-// move_semantics6.rs
-//
-// You can't change anything except adding or removing references.
-//
-// Execute `rustlings hint move_semantics6` or use the `hint` watch subcommand
-// for a hint.
-
-// 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/07_structs/structs1.rs b/exercises/07_structs/structs1.rs
index 5fa5821c..959c4c6a 100644
--- a/exercises/07_structs/structs1.rs
+++ b/exercises/07_structs/structs1.rs
@@ -1,28 +1,24 @@
-// structs1.rs
-//
-// Address all the TODOs to make the tests pass!
-//
-// Execute `rustlings hint structs1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-struct ColorClassicStruct {
- // TODO: Something goes here
+struct ColorRegularStruct {
+ // TODO: Add the fields that the test `regular_structs` expects.
+ // What types should the fields have? What are the minimum and maximum values for RGB colors?
}
-struct ColorTupleStruct(/* TODO: Something goes here */);
+struct ColorTupleStruct(/* TODO: Add the fields that the test `tuple_structs` expects */);
#[derive(Debug)]
-struct UnitLikeStruct;
+struct UnitStruct;
+
+fn main() {
+ // You can optionally experiment here.
+}
#[cfg(test)]
mod tests {
use super::*;
#[test]
- fn classic_c_structs() {
- // TODO: Instantiate a classic c struct!
+ fn regular_structs() {
+ // TODO: Instantiate a regular struct.
// let green =
assert_eq!(green.red, 0);
@@ -32,7 +28,7 @@ mod tests {
#[test]
fn tuple_structs() {
- // TODO: Instantiate a tuple struct!
+ // TODO: Instantiate a tuple struct.
// let green =
assert_eq!(green.0, 0);
@@ -42,10 +38,10 @@ mod tests {
#[test]
fn unit_structs() {
- // TODO: Instantiate a unit-like struct!
- // let unit_like_struct =
- let message = format!("{:?}s are fun!", unit_like_struct);
+ // TODO: Instantiate a unit struct.
+ // let unit_struct =
+ let message = format!("{unit_struct:?}s are fun!");
- assert_eq!(message, "UnitLikeStructs are fun!");
+ assert_eq!(message, "UnitStructs are fun!");
}
}
diff --git a/exercises/07_structs/structs2.rs b/exercises/07_structs/structs2.rs
index 328567f0..79141af9 100644
--- a/exercises/07_structs/structs2.rs
+++ b/exercises/07_structs/structs2.rs
@@ -1,12 +1,3 @@
-// structs2.rs
-//
-// Address all the TODOs to make the tests pass!
-//
-// Execute `rustlings hint structs2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
#[derive(Debug)]
struct Order {
name: String,
@@ -30,6 +21,10 @@ fn create_order_template() -> Order {
}
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -37,8 +32,10 @@ mod tests {
#[test]
fn your_order() {
let order_template = create_order_template();
+
// TODO: Create your own order using the update syntax and template above!
// let your_order =
+
assert_eq!(your_order.name, "Hacker in Rust");
assert_eq!(your_order.year, order_template.year);
assert_eq!(your_order.made_by_phone, order_template.made_by_phone);
diff --git a/exercises/07_structs/structs3.rs b/exercises/07_structs/structs3.rs
index 7cda5af1..93b57fef 100644
--- a/exercises/07_structs/structs3.rs
+++ b/exercises/07_structs/structs3.rs
@@ -1,13 +1,5 @@
-// structs3.rs
-//
// Structs contain data, but can also have logic. In this exercise we have
-// defined the Package struct and we want to test some logic attached to it.
-// Make the code compile and the tests pass!
-//
-// Execute `rustlings hint structs3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// defined the `Package` struct and we want to test some logic attached to it.
#[derive(Debug)]
struct Package {
@@ -17,29 +9,36 @@ struct Package {
}
impl Package {
- fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Package {
+ fn new(sender_country: String, recipient_country: String, weight_in_grams: u32) -> Self {
if weight_in_grams < 10 {
- // This is not how you should handle errors in Rust,
- // but we will learn about error handling later.
- panic!("Can not ship a package with weight below 10 grams.")
- } else {
- Package {
- sender_country,
- recipient_country,
- weight_in_grams,
- }
+ // This isn't how you should handle errors in Rust, but we will
+ // learn about error handling later.
+ panic!("Can't ship a package with weight below 10 grams");
+ }
+
+ Self {
+ sender_country,
+ recipient_country,
+ weight_in_grams,
}
}
- fn is_international(&self) -> ??? {
- // Something goes here...
+ // TODO: Add the correct return type to the function signature.
+ fn is_international(&self) {
+ // TODO: Read the tests that use this method to find out when a package
+ // is considered international.
}
- fn get_fees(&self, cents_per_gram: u32) -> ??? {
- // Something goes here...
+ // TODO: Add the correct return type to the function signature.
+ fn get_fees(&self, cents_per_gram: u32) {
+ // TODO: Calculate the package's fees.
}
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/exercises/08_enums/enums1.rs b/exercises/08_enums/enums1.rs
index 25525b25..99f70874 100644
--- a/exercises/08_enums/enums1.rs
+++ b/exercises/08_enums/enums1.rs
@@ -1,12 +1,6 @@
-// enums1.rs
-//
-// No hints this time! ;)
-
-// I AM NOT DONE
-
#[derive(Debug)]
enum Message {
- // TODO: define a few types of messages as used below
+ // TODO: Define a few types of messages as used below.
}
fn main() {
diff --git a/exercises/08_enums/enums2.rs b/exercises/08_enums/enums2.rs
index df93fe0f..14aa29ad 100644
--- a/exercises/08_enums/enums2.rs
+++ b/exercises/08_enums/enums2.rs
@@ -1,13 +1,6 @@
-// enums2.rs
-//
-// Execute `rustlings hint enums2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
#[derive(Debug)]
enum Message {
- // TODO: define the different variants used below
+ // TODO: Define the different variants used below.
}
impl Message {
diff --git a/exercises/08_enums/enums3.rs b/exercises/08_enums/enums3.rs
index 92d18c46..7dd21715 100644
--- a/exercises/08_enums/enums3.rs
+++ b/exercises/08_enums/enums3.rs
@@ -1,14 +1,5 @@
-// enums3.rs
-//
-// Address all the TODOs to make the tests pass!
-//
-// Execute `rustlings hint enums3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
enum Message {
- // TODO: implement the message variant types based on their usage below
+ // TODO: Implement the message variant types based on their usage below.
}
struct Point {
@@ -33,20 +24,24 @@ impl State {
}
fn echo(&mut self, s: String) {
- self.message = s
+ self.message = s;
}
- fn move_position(&mut self, p: Point) {
- self.position = p;
+ fn move_position(&mut self, point: Point) {
+ self.position = point;
}
fn process(&mut self, message: Message) {
- // TODO: create a match expression to process the different message variants
+ // TODO: Create a match expression to process the different message variants.
// Remember: When passing a tuple as a function argument, you'll need extra parentheses:
- // fn function((t, u, p, l, e))
+ // e.g. `foo((t, u, p, l, e))`
}
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
@@ -57,8 +52,9 @@ mod tests {
quit: false,
position: Point { x: 0, y: 0 },
color: (0, 0, 0),
- message: "hello world".to_string(),
+ message: String::from("hello world"),
};
+
state.process(Message::ChangeColor(255, 0, 255));
state.process(Message::Echo(String::from("Hello world!")));
state.process(Message::Move(Point { x: 10, y: 15 }));
@@ -67,7 +63,7 @@ mod tests {
assert_eq!(state.color, (255, 0, 255));
assert_eq!(state.position.x, 10);
assert_eq!(state.position.y, 15);
- assert_eq!(state.quit, true);
+ assert!(state.quit);
assert_eq!(state.message, "Hello world!");
}
}
diff --git a/exercises/09_strings/strings1.rs b/exercises/09_strings/strings1.rs
index f50e1fa9..6abdbb48 100644
--- a/exercises/09_strings/strings1.rs
+++ b/exercises/09_strings/strings1.rs
@@ -1,17 +1,9 @@
-// strings1.rs
-//
-// Make me compile without changing the function signature!
-//
-// Execute `rustlings hint strings1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-fn main() {
- let answer = current_favorite_color();
- println!("My current favorite color is {}", answer);
-}
-
+// TODO: Fix the compiler error without changing the function signature.
fn current_favorite_color() -> String {
"blue"
}
+
+fn main() {
+ let answer = current_favorite_color();
+ println!("My current favorite color is {answer}");
+}
diff --git a/exercises/09_strings/strings2.rs b/exercises/09_strings/strings2.rs
index 4d95d16a..93d9cb6b 100644
--- a/exercises/09_strings/strings2.rs
+++ b/exercises/09_strings/strings2.rs
@@ -1,21 +1,14 @@
-// strings2.rs
-//
-// Make me compile without changing the function signature!
-//
-// Execute `rustlings hint strings2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// TODO: Fix the compiler error in the `main` function without changing this function.
+fn is_a_color_word(attempt: &str) -> bool {
+ attempt == "green" || attempt == "blue" || attempt == "red"
+}
fn main() {
- let word = String::from("green"); // Try not changing this line :)
+ let word = String::from("green"); // Don't change this line.
+
if is_a_color_word(word) {
println!("That is a color word I know!");
} else {
println!("That is not a color word I know.");
}
}
-
-fn is_a_color_word(attempt: &str) -> bool {
- attempt == "green" || attempt == "blue" || attempt == "red"
-}
diff --git a/exercises/09_strings/strings3.rs b/exercises/09_strings/strings3.rs
index 384e7ce3..39fce18c 100644
--- a/exercises/09_strings/strings3.rs
+++ b/exercises/09_strings/strings3.rs
@@ -1,23 +1,17 @@
-// strings3.rs
-//
-// Execute `rustlings hint strings3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
-fn trim_me(input: &str) -> String {
- // TODO: Remove whitespace from both ends of a string!
- ???
+fn trim_me(input: &str) -> &str {
+ // TODO: Remove whitespace from both ends of a string.
}
fn compose_me(input: &str) -> String {
- // TODO: Add " world!" to the string! There are multiple ways to do this!
- ???
+ // TODO: Add " world!" to the string! There are multiple ways to do this.
}
fn replace_me(input: &str) -> String {
- // TODO: Replace "cars" in the string with "balloons"!
- ???
+ // TODO: Replace "cars" in the string with "balloons".
+}
+
+fn main() {
+ // You can optionally experiment here.
}
#[cfg(test)]
@@ -39,7 +33,13 @@ mod tests {
#[test]
fn replace_a_string() {
- assert_eq!(replace_me("I think cars are cool"), "I think balloons are cool");
- assert_eq!(replace_me("I love to look at cars"), "I love to look at balloons");
+ assert_eq!(
+ replace_me("I think cars are cool"),
+ "I think balloons are cool",
+ );
+ assert_eq!(
+ replace_me("I love to look at cars"),
+ "I love to look at balloons",
+ );
}
}
diff --git a/exercises/09_strings/strings4.rs b/exercises/09_strings/strings4.rs
index e8c54acc..9d9eb480 100644
--- a/exercises/09_strings/strings4.rs
+++ b/exercises/09_strings/strings4.rs
@@ -1,30 +1,36 @@
-// strings4.rs
-//
-// Ok, here are a bunch of values-- some are `String`s, some are `&str`s. Your
-// task is to call one of these two functions on each value depending on what
-// you think each value is. That is, add either `string_slice` or `string`
-// before the parentheses on each line. If you're right, it will compile!
-//
-// No hints this time!
-
-// I AM NOT DONE
+// Calls of this function should be replaced with calls of `string_slice` or `string`.
+fn placeholder() {}
fn string_slice(arg: &str) {
- println!("{}", arg);
+ println!("{arg}");
}
fn string(arg: String) {
- println!("{}", arg);
+ println!("{arg}");
}
+// TODO: Here are a bunch of values - some are `String`, some are `&str`.
+// Your task is to replace `placeholder(…)` with either `string_slice(…)`
+// or `string(…)` depending on what you think each value is.
fn main() {
- ???("blue");
- ???("red".to_string());
- ???(String::from("hi"));
- ???("rust is fun!".to_owned());
- ???("nice weather".into());
- ???(format!("Interpolation {}", "Station"));
- ???(&String::from("abc")[0..1]);
- ???(" hello there ".trim());
- ???("Happy Monday!".to_string().replace("Mon", "Tues"));
- ???("mY sHiFt KeY iS sTiCkY".to_lowercase());
+ placeholder("blue");
+
+ placeholder("red".to_string());
+
+ placeholder(String::from("hi"));
+
+ placeholder("rust is fun!".to_owned());
+
+ placeholder("nice weather".into());
+
+ placeholder(format!("Interpolation {}", "Station"));
+
+ // WARNING: This is byte indexing, not character indexing.
+ // Character indexing can be done using `s.chars().nth(INDEX)`.
+ placeholder(&String::from("abc")[0..1]);
+
+ placeholder(" hello there ".trim());
+
+ placeholder("Happy Monday!".replace("Mon", "Tues"));
+
+ placeholder("mY sHiFt KeY iS sTiCkY".to_lowercase());
}
diff --git a/exercises/10_modules/modules1.rs b/exercises/10_modules/modules1.rs
index 9eb5a48b..d97ab23a 100644
--- a/exercises/10_modules/modules1.rs
+++ b/exercises/10_modules/modules1.rs
@@ -1,10 +1,4 @@
-// modules1.rs
-//
-// Execute `rustlings hint modules1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
+// TODO: Fix the compiler error about calling a private function.
mod sausage_factory {
// Don't let anybody outside of this module see this!
fn get_secret_recipe() -> String {
diff --git a/exercises/10_modules/modules2.rs b/exercises/10_modules/modules2.rs
index 04154543..782a70ea 100644
--- a/exercises/10_modules/modules2.rs
+++ b/exercises/10_modules/modules2.rs
@@ -1,27 +1,19 @@
-// modules2.rs
-//
// You can bring module paths into scopes and provide new names for them with
-// the 'use' and 'as' keywords. Fix these 'use' statements to make the code
-// compile.
-//
-// Execute `rustlings hint modules2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// the `use` and `as` keywords.
mod delicious_snacks {
- // TODO: Fix these use statements
- use self::fruits::PEAR as ???
- use self::veggies::CUCUMBER as ???
+ // TODO: Add the following two `use` statements after fixing them.
+ // use self::fruits::PEAR as ???;
+ // use self::veggies::CUCUMBER as ???;
mod fruits {
- pub const PEAR: &'static str = "Pear";
- pub const APPLE: &'static str = "Apple";
+ pub const PEAR: &str = "Pear";
+ pub const APPLE: &str = "Apple";
}
mod veggies {
- pub const CUCUMBER: &'static str = "Cucumber";
- pub const CARROT: &'static str = "Carrot";
+ pub const CUCUMBER: &str = "Cucumber";
+ pub const CARROT: &str = "Carrot";
}
}
@@ -29,6 +21,6 @@ fn main() {
println!(
"favorite snacks: {} and {}",
delicious_snacks::fruit,
- delicious_snacks::veggie
+ delicious_snacks::veggie,
);
}
diff --git a/exercises/10_modules/modules3.rs b/exercises/10_modules/modules3.rs
index f2bb0503..691608d2 100644
--- a/exercises/10_modules/modules3.rs
+++ b/exercises/10_modules/modules3.rs
@@ -1,17 +1,9 @@
-// modules3.rs
-//
-// You can use the 'use' keyword to bring module paths from modules from
-// anywhere and especially from the Rust standard library into your scope. Bring
-// SystemTime and UNIX_EPOCH from the std::time module. Bonus style points if
-// you can do it with one line!
-//
-// Execute `rustlings hint modules3` or use the `hint` watch subcommand for a
-// hint.
+// You can use the `use` keyword to bring module paths from modules from
+// anywhere and especially from the standard library into your scope.
-// I AM NOT DONE
-
-// TODO: Complete this use statement
-use ???
+// TODO: Bring `SystemTime` and `UNIX_EPOCH` from the `std::time` module into
+// your scope. Bonus style points if you can do it with one line!
+// use ???;
fn main() {
match SystemTime::now().duration_since(UNIX_EPOCH) {
diff --git a/exercises/11_hashmaps/hashmaps1.rs b/exercises/11_hashmaps/hashmaps1.rs
index 02f4725e..74001d04 100644
--- a/exercises/11_hashmaps/hashmaps1.rs
+++ b/exercises/11_hashmaps/hashmaps1.rs
@@ -1,31 +1,27 @@
-// hashmaps1.rs
-//
// A basket of fruits in the form of a hash map needs to be defined. The key
// represents the name of the fruit and the value represents how many of that
-// particular fruit is in the basket. You have to put at least three different
+// particular fruit is in the basket. You have to put at least 3 different
// types of fruits (e.g. apple, banana, mango) in the basket and the total count
-// of all the fruits should be at least five.
-//
-// Make me compile and pass the tests!
-//
-// Execute `rustlings hint hashmaps1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// of all the fruits should be at least 5.
use std::collections::HashMap;
fn fruit_basket() -> HashMap {
- let mut basket = // TODO: declare your hash map here.
+ // TODO: Declare the hash map.
+ // let mut basket =
// Two bananas are already given for you :)
basket.insert(String::from("banana"), 2);
- // TODO: Put more fruits in your basket here.
+ // TODO: Put more fruits in your basket.
basket
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
diff --git a/exercises/11_hashmaps/hashmaps2.rs b/exercises/11_hashmaps/hashmaps2.rs
index a5925690..b3691b68 100644
--- a/exercises/11_hashmaps/hashmaps2.rs
+++ b/exercises/11_hashmaps/hashmaps2.rs
@@ -1,5 +1,3 @@
-// hashmaps2.rs
-//
// We're collecting different fruits to bake a delicious fruit cake. For this,
// we have a basket, which we'll represent in the form of a hash map. The key
// represents the name of each fruit we collect and the value represents how
@@ -8,17 +6,10 @@
// must add fruit to the basket so that there is at least one of each kind and
// more than 11 in total - we have a lot of mouths to feed. You are not allowed
// to insert any more of these fruits!
-//
-// Make me pass the tests!
-//
-// Execute `rustlings hint hashmaps2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
use std::collections::HashMap;
-#[derive(Hash, PartialEq, Eq)]
+#[derive(Hash, PartialEq, Eq, Debug)]
enum Fruit {
Apple,
Banana,
@@ -28,7 +19,7 @@ enum Fruit {
}
fn fruit_basket(basket: &mut HashMap) {
- let fruit_kinds = vec![
+ let fruit_kinds = [
Fruit::Apple,
Fruit::Banana,
Fruit::Mango,
@@ -43,18 +34,18 @@ fn fruit_basket(basket: &mut HashMap) {
}
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
// Don't modify this function!
fn get_fruit_basket() -> HashMap {
- let mut basket = HashMap::::new();
- basket.insert(Fruit::Apple, 4);
- basket.insert(Fruit::Mango, 2);
- basket.insert(Fruit::Lychee, 5);
-
- basket
+ let content = [(Fruit::Apple, 4), (Fruit::Mango, 2), (Fruit::Lychee, 5)];
+ HashMap::from_iter(content)
}
#[test]
@@ -81,13 +72,25 @@ mod tests {
let count = basket.values().sum::();
assert!(count > 11);
}
-
+
#[test]
fn all_fruit_types_in_basket() {
+ let fruit_kinds = [
+ Fruit::Apple,
+ Fruit::Banana,
+ Fruit::Mango,
+ Fruit::Lychee,
+ Fruit::Pineapple,
+ ];
+
let mut basket = get_fruit_basket();
fruit_basket(&mut basket);
- for amount in basket.values() {
- assert_ne!(amount, &0);
+
+ for fruit_kind in fruit_kinds {
+ let Some(amount) = basket.get(&fruit_kind) else {
+ panic!("Fruit kind {fruit_kind:?} was not found in basket");
+ };
+ assert!(*amount > 0);
}
}
}
diff --git a/exercises/11_hashmaps/hashmaps3.rs b/exercises/11_hashmaps/hashmaps3.rs
index 8d9236df..9f8fdd78 100644
--- a/exercises/11_hashmaps/hashmaps3.rs
+++ b/exercises/11_hashmaps/hashmaps3.rs
@@ -1,87 +1,77 @@
-// hashmaps3.rs
-//
// A list of scores (one per line) of a soccer match is given. Each line is of
-// the form : ",,,"
-// Example: England,France,4,2 (England scored 4 goals, France 2).
+// the form ",,,"
+// Example: "England,France,4,2" (England scored 4 goals, France 2).
//
// You have to build a scores table containing the name of the team, the total
-// number of goals the team scored, and the total number of goals the team
-// conceded. One approach to build the scores table is to use a Hashmap.
-// The solution is partially written to use a Hashmap,
-// complete it to pass the test.
-//
-// Make me pass the tests!
-//
-// Execute `rustlings hint hashmaps3` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+// number of goals the team scored, and the total number of goals the team
+// conceded.
use std::collections::HashMap;
// A structure to store the goal details of a team.
+#[derive(Default)]
struct Team {
goals_scored: u8,
goals_conceded: u8,
}
-fn build_scores_table(results: String) -> HashMap {
+fn build_scores_table(results: &str) -> HashMap<&str, Team> {
// The name of the team is the key and its associated struct is the value.
- let mut scores: HashMap = HashMap::new();
+ let mut scores = HashMap::new();
- for r in results.lines() {
- let v: Vec<&str> = r.split(',').collect();
- let team_1_name = v[0].to_string();
- let team_1_score: u8 = v[2].parse().unwrap();
- let team_2_name = v[1].to_string();
- let team_2_score: u8 = v[3].parse().unwrap();
- // TODO: Populate the scores table with details extracted from the
- // current line. Keep in mind that goals scored by team_1
- // will be the number of goals conceded by team_2, and similarly
- // goals scored by team_2 will be the number of goals conceded by
- // team_1.
+ for line in results.lines() {
+ let mut split_iterator = line.split(',');
+ // NOTE: We use `unwrap` because we didn't deal with error handling yet.
+ let team_1_name = split_iterator.next().unwrap();
+ let team_2_name = split_iterator.next().unwrap();
+ let team_1_score: u8 = split_iterator.next().unwrap().parse().unwrap();
+ let team_2_score: u8 = split_iterator.next().unwrap().parse().unwrap();
+
+ // TODO: Populate the scores table with the extracted details.
+ // Keep in mind that goals scored by team 1 will be the number of goals
+ // conceded by team 2. Similarly, goals scored by team 2 will be the
+ // number of goals conceded by team 1.
}
+
scores
}
+fn main() {
+ // You can optionally experiment here.
+}
+
#[cfg(test)]
mod tests {
use super::*;
- fn get_results() -> String {
- let results = "".to_string()
- + "England,France,4,2\n"
- + "France,Italy,3,1\n"
- + "Poland,Spain,2,0\n"
- + "Germany,England,2,1\n";
- results
- }
+ const RESULTS: &str = "England,France,4,2
+France,Italy,3,1
+Poland,Spain,2,0
+Germany,England,2,1
+England,Spain,1,0";
#[test]
fn build_scores() {
- let scores = build_scores_table(get_results());
+ let scores = build_scores_table(RESULTS);
- let mut keys: Vec<&String> = scores.keys().collect();
- keys.sort();
- assert_eq!(
- keys,
- vec!["England", "France", "Germany", "Italy", "Poland", "Spain"]
- );
+ assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
+ .into_iter()
+ .all(|team_name| scores.contains_key(team_name)));
}
#[test]
fn validate_team_score_1() {
- let scores = build_scores_table(get_results());
+ let scores = build_scores_table(RESULTS);
let team = scores.get("England").unwrap();
- assert_eq!(team.goals_scored, 5);
+ assert_eq!(team.goals_scored, 6);
assert_eq!(team.goals_conceded, 4);
}
#[test]
fn validate_team_score_2() {
- let scores = build_scores_table(get_results());
+ let scores = build_scores_table(RESULTS);
let team = scores.get("Spain").unwrap();
assert_eq!(team.goals_scored, 0);
- assert_eq!(team.goals_conceded, 2);
+ assert_eq!(team.goals_conceded, 3);
}
}
diff --git a/exercises/12_options/options1.rs b/exercises/12_options/options1.rs
index 3cbfecd6..5009f8b6 100644
--- a/exercises/12_options/options1.rs
+++ b/exercises/12_options/options1.rs
@@ -1,25 +1,27 @@
-// options1.rs
-//
-// Execute `rustlings hint options1` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
-
// This function returns how much icecream there is left in the fridge.
-// If it's before 10PM, there's 5 scoops left. At 10PM, someone eats it
-// all, so there'll be no more left :(
-fn maybe_icecream(time_of_day: u16) -> Option {
- // We use the 24-hour system here, so 10PM is a value of 22 and 12AM is a
- // value of 0. The Option output should gracefully handle cases where
- // time_of_day > 23.
- // TODO: Complete the function body - remember to return an Option!
- ???
+// If it's before 22:00 (24-hour system), then 5 scoops are left. At 22:00,
+// someone eats it all, so no icecream is left (value 0). Return `None` if
+// `hour_of_day` is higher than 23.
+fn maybe_icecream(hour_of_day: u16) -> Option {
+ // TODO: Complete the function body.
+}
+
+fn main() {
+ // You can optionally experiment here.
}
#[cfg(test)]
mod tests {
use super::*;
+ #[test]
+ fn raw_value() {
+ // TODO: Fix this test. How do you get the value contained in the
+ // Option?
+ let icecreams = maybe_icecream(12);
+ assert_eq!(icecreams, 5);
+ }
+
#[test]
fn check_icecream() {
assert_eq!(maybe_icecream(0), Some(5));
@@ -27,14 +29,7 @@ mod tests {
assert_eq!(maybe_icecream(18), Some(5));
assert_eq!(maybe_icecream(22), Some(0));
assert_eq!(maybe_icecream(23), Some(0));
+ assert_eq!(maybe_icecream(24), None);
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);
- }
}
diff --git a/exercises/12_options/options2.rs b/exercises/12_options/options2.rs
index 4d998e7d..07c27c6e 100644
--- a/exercises/12_options/options2.rs
+++ b/exercises/12_options/options2.rs
@@ -1,9 +1,6 @@
-// options2.rs
-//
-// Execute `rustlings hint options2` or use the `hint` watch subcommand for a
-// hint.
-
-// I AM NOT DONE
+fn main() {
+ // You can optionally experiment here.
+}
#[cfg(test)]
mod tests {
@@ -12,7 +9,7 @@ mod tests {
let target = "rustlings";
let optional_target = Some(target);
- // TODO: Make this an if let statement whose value is "Some" type
+ // TODO: Make this an if-let statement whose value is `Some`.
word = optional_target {
assert_eq!(word, target);
}
@@ -23,15 +20,15 @@ mod tests {
let range = 10;
let mut optional_integers: Vec