diff --git a/.all-contributorsrc b/.all-contributorsrc
index 2b0ffeaf..9c39e5ec 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1902,6 +1902,150 @@
"contributions": [
"tool"
]
+ },
+ {
+ "login": "Nagidal",
+ "name": "Nagidal",
+ "avatar_url": "https://avatars.githubusercontent.com/u/7075397?v=4",
+ "profile": "https://github.com/Nagidal",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "adamhb123",
+ "name": "Adam Brewer",
+ "avatar_url": "https://avatars.githubusercontent.com/u/25161597?v=4",
+ "profile": "https://adabrew.com",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "eugkhp",
+ "name": "Eugene",
+ "avatar_url": "https://avatars.githubusercontent.com/u/25910599?v=4",
+ "profile": "https://github.com/eugkhp",
+ "contributions": [
+ "tool"
+ ]
+ },
+ {
+ "login": "navicore",
+ "name": "Ed Sweeney",
+ "avatar_url": "https://avatars.githubusercontent.com/u/110999?v=4",
+ "profile": "https://social.linux.pizza/@navicore",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "javihernant",
+ "name": "javihernant",
+ "avatar_url": "https://avatars.githubusercontent.com/u/73640929?v=4",
+ "profile": "https://github.com/javihernant",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "VegardMatthey",
+ "name": "Vegard",
+ "avatar_url": "https://avatars.githubusercontent.com/u/59250656?v=4",
+ "profile": "https://github.com/VegardMatthey",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "ryanwhitehouse",
+ "name": "Ryan Whitehouse",
+ "avatar_url": "https://avatars.githubusercontent.com/u/13400784?v=4",
+ "profile": "https://github.com/ryanwhitehouse",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "guoard",
+ "name": "Ali Afsharzadeh",
+ "avatar_url": "https://avatars.githubusercontent.com/u/65511355?v=4",
+ "profile": "https://github.com/guoard",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "keogami",
+ "name": "Keogami",
+ "avatar_url": "https://avatars.githubusercontent.com/u/41939011?v=4",
+ "profile": "http://keogami.ml",
+ "contributions": [
+ "doc"
+ ]
+ },
+ {
+ "login": "ahresse",
+ "name": "Alexandre Esse",
+ "avatar_url": "https://avatars.githubusercontent.com/u/28402488?v=4",
+ "profile": "https://github.com/ahresse",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "sagarvora",
+ "name": "Sagar Vora",
+ "avatar_url": "https://avatars.githubusercontent.com/u/16315650?v=4",
+ "profile": "https://resilient.tech",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "poneciak57",
+ "name": "Kacper Poneta",
+ "avatar_url": "https://avatars.githubusercontent.com/u/94321164?v=4",
+ "profile": "https://github.com/poneciak57",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "ktheory",
+ "name": "Aaron Suggs",
+ "avatar_url": "https://avatars.githubusercontent.com/u/975?v=4",
+ "profile": "https://ktheory.com/",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "alexwh",
+ "name": "Alex",
+ "avatar_url": "https://avatars.githubusercontent.com/u/1723612?v=4",
+ "profile": "https://github.com/alexwh",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "stornquist",
+ "name": "Sebastian Törnquist",
+ "avatar_url": "https://avatars.githubusercontent.com/u/42915664?v=4",
+ "profile": "https://github.com/stornquist",
+ "contributions": [
+ "content"
+ ]
+ },
+ {
+ "login": "smlavine",
+ "name": "Sebastian LaVine",
+ "avatar_url": "https://avatars.githubusercontent.com/u/33563640?v=4",
+ "profile": "http://smlavine.com",
+ "contributions": [
+ "code"
+ ]
}
],
"contributorsPerLine": 8,
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 00000000..67339d1b
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,18 @@
+name: Lint
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+ branches:
+ - main
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - uses: DavidAnson/markdownlint-cli2-action@v9
+ with:
+ globs: "exercises/**/*.md"
diff --git a/.markdownlint.yml b/.markdownlint.yml
new file mode 100644
index 00000000..d5f7e391
--- /dev/null
+++ b/.markdownlint.yml
@@ -0,0 +1,2 @@
+# MD013/line-length Line length, Expected: 80
+MD013: false
diff --git a/AUTHORS.md b/AUTHORS.md
index 54157fcd..f5accd79 100644
--- a/AUTHORS.md
+++ b/AUTHORS.md
@@ -270,6 +270,26 @@ authors.
 Nidhal Messaoudi 💻 |
 Mahdi Bahrami 🔧 |
+
+  Nagidal 🖋 |
+  Adam Brewer 🖋 |
+  Eugene 🔧 |
+  Ed Sweeney 🖋 |
+  javihernant 🖋 |
+  Vegard 🖋 |
+  Ryan Whitehouse 🖋 |
+  Ali Afsharzadeh 🖋 |
+
+
+  Keogami 📖 |
+  Alexandre Esse 🖋 |
+  Sagar Vora 🖋 |
+  Kacper Poneta 🖋 |
+  Aaron Suggs 🖋 |
+  Alex 🖋 |
+  Sebastian Törnquist 🖋 |
+  Sebastian LaVine 💻 |
+
diff --git a/Cargo.lock b/Cargo.lock
index 3d04953d..192a4ac0 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,18 +4,18 @@ version = 3
[[package]]
name = "aho-corasick"
-version = "0.7.18"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
[[package]]
name = "argh"
-version = "0.1.5"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e7317a549bc17c5278d9e72bb6e62c6aa801ac2567048e39ebc1c194249323e"
+checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e"
dependencies = [
"argh_derive",
"argh_shared",
@@ -23,22 +23,21 @@ dependencies = [
[[package]]
name = "argh_derive"
-version = "0.1.5"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60949c42375351e9442e354434b0cba2ac402c1237edf673cac3a4bf983b8d3c"
+checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6"
dependencies = [
"argh_shared",
- "heck",
"proc-macro2",
"quote",
- "syn",
+ "syn 1.0.109",
]
[[package]]
name = "argh_shared"
-version = "0.1.5"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a61eb019cb8f415d162cb9f12130ee6bbe9168b7d953c17f4ad049e4051ca00"
+checksum = "64cb94155d965e3d37ffbbe7cc5b82c3dd79dd33bd48e536f73d2cfb8d85506f"
[[package]]
name = "assert_cmd"
@@ -54,9 +53,9 @@ dependencies = [
[[package]]
name = "autocfg"
-version = "1.0.1"
+version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
+checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]]
name = "bitflags"
@@ -78,17 +77,15 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "console"
-version = "0.15.0"
+version = "0.15.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31"
+checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60"
dependencies = [
"encode_unicode",
+ "lazy_static",
"libc",
- "once_cell",
- "regex",
- "terminal_size",
"unicode-width",
- "winapi 0.3.9",
+ "windows-sys 0.42.0",
]
[[package]]
@@ -117,14 +114,14 @@ dependencies = [
[[package]]
name = "filetime"
-version = "0.2.15"
+version = "0.2.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98"
+checksum = "8a3de6e8d11b22ff9edc6d916f890800597d60f8b2da1caf2955c274638d6412"
dependencies = [
"cfg-if 1.0.0",
"libc",
"redox_syscall",
- "winapi 0.3.9",
+ "windows-sys 0.45.0",
]
[[package]]
@@ -173,24 +170,15 @@ checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
[[package]]
name = "glob"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
-
-[[package]]
-name = "heck"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
-dependencies = [
- "unicode-segmentation",
-]
+checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b"
[[package]]
name = "home"
-version = "0.5.3"
+version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2456aef2e6b6a9784192ae780c0f15bc57df0e918585282325e8c8ac27737654"
+checksum = "747309b4b440c06d57b0b25f2aee03ee9b5e5397d288c60e21fc709bb98a7408"
dependencies = [
"winapi 0.3.9",
]
@@ -238,9 +226,9 @@ dependencies = [
[[package]]
name = "itoa"
-version = "1.0.2"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d"
+checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "kernel32-sys"
@@ -266,24 +254,24 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
[[package]]
name = "libc"
-version = "0.2.100"
+version = "0.2.140"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
+checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
[[package]]
name = "log"
-version = "0.4.14"
+version = "0.4.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
+checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
dependencies = [
"cfg-if 1.0.0",
]
[[package]]
name = "memchr"
-version = "2.4.1"
+version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
+checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "mio"
@@ -330,9 +318,9 @@ dependencies = [
[[package]]
name = "net2"
-version = "0.2.37"
+version = "0.2.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae"
+checksum = "74d0df99cfcd2530b2e694f6e17e7f37b8e26bb23983ac530c0c97408837c631"
dependencies = [
"cfg-if 0.1.10",
"libc",
@@ -365,9 +353,9 @@ dependencies = [
[[package]]
name = "num-traits"
-version = "0.2.14"
+version = "0.2.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
+checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
dependencies = [
"autocfg",
]
@@ -378,12 +366,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
-[[package]]
-name = "once_cell"
-version = "1.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
-
[[package]]
name = "predicates"
version = "1.0.8"
@@ -399,52 +381,52 @@ dependencies = [
[[package]]
name = "predicates-core"
-version = "1.0.2"
+version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57e35a3326b75e49aa85f5dc6ec15b41108cf5aee58eabb1f274dd18b73c2451"
+checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174"
[[package]]
name = "predicates-tree"
-version = "1.0.3"
+version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d7dd0fd014130206c9352efbdc92be592751b2b9274dff685348341082c6ea3d"
+checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf"
dependencies = [
"predicates-core",
- "treeline",
+ "termtree",
]
[[package]]
name = "proc-macro2"
-version = "1.0.28"
+version = "1.0.53"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612"
+checksum = "ba466839c78239c09faf015484e5cc04860f88242cff4d03eb038f04b4699b73"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.9"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
[[package]]
name = "redox_syscall"
-version = "0.2.10"
+version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
+checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
dependencies = [
"bitflags",
]
[[package]]
name = "regex"
-version = "1.5.5"
+version = "1.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "cce168fea28d3e05f158bda4576cf0c844d5045bc2cc3620fa0292ed5bb5814c"
dependencies = [
"aho-corasick",
"memchr",
@@ -453,13 +435,13 @@ dependencies = [
[[package]]
name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "rustlings"
-version = "5.4.0"
+version = "5.4.1"
dependencies = [
"argh",
"assert_cmd",
@@ -477,9 +459,9 @@ dependencies = [
[[package]]
name = "ryu"
-version = "1.0.5"
+version = "1.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
+checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
[[package]]
name = "same-file"
@@ -492,29 +474,29 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.129"
+version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d1f72836d2aa753853178eda473a3b9d8e4eefdaf20523b919677e6de489f8f1"
+checksum = "771d4d9c4163ee138805e12c710dd365e4f44be8be0503cb1bb9eb989425d9c9"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.129"
+version = "1.0.158"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e57ae87ad533d9a56427558b516d0adac283614e347abf85b0dc0cbbf0a249f3"
+checksum = "e801c1712f48475582b7696ac71e0ca34ebb30e09338425384269d9717c62cad"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.8",
]
[[package]]
name = "serde_json"
-version = "1.0.81"
+version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c"
+checksum = "1c533a59c9d8a93a09c6ab31f0fd5e5f4dd1b8fc9434804029839884765d04ea"
dependencies = [
"itoa",
"ryu",
@@ -523,72 +505,69 @@ dependencies = [
[[package]]
name = "slab"
-version = "0.4.4"
+version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c307a32c1c5c437f38c7fd45d753050587732ba8628319fbdf12a7e289ccc590"
+checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+dependencies = [
+ "autocfg",
+]
[[package]]
name = "syn"
-version = "1.0.75"
+version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7f58f7e8eaa0009c5fec437aabf511bd9933e4b2d7407bd05273c01a8906ea7"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
-name = "terminal_size"
-version = "0.1.17"
+name = "syn"
+version = "2.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df"
+checksum = "bcc02725fd69ab9f26eab07fad303e2497fad6fb9eba4f96c4d1687bdf704ad9"
dependencies = [
- "libc",
- "winapi 0.3.9",
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
]
+[[package]]
+name = "termtree"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76"
+
[[package]]
name = "toml"
-version = "0.5.9"
+version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
dependencies = [
"serde",
]
[[package]]
-name = "treeline"
-version = "0.1.0"
+name = "unicode-ident"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
-
-[[package]]
-name = "unicode-segmentation"
-version = "1.8.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-width"
-version = "0.1.8"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3"
-
-[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "walkdir"
-version = "2.3.2"
+version = "2.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
+checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
dependencies = [
"same-file",
- "winapi 0.3.9",
"winapi-util",
]
@@ -635,6 +614,87 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+[[package]]
+name = "windows-sys"
+version = "0.42.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.42.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
+
[[package]]
name = "ws2_32-sys"
version = "0.2.1"
diff --git a/README.md b/README.md
index d16b7385..be470fdb 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,10 @@ Just run:
```bash
curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash
-# Or if you want it to be installed to a different path:
+```
+Or if you want it to be installed to a different path:
+
+```bash
curl -L https://raw.githubusercontent.com/rust-lang/rustlings/main/install.sh | bash -s mypath/
```
diff --git a/exercises/conversions/README.md b/exercises/conversions/README.md
index 8d7da93e..619a78c5 100644
--- a/exercises/conversions/README.md
+++ b/exercises/conversions/README.md
@@ -6,6 +6,7 @@ The simplest form of type conversion is a type cast expression. It is denoted wi
Rust also offers traits that facilitate type conversions upon implementation. These traits can be found under the [`convert`](https://doc.rust-lang.org/std/convert/index.html) module.
The traits are the following:
+
- `From` and `Into` covered in [`from_into`](from_into.rs)
- `TryFrom` and `TryInto` covered in [`try_from_into`](try_from_into.rs)
- `AsRef` and `AsMut` covered in [`as_ref_mut`](as_ref_mut.rs)
@@ -17,5 +18,6 @@ These should be the main ways ***within the standard library*** to convert data
## Further information
These are not directly covered in the book, but the standard library has a great documentation for it.
+
- [conversions](https://doc.rust-lang.org/std/convert/index.html)
-- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
\ No newline at end of file
+- [`FromStr` trait](https://doc.rust-lang.org/std/str/trait.FromStr.html)
diff --git a/exercises/error_handling/README.md b/exercises/error_handling/README.md
index 5255ace9..3b21f2b7 100644
--- a/exercises/error_handling/README.md
+++ b/exercises/error_handling/README.md
@@ -1,5 +1,6 @@
# Error handling
-Most errors aren’t serious enough to require the program to stop entirely.
+
+Most errors aren’t serious enough to require the program to stop entirely.
Sometimes, when a function fails, it’s for a reason that you can easily interpret and respond to.
For example, if you try to open a file and that operation fails because the file doesn’t exist, you might want to create the file instead of terminating the process.
diff --git a/exercises/error_handling/errors2.rs b/exercises/error_handling/errors2.rs
index 1cd8fc66..6971fcfb 100644
--- a/exercises/error_handling/errors2.rs
+++ b/exercises/error_handling/errors2.rs
@@ -2,7 +2,7 @@
// Say we're writing a game where you can buy items with tokens. All items cost
// 5 tokens, and whenever you purchase items there is a processing fee of 1
// token. A player of the game will type in how many items they want to buy,
-// and the `total_cost` function will calculate the total number of tokens.
+// and the `total_cost` function will calculate the total cost of the tokens.
// Since the player typed in the quantity, though, we get it as a string-- and
// they might have typed anything, not just numbers!
diff --git a/exercises/hashmaps/README.md b/exercises/hashmaps/README.md
index 30471cf9..80ec1441 100644
--- a/exercises/hashmaps/README.md
+++ b/exercises/hashmaps/README.md
@@ -1,6 +1,7 @@
# Hashmaps
+
A *hash map* allows you to associate a value with a particular key.
-You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
+You may also know this by the names [*unordered map* in C++](https://en.cppreference.com/w/cpp/container/unordered_map),
[*dictionary* in Python](https://docs.python.org/3/tutorial/datastructures.html#dictionaries) or an *associative array* in other languages.
This is the other data structure that we've been talking about before, when
diff --git a/exercises/hashmaps/hashmaps2.rs b/exercises/hashmaps/hashmaps2.rs
index 454b3e1d..a4f069a8 100644
--- a/exercises/hashmaps/hashmaps2.rs
+++ b/exercises/hashmaps/hashmaps2.rs
@@ -1,11 +1,13 @@
// hashmaps2.rs
-
-// A basket of fruits in the form of a hash map is given. 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 *MORE
-// THAN 11* fruits in the basket. Three types of fruits - Apple (4),
-// Mango (2) and Lychee (5) are already given in the basket. You are
-// not allowed to insert any more of these fruits!
+// 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 many of that particular fruit we have collected.
+// Three types of fruits - Apple (4), Mango (2) and Lychee (5) are already
+// in the basket hash map.
+// You 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!
//
@@ -34,8 +36,8 @@ fn fruit_basket(basket: &mut HashMap) {
];
for fruit in fruit_kinds {
- // TODO: Put new fruits if not already present. Note that you
- // are not allowed to put any type of fruit that's already
+ // TODO: Insert new fruits if they are not already present in the basket.
+ // Note that you are not allowed to put any type of fruit that's already
// present!
}
}
@@ -44,6 +46,7 @@ fn fruit_basket(basket: &mut HashMap) {
mod tests {
use super::*;
+ // Don't modify this function!
fn get_fruit_basket() -> HashMap {
let mut basket = HashMap::::new();
basket.insert(Fruit::Apple, 4);
diff --git a/exercises/iterators/iterators5.rs b/exercises/iterators/iterators5.rs
index 0593d123..87097956 100644
--- a/exercises/iterators/iterators5.rs
+++ b/exercises/iterators/iterators5.rs
@@ -2,13 +2,11 @@
// Let's define a simple model to track Rustlings exercise progress. Progress
// will be modelled using a hash map. The name of the exercise is the key and
// the progress is the value. Two counting functions were created to count the
-// number of exercises with a given progress. These counting functions use
-// imperative style for loops. Recreate this counting functionality using
-// iterators. Only the two iterator methods (count_iterator and
-// count_collection_iterator) need to be modified.
+// number of exercises with a given progress. Recreate this counting
+// functionality using iterators. Try not to use imperative loops (for, while).
+// Only the two iterator methods (count_iterator and count_collection_iterator)
+// need to be modified.
// Execute `rustlings hint iterators5` or use the `hint` watch subcommand for a hint.
-//
-// Make the code compile and the tests pass.
// I AM NOT DONE
diff --git a/exercises/lifetimes/README.md b/exercises/lifetimes/README.md
index 72befb3e..91373f73 100644
--- a/exercises/lifetimes/README.md
+++ b/exercises/lifetimes/README.md
@@ -3,15 +3,20 @@
Lifetimes tell the compiler how to check whether references live long
enough to be valid in any given situation. For example lifetimes say
"make sure parameter 'a' lives as long as parameter 'b' so that the return
-value is valid".
+value is valid".
-They are only necessary on borrows, i.e. references,
+They are only necessary on borrows, i.e. references,
since copied parameters or moves are owned in their scope and cannot
be referenced outside. Lifetimes mean that calling code of e.g. functions
-can be checked to make sure their arguments are valid. Lifetimes are
+can be checked to make sure their arguments are valid. Lifetimes are
restrictive of their callers.
+If you'd like to learn more about lifetime annotations, the
+[lifetimekata](https://tfpk.github.io/lifetimekata/) project
+has a similar style of exercises to Rustlings, but is all about
+learning to write lifetime annotations.
+
## Further information
-- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
- [Lifetimes (in Rust By Example)](https://doc.rust-lang.org/stable/rust-by-example/scope/lifetime.html)
+- [Validating References with Lifetimes](https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html)
diff --git a/exercises/macros/README.md b/exercises/macros/README.md
index e34bc3a8..337816d6 100644
--- a/exercises/macros/README.md
+++ b/exercises/macros/README.md
@@ -4,7 +4,7 @@ Rust's macro system is very powerful, but also kind of difficult to wrap your
head around. We're not going to teach you how to write your own fully-featured
macros. Instead, we'll show you how to use and create them.
-If you'd like to learn more about writing your own macros, the
+If you'd like to learn more about writing your own macros, the
[macrokata](https://github.com/tfpk/macrokata) project has a similar style
of exercises to Rustlings, but is all about learning to write Macros.
diff --git a/exercises/options/README.md b/exercises/options/README.md
index 6140a167..bdd33749 100644
--- a/exercises/options/README.md
+++ b/exercises/options/README.md
@@ -1,7 +1,8 @@
# Options
-Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
+Type Option represents an optional value: every Option is either Some and contains a value, or None, and does not.
Option types are very common in Rust code, as they have a number of uses:
+
- Initial values
- Return values for functions that are not defined over their entire input range (partial functions)
- Return value for otherwise reporting simple errors, where None is returned on error
diff --git a/exercises/smart_pointers/README.md b/exercises/smart_pointers/README.md
index c517ae31..d56d2b62 100644
--- a/exercises/smart_pointers/README.md
+++ b/exercises/smart_pointers/README.md
@@ -1,4 +1,5 @@
# Smart Pointers
+
In Rust, smart pointers are variables that contain an address in memory and reference some other data, but they also have additional metadata and capabilities.
Smart pointers in Rust often own the data they point to, while references only borrow data.
diff --git a/exercises/tests/tests4.rs b/exercises/tests/tests4.rs
new file mode 100644
index 00000000..1f34a2b2
--- /dev/null
+++ b/exercises/tests/tests4.rs
@@ -0,0 +1,45 @@
+// tests4.rs
+// Make sure that we're testing for the correct conditions!
+// Execute `rustlings hint tests4` or use the `hint` watch subcommand for a hint.
+
+// I AM NOT DONE
+
+struct Rectangle {
+ width: i32,
+ height: i32
+}
+
+impl Rectangle {
+ // Only change the test functions themselves
+ pub fn new(width: i32, height: i32) -> Self {
+ if width <= 0 || height <= 0 {
+ panic!("Rectangle width and height cannot be negative!")
+ }
+ Rectangle {width, height}
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn correct_width_and_height() {
+ // This test should check if the rectangle is the size that we pass into its constructor
+ let rect = Rectangle::new(10, 20);
+ assert_eq!(???, 10); // check width
+ assert_eq!(???, 20); // check height
+ }
+
+ #[test]
+ fn negative_width() {
+ // This test should check if program panics when we try to create rectangle with negative width
+ let _rect = Rectangle::new(-10, 10);
+ }
+
+ #[test]
+ fn negative_height() {
+ // This test should check if program panics when we try to create rectangle with negative height
+ let _rect = Rectangle::new(10, -10);
+ }
+}
diff --git a/exercises/threads/threads1.rs b/exercises/threads/threads1.rs
index d6376db2..ae124eeb 100644
--- a/exercises/threads/threads1.rs
+++ b/exercises/threads/threads1.rs
@@ -30,7 +30,7 @@ fn main() {
if results.len() != 10 {
panic!("Oh no! All the spawned threads did not finish!");
}
-
+
println!();
for (i, result) in results.into_iter().enumerate() {
println!("thread {} took {}ms", i, result);
diff --git a/exercises/traits/README.md b/exercises/traits/README.md
index de67acd0..ac87c64e 100644
--- a/exercises/traits/README.md
+++ b/exercises/traits/README.md
@@ -7,13 +7,13 @@ Data types can implement traits. To do so, the methods making up the trait are d
In this way, traits are somewhat similar to Java interfaces and C++ abstract classes.
Some additional common Rust traits include:
+
- `Clone` (the `clone` method)
- `Display` (which allows formatted display via `{}`)
- `Debug` (which allows formatted display via `{:?}`)
Because traits indicate shared behavior between data types, they are useful when writing generics.
-
## Further information
- [Traits](https://doc.rust-lang.org/book/ch10-02-traits.html)
diff --git a/exercises/variables/README.md b/exercises/variables/README.md
index 11a7a78a..7964ff29 100644
--- a/exercises/variables/README.md
+++ b/exercises/variables/README.md
@@ -2,7 +2,7 @@
In Rust, variables are immutable by default.
When a variable is immutable, once a value is bound to a name, you can’t change that value.
-You can make them mutable by adding mut in front of the variable name.
+You can make them mutable by adding `mut` in front of the variable name.
## Further information
diff --git a/exercises/vecs/vecs2.rs b/exercises/vecs/vecs2.rs
index aee6b4e0..073759e2 100644
--- a/exercises/vecs/vecs2.rs
+++ b/exercises/vecs/vecs2.rs
@@ -9,7 +9,7 @@
fn vec_loop(mut v: Vec) -> Vec {
- for i in v.iter_mut() {
+ for element in v.iter_mut() {
// TODO: Fill this up so that each element in the Vec `v` is
// multiplied by 2.
*i = *i * 2;
@@ -20,7 +20,7 @@ fn vec_loop(mut v: Vec) -> Vec {
}
fn vec_map(v: &Vec) -> Vec {
- v.iter().map(|num| {
+ v.iter().map(|element| {
// TODO: Do the same thing as above - but instead of mutating the
// Vec, you can just return the new number!
num * 2
diff --git a/info.toml b/info.toml
index 2f424033..28f9bb31 100644
--- a/info.toml
+++ b/info.toml
@@ -325,8 +325,7 @@ doing one step and then fixing the compiler errors that result!
So the end goal is to:
- get rid of the first line in main that creates the new vector
- so then `vec0` doesn't exist, so we can't pass it to `fill_vec`
- - we don't want to pass anything to `fill_vec`, so its signature should
- reflect that it does not take any arguments
+ - `fill_vec` has had its signature changed, which our call should reflect
- since we're not creating a new vec in `main` anymore, we need to create
a new vec in `fill_vec`, similarly to the way we did in `main`"""
@@ -439,7 +438,9 @@ mode = "compile"
hint = """
Yes, it would be really easy to fix this by just changing the value bound to `word` to be a
string slice instead of a `String`, wouldn't it?? There is a way to add one character to line
-9, though, that will coerce the `String` into a string slice."""
+9, though, that will coerce the `String` into a string slice.
+
+Side note: If you're interested in learning about how this kind of reference conversion works, you can jump ahead in the book and read this part in the smart pointers chapter: https://doc.rust-lang.org/stable/book/ch15-02-deref.html#implicit-deref-coercions-with-functions-and-methods"""
[[exercises]]
name = "strings3"
@@ -746,6 +747,33 @@ hint = """
To find the best solution to this challenge you're going to need to think back to your
knowledge of traits, specifically Trait Bound Syntax - you may also need this: `use std::fmt::Display;`."""
+# LIFETIMES
+
+[[exercises]]
+name = "lifetimes1"
+path = "exercises/lifetimes/lifetimes1.rs"
+mode = "compile"
+hint = """
+Let the compiler guide you. Also take a look at the book if you need help:
+https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html"""
+
+[[exercises]]
+name = "lifetimes2"
+path = "exercises/lifetimes/lifetimes2.rs"
+mode = "compile"
+hint = """
+Remember that the generic lifetime 'a will get the concrete lifetime that is equal to the smaller of the lifetimes of x and y.
+You can take at least two paths to achieve the desired result while keeping the inner block:
+1. Move the string2 declaration to make it live as long as string1 (how is result declared?)
+2. Move println! into the inner block"""
+
+[[exercises]]
+name = "lifetimes3"
+path = "exercises/lifetimes/lifetimes3.rs"
+mode = "compile"
+hint = """
+If you use a lifetime annotation in a struct's fields, where else does it need to be added?"""
+
# TESTS
[[exercises]]
@@ -778,32 +806,16 @@ You can call a function right where you're passing arguments to `assert!` -- so
something like `assert!(having_fun())`. If you want to check that you indeed get false, you
can negate the result of what you're doing using `!`, like `assert!(!having_fun())`."""
-# LIFETIMES
-
[[exercises]]
-name = "lifetimes1"
-path = "exercises/lifetimes/lifetimes1.rs"
-mode = "compile"
+name = "tests4"
+path = "exercises/tests/tests4.rs"
+mode = "test"
hint = """
-Let the compiler guide you. Also take a look at the book if you need help:
-https://doc.rust-lang.org/book/ch10-03-lifetime-syntax.html"""
+We expect method `Rectangle::new()` to panic for negative values.
+To handle that you need to add a special attribute to the test function.
+You can refer to the docs:
+https://doc.rust-lang.org/stable/book/ch11-01-writing-tests.html#checking-for-panics-with-should_panic"""
-[[exercises]]
-name = "lifetimes2"
-path = "exercises/lifetimes/lifetimes2.rs"
-mode = "compile"
-hint = """
-Remember that the generic lifetime 'a will get the concrete lifetime that is equal to the smaller of the lifetimes of x and y.
-You can take at least two paths to achieve the desired result while keeping the inner block:
-1. Move the string2 declaration to make it live as long as string1 (how is result declared?)
-2. Move println! into the inner block"""
-
-[[exercises]]
-name = "lifetimes3"
-path = "exercises/lifetimes/lifetimes3.rs"
-mode = "compile"
-hint = """
-If you use a lifetime annotation in a struct's fields, where else does it need to be added?"""
# STANDARD LIBRARY TYPES
@@ -842,7 +854,7 @@ Create an iterator from the slice. Transform the iterated values by applying
the `capitalize_first` function. Remember to collect the iterator.
Step 3.
-This is surprising similar to the previous solution. Collect is very powerful
+This is surprisingly similar to the previous solution. Collect is very powerful
and very general. Rust just needs to know the desired type."""
[[exercises]]
diff --git a/src/main.rs b/src/main.rs
index 312a0a12..793b826d 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -298,13 +298,21 @@ fn spawn_watch_shell(
println!("Bye!");
} else if input.eq("help") {
println!("Commands available to you in watch mode:");
- println!(" hint - prints the current exercise's hint");
- println!(" clear - clears the screen");
- println!(" quit - quits watch mode");
- println!(" help - displays this help message");
+ println!(" hint - prints the current exercise's hint");
+ println!(" clear - clears the screen");
+ println!(" quit - quits watch mode");
+ println!(" ! - executes a command, like `!rustc --explain E0381`");
+ println!(" help - displays this help message");
println!();
println!("Watch mode automatically re-evaluates the current exercise");
println!("when you edit a file's contents.")
+ } else if let Some(cmd) = input.strip_prefix('!') {
+ let parts: Vec<&str> = cmd.split_whitespace().collect();
+ if parts.is_empty() {
+ println!("no command provided");
+ } else if let Err(e) = Command::new(parts[0]).args(&parts[1..]).status() {
+ println!("failed to execute command `{}`: {}", cmd, e);
+ }
} else {
println!("unknown command: {input}");
}
@@ -433,8 +441,8 @@ started, here's a couple of notes about how Rustlings operates:
4. If an exercise doesn't make sense to you, feel free to open an issue on GitHub!
(https://github.com/rust-lang/rustlings/issues/new). We look at every issue,
and sometimes, other learners do too so you can help each other out!
-5. If you want to use `rust-analyzer` with exercises, which provides features like
- autocompletion, run the command `rustlings lsp`.
+5. If you want to use `rust-analyzer` with exercises, which provides features like
+ autocompletion, run the command `rustlings lsp`.
Got all that? Great! To get started, run `rustlings watch` in order to get the first
exercise. Make sure to have your editor open!"#;