mirror of
https://github.com/rust-lang/rustlings.git
synced 2026-06-01 03:19:47 +09:00
Compare commits
52 Commits
v6.4.0
...
push-vpkvx
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b2b3005670 | ||
|
|
e73fff3bd4 | ||
|
|
8dff0df266 | ||
|
|
5ee7dfb5c2 | ||
|
|
9a3586878d | ||
|
|
a99433c62d | ||
|
|
e76ca5e2b9 | ||
|
|
48bab77609 | ||
|
|
a063bcfb4c | ||
|
|
c5f49cfa48 | ||
|
|
9bcd4198c5 | ||
|
|
29dc8ea9fa | ||
|
|
fa91814aa9 | ||
|
|
0b91db2195 | ||
|
|
7b2d42b0f0 | ||
|
|
bd3bdd620b | ||
|
|
8b4562e102 | ||
|
|
63d8986f2a | ||
|
|
ecaecc2f76 | ||
|
|
78194b4441 | ||
|
|
44699e9b1b | ||
|
|
9978c17d5f | ||
|
|
3cc7e0377c | ||
|
|
d2abc359cc | ||
|
|
7c0d269279 | ||
|
|
8db85946af | ||
|
|
7019f4d178 | ||
|
|
fcd77a83cc | ||
|
|
ae444eb3da | ||
|
|
425c9821e0 | ||
|
|
46c6fb2c82 | ||
|
|
374c3874af | ||
|
|
1eb6c1e469 | ||
|
|
06af3ffc99 | ||
|
|
65dc019fa6 | ||
|
|
a56ccb6f4f | ||
|
|
d9872f2615 | ||
|
|
298be671b9 | ||
|
|
fbfd4f25e7 | ||
|
|
d12735a573 | ||
|
|
1aec7c1152 | ||
|
|
0b55809bb9 | ||
|
|
bde6f7470c | ||
|
|
53ec59ed95 | ||
|
|
ed1ee38923 | ||
|
|
26cf4989a2 | ||
|
|
6e60f441e9 | ||
|
|
d07de879a7 | ||
|
|
dd0634c483 | ||
|
|
fc0cd8f0f8 | ||
|
|
d5cae8ff59 | ||
|
|
38016cb2d6 |
2
.cargo/config.toml
Normal file
2
.cargo/config.toml
Normal file
@@ -0,0 +1,2 @@
|
||||
[alias]
|
||||
dev = ["run", "--", "dev"]
|
||||
8
.github/workflows/rust.yml
vendored
8
.github/workflows/rust.yml
vendored
@@ -22,22 +22,22 @@ jobs:
|
||||
- uses: DavidAnson/markdownlint-cli2-action@v16
|
||||
with:
|
||||
globs: "exercises/**/*.md"
|
||||
- name: Run cargo fmt
|
||||
- name: rustfmt
|
||||
run: cargo fmt --all --check
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest, macOS-latest]
|
||||
os: [ubuntu-latest, windows-latest, macos-latest]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: swatinem/rust-cache@v2
|
||||
- name: Run cargo test
|
||||
- name: cargo test
|
||||
run: cargo test --workspace
|
||||
dev-check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: swatinem/rust-cache@v2
|
||||
- name: Run rustlings dev check
|
||||
- name: rustlings dev check
|
||||
run: cargo run -- dev check --require-solutions
|
||||
|
||||
@@ -1,3 +1,10 @@
|
||||
## Unreleased
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade to Rust edition 2024
|
||||
- Raise the minimum supported Rust version to `1.87`
|
||||
|
||||
<a name="6.4.0"></a>
|
||||
|
||||
## 6.4.0 (2024-11-11)
|
||||
|
||||
273
Cargo.lock
generated
273
Cargo.lock
generated
@@ -1,6 +1,6 @@
|
||||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
version = 4
|
||||
|
||||
[[package]]
|
||||
name = "anstream"
|
||||
@@ -43,19 +43,20 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "anstyle-wincon"
|
||||
version = "3.0.6"
|
||||
version = "3.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125"
|
||||
checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e"
|
||||
dependencies = [
|
||||
"anstyle",
|
||||
"once_cell",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.93"
|
||||
version = "1.0.98"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4c95c10ba0b00a02636238b814946408b1322d5ac4760326e6fb8ec956d85775"
|
||||
checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
@@ -71,9 +72,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.6.0"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
|
||||
checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
@@ -83,9 +84,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "4.5.20"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8"
|
||||
checksum = "ed93b9805f8ba930df42c2590f05453d5ec36cbb85d018868a5b24d31f6ac000"
|
||||
dependencies = [
|
||||
"clap_builder",
|
||||
"clap_derive",
|
||||
@@ -93,9 +94,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_builder"
|
||||
version = "4.5.20"
|
||||
version = "4.5.38"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54"
|
||||
checksum = "379026ff283facf611b0ea629334361c4211d1b12ee01024eec1591133b04120"
|
||||
dependencies = [
|
||||
"anstream",
|
||||
"anstyle",
|
||||
@@ -105,9 +106,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_derive"
|
||||
version = "4.5.18"
|
||||
version = "4.5.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab"
|
||||
checksum = "09176aae279615badda0765c0c0b3f6ed53f4709118af73cf4655d85d1530cd7"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
@@ -117,9 +118,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clap_lex"
|
||||
version = "0.7.2"
|
||||
version = "0.7.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97"
|
||||
checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6"
|
||||
|
||||
[[package]]
|
||||
name = "colorchoice"
|
||||
@@ -129,12 +130,13 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990"
|
||||
|
||||
[[package]]
|
||||
name = "crossterm"
|
||||
version = "0.28.1"
|
||||
version = "0.29.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6"
|
||||
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.1",
|
||||
"crossterm_winapi",
|
||||
"document-features",
|
||||
"mio",
|
||||
"parking_lot",
|
||||
"rustix",
|
||||
@@ -153,26 +155,35 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
name = "document-features"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
|
||||
checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d"
|
||||
dependencies = [
|
||||
"litrs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.9"
|
||||
version = "0.3.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
|
||||
checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.2.0"
|
||||
version = "2.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4"
|
||||
checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be"
|
||||
|
||||
[[package]]
|
||||
name = "filetime"
|
||||
@@ -196,10 +207,22 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.1"
|
||||
name = "getrandom"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3"
|
||||
checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"r-efi",
|
||||
"wasi 0.14.2+wasi-0.2.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.15.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84b26c544d002229e640969970a2e74021aadf6e2f96372b9c58eff97de08eb3"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -207,17 +230,11 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024"
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.6.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown",
|
||||
@@ -225,11 +242,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "inotify"
|
||||
version = "0.10.2"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fdd168d97690d0b8c412d6b6c10360277f4d7ee495c5d0d5d5fe0854923255cc"
|
||||
checksum = "f37dccff2791ab604f9babef0ba14fbe0be30bd368dc541e2b08d07c8aa908f3"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"bitflags 2.9.1",
|
||||
"inotify-sys",
|
||||
"libc",
|
||||
]
|
||||
@@ -243,15 +260,6 @@ 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.1"
|
||||
@@ -260,15 +268,15 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.11"
|
||||
version = "1.0.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
|
||||
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
|
||||
|
||||
[[package]]
|
||||
name = "kqueue"
|
||||
version = "1.0.8"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7447f1ca1b7b563588a205fe93dea8df60fd981423a768bc1c0ded35ed147d0c"
|
||||
checksum = "eac30106d7dce88daf4a3fcb4879ea939476d5074a9b7ddd0fb97fa4bed5596a"
|
||||
dependencies = [
|
||||
"kqueue-sys",
|
||||
"libc",
|
||||
@@ -286,9 +294,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.162"
|
||||
version = "0.2.172"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398"
|
||||
checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -296,16 +304,22 @@ version = "0.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.1",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.4.14"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "litrs"
|
||||
version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -319,9 +333,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.22"
|
||||
version = "0.4.27"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||
checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
@@ -331,24 +345,23 @@ checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.0.2"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec"
|
||||
checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify"
|
||||
version = "7.0.0"
|
||||
version = "8.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c533b4c39709f9ba5005d8002048266593c1cfaf3c5f0739d5b8ab0c6c504009"
|
||||
checksum = "2fee8403b3d66ac7b26aee6e40a897d85dc5ce26f44da36b8b73e987cc52e943"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.1",
|
||||
"filetime",
|
||||
"fsevent-sys",
|
||||
"inotify",
|
||||
@@ -358,33 +371,20 @@ dependencies = [
|
||||
"mio",
|
||||
"notify-types",
|
||||
"walkdir",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "notify-types"
|
||||
version = "1.0.0"
|
||||
version = "2.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7393c226621f817964ffb3dc5704f9509e107a8b024b489cc2c1b217378785df"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "os_pipe"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ffd2b0a5634335b135d5728d84c5e0fd726954b87111f7506a61c502280d982"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
@@ -411,42 +411,48 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.89"
|
||||
version = "1.0.95"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e"
|
||||
checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.37"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af"
|
||||
checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.7"
|
||||
name = "r-efi"
|
||||
version = "5.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f"
|
||||
checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5"
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.5.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "928fca9cf2aa042393a8325b9ead81d2f0df4cb12e1e24cef072922ccd99c5af"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.38.40"
|
||||
version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "99e4ea3e1cdc4b559b8e5650f9c8e5998e3e5c1343b4eaf034565f32318d63c0"
|
||||
checksum = "c71e83d6afe7ff64890ec6b71d6a69bb8a610ab78ce364b3352876bb4c801266"
|
||||
dependencies = [
|
||||
"bitflags 2.6.0",
|
||||
"bitflags 2.9.1",
|
||||
"errno",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.52.0",
|
||||
"windows-sys 0.59.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -457,7 +463,6 @@ dependencies = [
|
||||
"clap",
|
||||
"crossterm",
|
||||
"notify",
|
||||
"os_pipe",
|
||||
"rustix",
|
||||
"rustlings-macros",
|
||||
"serde",
|
||||
@@ -477,9 +482,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.18"
|
||||
version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
||||
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
|
||||
|
||||
[[package]]
|
||||
name = "same-file"
|
||||
@@ -498,18 +503,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.214"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5"
|
||||
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.214"
|
||||
version = "1.0.219"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766"
|
||||
checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -518,9 +523,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.132"
|
||||
version = "1.0.140"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03"
|
||||
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"memchr",
|
||||
@@ -539,9 +544,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook"
|
||||
version = "0.3.17"
|
||||
version = "0.3.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801"
|
||||
checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"signal-hook-registry",
|
||||
@@ -560,18 +565,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "signal-hook-registry"
|
||||
version = "1.4.2"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1"
|
||||
checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
version = "1.13.2"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
|
||||
checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
@@ -581,9 +586,9 @@ checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.87"
|
||||
version = "2.0.101"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d"
|
||||
checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -592,12 +597,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.14.0"
|
||||
version = "3.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c"
|
||||
checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"rustix",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -605,18 +610,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_datetime"
|
||||
version = "0.6.8"
|
||||
version = "0.6.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41"
|
||||
checksum = "3da5db5a963e24bc68be8b17b6fa82814bb22ee8660f192bb182771d498f09a3"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.22.22"
|
||||
version = "0.22.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5"
|
||||
checksum = "310068873db2c5b3e7659d2cc35d21855dbafa50d1ce336397c666e3cb08137e"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"serde",
|
||||
@@ -627,9 +632,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.13"
|
||||
version = "1.0.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe"
|
||||
checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
|
||||
|
||||
[[package]]
|
||||
name = "utf8parse"
|
||||
@@ -653,6 +658,15 @@ version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.14.2+wasi-0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3"
|
||||
dependencies = [
|
||||
"wit-bindgen-rt",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
@@ -768,9 +782,18 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.6.20"
|
||||
version = "0.7.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b"
|
||||
checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wit-bindgen-rt"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1"
|
||||
dependencies = [
|
||||
"bitflags 2.9.1",
|
||||
]
|
||||
|
||||
25
Cargo.toml
25
Cargo.toml
@@ -15,12 +15,12 @@ authors = [
|
||||
]
|
||||
repository = "https://github.com/rust-lang/rustlings"
|
||||
license = "MIT"
|
||||
edition = "2021" # On Update: Update the edition of the `rustfmt` command that checks the solutions.
|
||||
rust-version = "1.80"
|
||||
edition = "2024" # On Update: Update the edition of `rustfmt` in `dev check` and `CARGO_TOML` in `dev new`.
|
||||
rust-version = "1.87"
|
||||
|
||||
[workspace.dependencies]
|
||||
serde = { version = "1.0.214", features = ["derive"] }
|
||||
toml_edit = { version = "0.22.22", default-features = false, features = ["parse", "serde"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
toml_edit = { version = "0.22", default-features = false, features = ["parse", "serde"] }
|
||||
|
||||
[package]
|
||||
name = "rustlings"
|
||||
@@ -46,21 +46,20 @@ include = [
|
||||
]
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.93"
|
||||
clap = { version = "4.5.20", features = ["derive"] }
|
||||
crossterm = { version = "0.28.1", default-features = false, features = ["windows", "events"] }
|
||||
notify = "7.0.0"
|
||||
os_pipe = "1.2.1"
|
||||
anyhow = "1.0"
|
||||
clap = { version = "4.5", features = ["derive"] }
|
||||
crossterm = { version = "0.29", default-features = false, features = ["windows", "events"] }
|
||||
notify = "8.0"
|
||||
rustlings-macros = { path = "rustlings-macros", version = "=6.4.0" }
|
||||
serde_json = "1.0.132"
|
||||
serde_json = "1.0"
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
|
||||
[target.'cfg(not(windows))'.dependencies]
|
||||
rustix = { version = "0.38.38", default-features = false, features = ["std", "stdio", "termios"] }
|
||||
rustix = { version = "1.0", default-features = false, features = ["std", "stdio", "termios"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile = "3.14.0"
|
||||
tempfile = "3.19"
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
@@ -84,8 +83,6 @@ infinite_loop = "deny"
|
||||
mem_forget = "deny"
|
||||
dbg_macro = "warn"
|
||||
todo = "warn"
|
||||
# TODO: Remove after the following fix is released: https://github.com/rust-lang/rust-clippy/pull/13102
|
||||
needless_option_as_deref = "allow"
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
18
README.md
18
README.md
@@ -21,12 +21,13 @@ Before installing Rustlings, you need to have the **latest version of Rust** ins
|
||||
Visit [www.rust-lang.org/tools/install](https://www.rust-lang.org/tools/install) for further instructions on installing Rust.
|
||||
This will also install _Cargo_, Rust's package/project manager.
|
||||
|
||||
> 🐧 If you're on Linux, make sure you've installed `gcc` (for a linker).
|
||||
> 🐧 If you are on Linux, make sure you have installed `gcc` (for a linker).
|
||||
>
|
||||
> Deb: `sudo apt install gcc`.
|
||||
> Dnf: `sudo dnf install gcc`.
|
||||
> Deb: `sudo apt install gcc`
|
||||
>
|
||||
> Dnf: `sudo dnf install gcc`
|
||||
|
||||
> 🍎 If you're on MacOS, make sure you've installed Xcode and its developer tools by running `xcode-select --install`.
|
||||
> 🍎 If you are on MacOS, make sure you have installed Xcode and its developer tools by running `xcode-select --install`.
|
||||
|
||||
### Installing Rustlings
|
||||
|
||||
@@ -102,7 +103,7 @@ Ask for hints by entering `h` in the _watch mode_ 💡
|
||||
|
||||
### Watch Mode
|
||||
|
||||
After [initialization](#initialization), Rustlings can be launched by simply running the command `rustlings`.
|
||||
After the [initialization](#initialization), Rustlings can be launched by simply running the command `rustlings`.
|
||||
|
||||
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.
|
||||
@@ -137,7 +138,8 @@ If you need any help while doing the exercises and the builtin-hints aren't help
|
||||
Third-party exercises are a set of exercises maintained by the community.
|
||||
You can use the same `rustlings` program that you installed with `cargo install rustlings` to run them:
|
||||
|
||||
- [日本語版 Rustlings](https://github.com/sotanengel/rustlings-jp):A Japanese translation of the Rustlings exercises.
|
||||
- 🇯🇵 [Japanese Rustlings](https://github.com/sotanengel/rustlings-jp):A Japanese translation of the Rustlings exercises.
|
||||
- 🇨🇳 [Simplified Chinese Rustlings](https://github.com/SandmeyerX/rustlings-zh-cn): A simplified Chinese translation of the Rustlings 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?
|
||||
@@ -160,6 +162,4 @@ cargo uninstall rustlings
|
||||
|
||||
See [CONTRIBUTING.md](https://github.com/rust-lang/rustlings/blob/main/CONTRIBUTING.md) 🔗
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
Thanks to [all the wonderful contributors](https://github.com/rust-lang/rustlings/graphs/contributors) 🎉
|
||||
Thanks to [all the wonderful contributors](https://github.com/rust-lang/rustlings/graphs/contributors) ✨
|
||||
|
||||
5
build.rs
Normal file
5
build.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
fn main() {
|
||||
// Fix building from source on Windows because it can't handle file links.
|
||||
#[cfg(windows)]
|
||||
let _ = std::fs::copy("dev/Cargo.toml", "dev-Cargo.toml");
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
# Don't edit the `bin` list manually! It is updated by `cargo run -- dev update`. This comment line will be stripped in `rustlings init`.
|
||||
# Don't edit the `bin` list manually! It is updated by `cargo 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" },
|
||||
@@ -164,38 +164,45 @@ bin = [
|
||||
{ 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" },
|
||||
{ name = "async1", path = "../exercises/21_async/async1.rs" },
|
||||
{ name = "async1_sol", path = "../solutions/21_async/async1.rs" },
|
||||
{ name = "async2", path = "../exercises/21_async/async2.rs" },
|
||||
{ name = "async2_sol", path = "../solutions/21_async/async2.rs" },
|
||||
{ name = "macros1", path = "../exercises/22_macros/macros1.rs" },
|
||||
{ name = "macros1_sol", path = "../solutions/22_macros/macros1.rs" },
|
||||
{ name = "macros2", path = "../exercises/22_macros/macros2.rs" },
|
||||
{ name = "macros2_sol", path = "../solutions/22_macros/macros2.rs" },
|
||||
{ name = "macros3", path = "../exercises/22_macros/macros3.rs" },
|
||||
{ name = "macros3_sol", path = "../solutions/22_macros/macros3.rs" },
|
||||
{ name = "macros4", path = "../exercises/22_macros/macros4.rs" },
|
||||
{ name = "macros4_sol", path = "../solutions/22_macros/macros4.rs" },
|
||||
{ name = "clippy1", path = "../exercises/23_clippy/clippy1.rs" },
|
||||
{ name = "clippy1_sol", path = "../solutions/23_clippy/clippy1.rs" },
|
||||
{ name = "clippy2", path = "../exercises/23_clippy/clippy2.rs" },
|
||||
{ name = "clippy2_sol", path = "../solutions/23_clippy/clippy2.rs" },
|
||||
{ name = "clippy3", path = "../exercises/23_clippy/clippy3.rs" },
|
||||
{ name = "clippy3_sol", path = "../solutions/23_clippy/clippy3.rs" },
|
||||
{ name = "using_as", path = "../exercises/24_conversions/using_as.rs" },
|
||||
{ name = "using_as_sol", path = "../solutions/24_conversions/using_as.rs" },
|
||||
{ name = "from_into", path = "../exercises/24_conversions/from_into.rs" },
|
||||
{ name = "from_into_sol", path = "../solutions/24_conversions/from_into.rs" },
|
||||
{ name = "from_str", path = "../exercises/24_conversions/from_str.rs" },
|
||||
{ name = "from_str_sol", path = "../solutions/24_conversions/from_str.rs" },
|
||||
{ name = "try_from_into", path = "../exercises/24_conversions/try_from_into.rs" },
|
||||
{ name = "try_from_into_sol", path = "../solutions/24_conversions/try_from_into.rs" },
|
||||
{ name = "as_ref_mut", path = "../exercises/24_conversions/as_ref_mut.rs" },
|
||||
{ name = "as_ref_mut_sol", path = "../solutions/24_conversions/as_ref_mut.rs" },
|
||||
]
|
||||
|
||||
[package]
|
||||
name = "exercises"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
# Don't publish the exercises on crates.io!
|
||||
publish = false
|
||||
|
||||
[dependencies]
|
||||
tokio = { version = "1.45.0", features = ["rt-multi-thread", "macros"] }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Variables
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Further information
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn main() {
|
||||
let number = "T-H-R-E-E"; // Don't change this line
|
||||
println!("Spell a number: {}", number);
|
||||
println!("Spell a number: {number}");
|
||||
|
||||
// TODO: Fix the compiler error by changing the line below without renaming the variable.
|
||||
number = 3;
|
||||
|
||||
@@ -19,7 +19,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn yummy_food() {
|
||||
// This means that calling `picky_eater` with the argument "food" should return "Yummy!".
|
||||
// This means that calling `picky_eater` with the argument "strawberry" should return "Yummy!".
|
||||
assert_eq!(picky_eater("strawberry"), "Yummy!");
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Enums
|
||||
|
||||
Rust allows you to define types called "enums" which enumerate possible values.
|
||||
Enums are a feature in many languages, but their capabilities differ in each language. Rust’s enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
|
||||
Enums are a feature in many languages, but their capabilities differ in each language. Rust's enums are most similar to algebraic data types in functional languages, such as F#, OCaml, and Haskell.
|
||||
Useful in combination with enums is Rust's "pattern matching" facility, which makes it easy to run different code for different values of an enumeration.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Enums](https://doc.rust-lang.org/book/ch06-00-enums.html)
|
||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html)
|
||||
- [Pattern syntax](https://doc.rust-lang.org/book/ch19-03-pattern-syntax.html)
|
||||
|
||||
@@ -23,6 +23,7 @@ mod tests {
|
||||
assert_eq!(trim_me("Hello! "), "Hello!");
|
||||
assert_eq!(trim_me(" What's up!"), "What's up!");
|
||||
assert_eq!(trim_me(" Hola! "), "Hola!");
|
||||
assert_eq!(trim_me("Hi!"), "Hi!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
// This function returns how much icecream there is left in the fridge.
|
||||
// This function returns how much ice cream there is left in the fridge.
|
||||
// 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
|
||||
// someone eats it all, so no ice cream is left (value 0). Return `None` if
|
||||
// `hour_of_day` is higher than 23.
|
||||
fn maybe_icecream(hour_of_day: u16) -> Option<u16> {
|
||||
fn maybe_ice_cream(hour_of_day: u16) -> Option<u16> {
|
||||
// TODO: Complete the function body.
|
||||
}
|
||||
|
||||
@@ -18,19 +18,19 @@ mod tests {
|
||||
fn raw_value() {
|
||||
// TODO: Fix this test. How do you get the value contained in the
|
||||
// Option?
|
||||
let icecreams = maybe_icecream(12);
|
||||
let ice_creams = maybe_ice_cream(12);
|
||||
|
||||
assert_eq!(icecreams, 5); // Don't change this line.
|
||||
assert_eq!(ice_creams, 5); // Don't change this line.
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_icecream() {
|
||||
assert_eq!(maybe_icecream(0), Some(5));
|
||||
assert_eq!(maybe_icecream(9), Some(5));
|
||||
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);
|
||||
fn check_ice_cream() {
|
||||
assert_eq!(maybe_ice_cream(0), Some(5));
|
||||
assert_eq!(maybe_ice_cream(9), Some(5));
|
||||
assert_eq!(maybe_ice_cream(18), Some(5));
|
||||
assert_eq!(maybe_ice_cream(22), Some(0));
|
||||
assert_eq!(maybe_ice_cream(23), Some(0));
|
||||
assert_eq!(maybe_ice_cream(24), None);
|
||||
assert_eq!(maybe_ice_cream(25), None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ fn main() {
|
||||
|
||||
// TODO: Fix the compiler error by adding something to this match statement.
|
||||
match optional_point {
|
||||
Some(p) => println!("Co-ordinates are {},{}", p.x, p.y),
|
||||
Some(p) => println!("Coordinates are {},{}", p.x, p.y),
|
||||
_ => panic!("No match!"),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
# Error handling
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
## Further information
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
// In short, this particular use case for boxes is for when you want to own a
|
||||
// value and you care only that it is a type which implements a particular
|
||||
// trait. To do so, The `Box` is declared as of type `Box<dyn Trait>` where
|
||||
// trait. To do so, the `Box` is declared as of type `Box<dyn Trait>` where
|
||||
// `Trait` is the trait the compiler looks for on any value used in that
|
||||
// context. For this exercise, that context is the potential errors which
|
||||
// can be returned in a `Result`.
|
||||
|
||||
10
exercises/21_async/README.md
Normal file
10
exercises/21_async/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
# Async
|
||||
|
||||
Rust includes built-in support for asynchronous programming. In other languages, this might be known as Promises or
|
||||
Coroutines. async programming uses async functions, which are powerful, but may require some getting used to,
|
||||
especially if you haven't used something similar in another language.
|
||||
|
||||
The [relevant book chapter][1] is essential reading. The [tokio docs][2] are also very helpful!
|
||||
|
||||
[1]: https://doc.rust-lang.org/book/ch17-00-async-await.html
|
||||
[2]: https://tokio.rs/tokio/tutorial
|
||||
44
exercises/21_async/async1.rs
Normal file
44
exercises/21_async/async1.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
// Our loyal worker works hard to create a new number.
|
||||
#[derive(Default)]
|
||||
struct Worker;
|
||||
|
||||
struct NumberContainer {
|
||||
number: i32,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
async fn work(&self) -> NumberContainer {
|
||||
// Pretend this takes a while...
|
||||
let new_number = 32;
|
||||
NumberContainer { number: new_number }
|
||||
}
|
||||
}
|
||||
|
||||
impl NumberContainer {
|
||||
async fn extract_number(&self) -> i32 {
|
||||
// And this too...
|
||||
self.number
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Fix the function signature!
|
||||
fn run_worker() -> i32 {
|
||||
// TODO: Make our worker create a new number and return it.
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Feel free to experiment here. You may need to make some adjustments
|
||||
// to this function, though.
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Don't worry about this attribute for now.
|
||||
// If you want to know what this does, read the hint!
|
||||
#[tokio::test]
|
||||
async fn test_if_it_works() {
|
||||
let number = run_worker().await;
|
||||
assert_eq!(number, 32);
|
||||
}
|
||||
}
|
||||
42
exercises/21_async/async2.rs
Normal file
42
exercises/21_async/async2.rs
Normal file
@@ -0,0 +1,42 @@
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
// A MultiWorker can work with the power of 5 normal workers,
|
||||
// allowing us to create 5 new numbers at once!
|
||||
struct MultiWorker;
|
||||
|
||||
impl MultiWorker {
|
||||
async fn start_work(&self) -> JoinSet<i32> {
|
||||
let mut set = JoinSet::new();
|
||||
|
||||
for i in 30..35 {
|
||||
// TODO: `set.spawn` accepts an async function that will return the number
|
||||
// we want. Implement this function as a closure!
|
||||
set.spawn(???);
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_multi_worker() -> Vec<i32> {
|
||||
let tasks = MultiWorker.start_work().await;
|
||||
|
||||
// TODO: We have a bunch of tasks, how do we run them to completion
|
||||
// to get at the i32s they create?
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Feel free to experiment here. You may need to make some adjustments
|
||||
// to this function, though.
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_if_it_works() {
|
||||
let mut numbers = run_multi_worker().await;
|
||||
numbers.sort(); // in case tasks run out-of-order
|
||||
assert_eq!(numbers, vec![30, 31, 32, 33, 34]);
|
||||
}
|
||||
}
|
||||
@@ -10,5 +10,6 @@ of exercises to Rustlings, but is all about learning to write Macros.
|
||||
|
||||
## Further information
|
||||
|
||||
- [Macros](https://doc.rust-lang.org/book/ch19-06-macros.html)
|
||||
- [The Rust Book - Macros](https://doc.rust-lang.org/book/ch20-05-macros.html)
|
||||
- [The Little Book of Rust Macros](https://veykril.github.io/tlborm/)
|
||||
- [Rust by Example - macro_rules!](https://doc.rust-lang.org/rust-by-example/macros.html)
|
||||
@@ -4,9 +4,11 @@
|
||||
#[rustfmt::skip]
|
||||
#[allow(unused_variables, unused_assignments)]
|
||||
fn main() {
|
||||
let my_option: Option<()> = None;
|
||||
let my_option: Option<&str> = None;
|
||||
// Assume that you don't know the value of `my_option`.
|
||||
// In the case of `Some`, we want to print its value.
|
||||
if my_option.is_none() {
|
||||
println!("{:?}", my_option.unwrap());
|
||||
println!("{}", my_option.unwrap());
|
||||
}
|
||||
|
||||
let my_arr = &[
|
||||
@@ -22,6 +22,7 @@
|
||||
| iterators | §13.2-4 |
|
||||
| smart_pointers | §15, §16.3 |
|
||||
| threads | §16.1-3 |
|
||||
| async | §17 |
|
||||
| macros | §19.5 |
|
||||
| clippy | §21.4 |
|
||||
| conversions | n/a |
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"path_prefix": "rustlings"
|
||||
},
|
||||
"project": {
|
||||
"homepage": "https://rustlings.cool",
|
||||
"repository": "https://github.com/rust-lang/rustlings"
|
||||
|
||||
@@ -13,4 +13,4 @@ cargo test --workspace --all-targets
|
||||
cargo run -- dev check --require-solutions
|
||||
|
||||
# MSRV
|
||||
cargo +1.80 run -- dev check --require-solutions
|
||||
cargo +1.85 run -- dev check --require-solutions
|
||||
|
||||
@@ -16,7 +16,7 @@ include = [
|
||||
proc-macro = true
|
||||
|
||||
[dependencies]
|
||||
quote = "1.0.37"
|
||||
quote = "1.0"
|
||||
serde.workspace = true
|
||||
toml_edit.workspace = true
|
||||
|
||||
|
||||
@@ -764,7 +764,7 @@ Notice how the trait takes ownership of `self` and returns `Self`.
|
||||
|
||||
Although the signature of `append_bar` in the trait takes `self` as argument,
|
||||
the implementation can take `mut self` instead. This is possible because the
|
||||
the value is owned anyway."""
|
||||
value is owned anyway."""
|
||||
|
||||
[[exercises]]
|
||||
name = "traits3"
|
||||
@@ -1079,11 +1079,51 @@ original sending end.
|
||||
Related section in The Book:
|
||||
https://doc.rust-lang.org/book/ch16-02-message-passing.html"""
|
||||
|
||||
# ASYNC
|
||||
|
||||
[[exercises]]
|
||||
name = "async1"
|
||||
dir = "21_async"
|
||||
test = true
|
||||
hint = """
|
||||
Async functions are not the same as normal functions -- they have to be marked with a
|
||||
special bit of syntax, `async fn`. These functions don't immediately return or even
|
||||
execute, you have to encourage them to do so by calling another special bit of syntax
|
||||
on them.
|
||||
|
||||
Another thing - an async function can't be properly called in a normal function. Think of
|
||||
it as something contagious -- everything that it touches needs to be marked as such. Keeping
|
||||
that in mind, what adjustment do you need to make to the function signature?
|
||||
|
||||
Aside:
|
||||
`#[tokio::test]` (and `#[tokio::main]`) are "magic" attributes that automatically
|
||||
set up what we call an async runtime. The Rust compiler intentionally doesn't supply
|
||||
a default implementation of this runtime. Tokio is by far the most popular
|
||||
community-developed runtime, and this macro does a lot of the heavy lifting to let
|
||||
us use it.
|
||||
"""
|
||||
|
||||
[[exercises]]
|
||||
name = "async2"
|
||||
dir = "21_async"
|
||||
test = true
|
||||
hint = """
|
||||
Async functions can be used to run multiple things in parallel, or to more efficiently
|
||||
run things on multiple cores. Here, we use Tokio's tasks to schedule some work to run
|
||||
at the same time. We use a `JoinSet`, which is a list of tasks that lets us decide how
|
||||
to best execute them.
|
||||
|
||||
One of the ways to execute tasks is `JoinSet::join_all`, which even gives us a neat
|
||||
Vec that we can immediately return! You can also do this sequentially, with an iterator.
|
||||
See if you can also find a way to do it that doesn't use `JoinSet`! You have access to
|
||||
most of Tokio's task-based functionality here.
|
||||
"""
|
||||
|
||||
# MACROS
|
||||
|
||||
[[exercises]]
|
||||
name = "macros1"
|
||||
dir = "21_macros"
|
||||
dir = "22_macros"
|
||||
test = false
|
||||
hint = """
|
||||
When you call a macro, you need to add something special compared to a regular
|
||||
@@ -1091,7 +1131,7 @@ function call."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros2"
|
||||
dir = "21_macros"
|
||||
dir = "22_macros"
|
||||
test = false
|
||||
hint = """
|
||||
Macros don't quite play by the same rules as the rest of Rust, in terms of
|
||||
@@ -1102,7 +1142,7 @@ Unlike other things in Rust, the order of "where you define a macro" versus
|
||||
|
||||
[[exercises]]
|
||||
name = "macros3"
|
||||
dir = "21_macros"
|
||||
dir = "22_macros"
|
||||
test = false
|
||||
hint = """
|
||||
In order to use a macro outside of its module, you need to do something
|
||||
@@ -1110,7 +1150,7 @@ special to the module to lift the macro out into its parent."""
|
||||
|
||||
[[exercises]]
|
||||
name = "macros4"
|
||||
dir = "21_macros"
|
||||
dir = "22_macros"
|
||||
test = false
|
||||
hint = """
|
||||
You only need to add a single character to make this compile.
|
||||
@@ -1127,7 +1167,7 @@ https://veykril.github.io/tlborm/"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy1"
|
||||
dir = "22_clippy"
|
||||
dir = "23_clippy"
|
||||
test = false
|
||||
strict_clippy = true
|
||||
hint = """
|
||||
@@ -1144,7 +1184,7 @@ appropriate replacement constant from `std::f32::consts`."""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy2"
|
||||
dir = "22_clippy"
|
||||
dir = "23_clippy"
|
||||
test = false
|
||||
strict_clippy = true
|
||||
hint = """
|
||||
@@ -1157,7 +1197,7 @@ https://doc.rust-lang.org/std/option/#iterating-over-option"""
|
||||
|
||||
[[exercises]]
|
||||
name = "clippy3"
|
||||
dir = "22_clippy"
|
||||
dir = "23_clippy"
|
||||
test = false
|
||||
strict_clippy = true
|
||||
hint = "No hints this time!"
|
||||
@@ -1166,20 +1206,20 @@ hint = "No hints this time!"
|
||||
|
||||
[[exercises]]
|
||||
name = "using_as"
|
||||
dir = "23_conversions"
|
||||
dir = "24_conversions"
|
||||
hint = """
|
||||
Use the `as` operator to cast one of the operands in the last line of the
|
||||
`average` function into the expected return type."""
|
||||
|
||||
[[exercises]]
|
||||
name = "from_into"
|
||||
dir = "23_conversions"
|
||||
dir = "24_conversions"
|
||||
hint = """
|
||||
Follow the steps provided right before the `From` implementation."""
|
||||
|
||||
[[exercises]]
|
||||
name = "from_str"
|
||||
dir = "23_conversions"
|
||||
dir = "24_conversions"
|
||||
hint = """
|
||||
The implementation of `FromStr` should return an `Ok` with a `Person` object,
|
||||
or an `Err` with an error if the string is not valid.
|
||||
@@ -1196,7 +1236,7 @@ https://doc.rust-lang.org/stable/rust-by-example/error/multiple_error_types/reen
|
||||
|
||||
[[exercises]]
|
||||
name = "try_from_into"
|
||||
dir = "23_conversions"
|
||||
dir = "24_conversions"
|
||||
hint = """
|
||||
Is there an implementation of `TryFrom` in the standard library that can both do
|
||||
the required integer conversion and check the range of the input?
|
||||
@@ -1206,6 +1246,6 @@ types?"""
|
||||
|
||||
[[exercises]]
|
||||
name = "as_ref_mut"
|
||||
dir = "23_conversions"
|
||||
dir = "24_conversions"
|
||||
hint = """
|
||||
Add `AsRef<str>` or `AsMut<u32>` as a trait bound to the functions."""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
fn main() {
|
||||
let number = "T-H-R-E-E";
|
||||
println!("Spell a number: {}", number);
|
||||
println!("Spell a number: {number}");
|
||||
|
||||
// Using variable shadowing
|
||||
// https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
fn bigger(a: i32, b: i32) -> i32 {
|
||||
if a > b {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
}
|
||||
if a > b { a } else { b }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -4,8 +4,6 @@ fn main() {
|
||||
|
||||
#[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_semantics4() {
|
||||
let mut x = Vec::new();
|
||||
|
||||
@@ -26,6 +26,7 @@ mod tests {
|
||||
assert_eq!(trim_me("Hello! "), "Hello!");
|
||||
assert_eq!(trim_me(" What's up!"), "What's up!");
|
||||
assert_eq!(trim_me(" Hola! "), "Hola!");
|
||||
assert_eq!(trim_me("Hi!"), "Hi!");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -60,9 +60,11 @@ England,Spain,1,0";
|
||||
fn build_scores() {
|
||||
let scores = build_scores_table(RESULTS);
|
||||
|
||||
assert!(["England", "France", "Germany", "Italy", "Poland", "Spain"]
|
||||
.into_iter()
|
||||
.all(|team_name| scores.contains_key(team_name)));
|
||||
assert!(
|
||||
["England", "France", "Germany", "Italy", "Poland", "Spain"]
|
||||
.into_iter()
|
||||
.all(|team_name| scores.contains_key(team_name))
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -10,7 +10,7 @@ fn main() {
|
||||
// Solution 1: Matching over the `Option` (not `&Option`) but without moving
|
||||
// out of the `Some` variant.
|
||||
match optional_point {
|
||||
Some(ref p) => println!("Co-ordinates are {},{}", p.x, p.y),
|
||||
Some(ref p) => println!("Coordinates are {},{}", p.x, p.y),
|
||||
// ^^^ added
|
||||
_ => panic!("No match!"),
|
||||
}
|
||||
@@ -18,7 +18,8 @@ fn main() {
|
||||
// Solution 2: Matching over a reference (`&Option`) by added `&` before
|
||||
// `optional_point`.
|
||||
match &optional_point {
|
||||
Some(p) => println!("Co-ordinates are {},{}", p.x, p.y),
|
||||
//^ added
|
||||
Some(p) => println!("Coordinates are {},{}", p.x, p.y),
|
||||
_ => panic!("No match!"),
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
use std::num::ParseIntError;
|
||||
|
||||
#[allow(unused_variables)]
|
||||
#[allow(unused_variables, clippy::question_mark)]
|
||||
fn total_cost(item_quantity: &str) -> Result<i32, ParseIntError> {
|
||||
let processing_fee = 1;
|
||||
let cost_per_item = 5;
|
||||
|
||||
@@ -29,6 +29,21 @@ impl ParsePosNonzeroError {
|
||||
}
|
||||
}
|
||||
|
||||
// As an alternative solution, implementing the `From` trait allows for the
|
||||
// automatic conversion from a `ParseIntError` into a `ParsePosNonzeroError`
|
||||
// using the `?` operator, without the need to call `map_err`.
|
||||
//
|
||||
// ```
|
||||
// let x: i64 = s.parse()?;
|
||||
// ```
|
||||
//
|
||||
// Traits like `From` will be dealt with in later exercises.
|
||||
impl From<ParseIntError> for ParsePosNonzeroError {
|
||||
fn from(err: ParseIntError) -> Self {
|
||||
ParsePosNonzeroError::ParseInt(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
struct PositiveNonzeroInteger(u64);
|
||||
|
||||
|
||||
@@ -5,11 +5,7 @@
|
||||
|
||||
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
||||
// ^^^^ ^^ ^^ ^^
|
||||
if x.len() > y.len() {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
if x.len() > y.len() { x } else { y }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
|
||||
if x.len() > y.len() {
|
||||
x
|
||||
} else {
|
||||
y
|
||||
}
|
||||
if x.len() > y.len() { x } else { y }
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
||||
@@ -63,12 +63,10 @@ mod tests {
|
||||
println!("reference count = {}", Rc::strong_count(&sun)); // 7 references
|
||||
saturn.details();
|
||||
|
||||
// TODO
|
||||
let uranus = Planet::Uranus(Rc::clone(&sun));
|
||||
println!("reference count = {}", Rc::strong_count(&sun)); // 8 references
|
||||
uranus.details();
|
||||
|
||||
// TODO
|
||||
let neptune = Planet::Neptune(Rc::clone(&sun));
|
||||
println!("reference count = {}", Rc::strong_count(&sun)); // 9 references
|
||||
neptune.details();
|
||||
|
||||
45
solutions/21_async/async1.rs
Normal file
45
solutions/21_async/async1.rs
Normal file
@@ -0,0 +1,45 @@
|
||||
// Our loyal worker works hard to create a new number.
|
||||
#[derive(Default)]
|
||||
struct Worker;
|
||||
|
||||
struct NumberContainer {
|
||||
number: i32,
|
||||
}
|
||||
|
||||
impl Worker {
|
||||
async fn work(&self) -> NumberContainer {
|
||||
// Pretend this takes a while...
|
||||
let new_number = 32;
|
||||
NumberContainer { number: new_number }
|
||||
}
|
||||
}
|
||||
|
||||
impl NumberContainer {
|
||||
async fn extract_number(&self) -> i32 {
|
||||
// And this too...
|
||||
self.number
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_worker() -> i32 {
|
||||
// TODO: Make our worker create a new number and return it.
|
||||
Worker.work().await.extract_number().await
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Feel free to experiment here. You may need to make some adjustments
|
||||
// to this function, though.
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
// Don't worry about this attribute for now.
|
||||
// If you want to know what this does, read the hint!
|
||||
#[tokio::test]
|
||||
// TODO: Fix the test function signature
|
||||
fn test_if_it_works() {
|
||||
let number = run_worker().await;
|
||||
assert_eq!(number, 32);
|
||||
}
|
||||
}
|
||||
43
solutions/21_async/async2.rs
Normal file
43
solutions/21_async/async2.rs
Normal file
@@ -0,0 +1,43 @@
|
||||
use tokio::task::JoinSet;
|
||||
|
||||
// A MultiWorker can work with the power of 5 normal workers,
|
||||
// allowing us to create 5 new numbers at once!
|
||||
struct MultiWorker;
|
||||
|
||||
impl MultiWorker {
|
||||
async fn start_work(&self) -> JoinSet<i32> {
|
||||
let mut set = JoinSet::new();
|
||||
|
||||
for i in 30..35 {
|
||||
// TODO: `set.spawn` accepts an async function that will return the number
|
||||
// we want. Implement this function as a closure!
|
||||
set.spawn(async move { i });
|
||||
}
|
||||
|
||||
set
|
||||
}
|
||||
}
|
||||
|
||||
async fn run_multi_worker() -> Vec<i32> {
|
||||
let tasks = MultiWorker.start_work().await;
|
||||
|
||||
// TODO: We have a bunch of tasks, how do we run them to completion
|
||||
// to get at the i32s they create?
|
||||
tasks.join_all().await
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// Feel free to experiment here. You may need to make some adjustments
|
||||
// to this function, though.
|
||||
}
|
||||
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_if_it_works() {
|
||||
let mut numbers = run_multi_worker().await;
|
||||
numbers.sort(); // in case tasks run out-of-order
|
||||
assert_eq!(numbers, vec![30, 31, 32, 33, 34]);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@ use std::mem;
|
||||
#[rustfmt::skip]
|
||||
#[allow(unused_variables, unused_assignments)]
|
||||
fn main() {
|
||||
let my_option: Option<()> = None;
|
||||
let my_option: Option<&str> = None;
|
||||
// `unwrap` of an `Option` after checking if it is `None` will panic.
|
||||
// Use `if-let` instead.
|
||||
if let Some(value) = my_option {
|
||||
println!("{value:?}");
|
||||
println!("{value}");
|
||||
}
|
||||
|
||||
// A comma was missing.
|
||||
@@ -15,7 +15,7 @@ fn main() {
|
||||
-1, -2, -3,
|
||||
-4, -5, -6,
|
||||
];
|
||||
println!("My array! Here it is: {:?}", my_arr);
|
||||
println!("My array! Here it is: {my_arr:?}");
|
||||
|
||||
let mut my_empty_vec = vec![1, 2, 3, 4, 5];
|
||||
// `resize` mutates a vector instead of returning a new one.
|
||||
@@ -27,5 +27,5 @@ fn main() {
|
||||
let mut value_b = 66;
|
||||
// Use `mem::swap` to correctly swap two values.
|
||||
mem::swap(&mut value_a, &mut value_b);
|
||||
println!("value a: {}; value b: {}", value_a, value_b);
|
||||
println!("value a: {value_a}; value b: {value_b}");
|
||||
}
|
||||
@@ -62,8 +62,8 @@ mod tests {
|
||||
// Import `transformer`.
|
||||
use super::my_module::transformer;
|
||||
|
||||
use super::my_module::transformer_iter;
|
||||
use super::Command;
|
||||
use super::my_module::transformer_iter;
|
||||
|
||||
#[test]
|
||||
fn it_works() {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use anyhow::{bail, Context, Error, Result};
|
||||
use crossterm::{cursor, terminal, QueueableCommand};
|
||||
use anyhow::{Context, Error, Result, bail};
|
||||
use crossterm::{QueueableCommand, cursor, terminal};
|
||||
use std::{
|
||||
collections::HashSet,
|
||||
env,
|
||||
fs::{File, OpenOptions},
|
||||
io::{Read, Seek, StdoutLock, Write},
|
||||
path::{Path, MAIN_SEPARATOR_STR},
|
||||
path::{MAIN_SEPARATOR_STR, Path},
|
||||
process::{Command, Stdio},
|
||||
sync::{
|
||||
atomic::{AtomicUsize, Ordering::Relaxed},
|
||||
@@ -427,32 +427,34 @@ impl AppState {
|
||||
let next_exercise_ind = &next_exercise_ind;
|
||||
let slf = &self;
|
||||
thread::Builder::new()
|
||||
.spawn_scoped(s, move || loop {
|
||||
let exercise_ind = next_exercise_ind.fetch_add(1, Relaxed);
|
||||
let Some(exercise) = slf.exercises.get(exercise_ind) else {
|
||||
// No more exercises.
|
||||
break;
|
||||
};
|
||||
.spawn_scoped(s, move || {
|
||||
loop {
|
||||
let exercise_ind = next_exercise_ind.fetch_add(1, Relaxed);
|
||||
let Some(exercise) = slf.exercises.get(exercise_ind) else {
|
||||
// No more exercises.
|
||||
break;
|
||||
};
|
||||
|
||||
if exercise_progress_sender
|
||||
.send((exercise_ind, CheckProgress::Checking))
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
};
|
||||
if exercise_progress_sender
|
||||
.send((exercise_ind, CheckProgress::Checking))
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
};
|
||||
|
||||
let success = exercise.run_exercise(None, &slf.cmd_runner);
|
||||
let progress = match success {
|
||||
Ok(true) => CheckProgress::Done,
|
||||
Ok(false) => CheckProgress::Pending,
|
||||
Err(_) => CheckProgress::None,
|
||||
};
|
||||
let success = exercise.run_exercise(None, &slf.cmd_runner);
|
||||
let progress = match success {
|
||||
Ok(true) => CheckProgress::Done,
|
||||
Ok(false) => CheckProgress::Pending,
|
||||
Err(_) => CheckProgress::None,
|
||||
};
|
||||
|
||||
if exercise_progress_sender
|
||||
.send((exercise_ind, progress))
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
if exercise_progress_sender
|
||||
.send((exercise_ind, progress))
|
||||
.is_err()
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
})
|
||||
.context("Failed to spawn a thread to check all exercises")?;
|
||||
|
||||
@@ -74,13 +74,13 @@ pub fn updated_cargo_toml(
|
||||
let (bins_start_ind, bins_end_ind) = bins_start_end_ind(current_cargo_toml)?;
|
||||
|
||||
let mut updated_cargo_toml = Vec::with_capacity(BINS_BUFFER_CAPACITY);
|
||||
updated_cargo_toml.extend_from_slice(current_cargo_toml[..bins_start_ind].as_bytes());
|
||||
updated_cargo_toml.extend_from_slice(¤t_cargo_toml.as_bytes()[..bins_start_ind]);
|
||||
append_bins(
|
||||
&mut updated_cargo_toml,
|
||||
exercise_infos,
|
||||
exercise_path_prefix,
|
||||
);
|
||||
updated_cargo_toml.extend_from_slice(current_cargo_toml[bins_end_ind..].as_bytes());
|
||||
updated_cargo_toml.extend_from_slice(¤t_cargo_toml.as_bytes()[bins_end_ind..]);
|
||||
|
||||
Ok(updated_cargo_toml)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
io::Read,
|
||||
io::{Read, pipe},
|
||||
path::PathBuf,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
@@ -17,7 +17,7 @@ fn run_cmd(mut cmd: Command, description: &str, output: Option<&mut Vec<u8>>) ->
|
||||
};
|
||||
|
||||
let mut handle = if let Some(output) = output {
|
||||
let (mut reader, writer) = os_pipe::pipe().with_context(|| {
|
||||
let (mut reader, writer) = pipe().with_context(|| {
|
||||
format!("Failed to create a pipe to run the command `{description}``")
|
||||
})?;
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use clap::Subcommand;
|
||||
use std::path::PathBuf;
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use anyhow::{anyhow, bail, Context, Error, Result};
|
||||
use anyhow::{Context, Error, Result, anyhow, bail};
|
||||
use std::{
|
||||
cmp::Ordering,
|
||||
collections::HashSet,
|
||||
fs::{self, read_dir, OpenOptions},
|
||||
fs::{self, OpenOptions, read_dir},
|
||||
io::{self, Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
process::{Command, Stdio},
|
||||
@@ -10,11 +10,11 @@ use std::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
cargo_toml::{append_bins, bins_start_end_ind, BINS_BUFFER_CAPACITY},
|
||||
cmd::CmdRunner,
|
||||
exercise::{RunnableExercise, OUTPUT_CAPACITY},
|
||||
info_file::{ExerciseInfo, InfoFile},
|
||||
CURRENT_FORMAT_VERSION,
|
||||
cargo_toml::{BINS_BUFFER_CAPACITY, append_bins, bins_start_end_ind},
|
||||
cmd::CmdRunner,
|
||||
exercise::{OUTPUT_CAPACITY, RunnableExercise},
|
||||
info_file::{ExerciseInfo, InfoFile},
|
||||
};
|
||||
|
||||
const MAX_N_EXERCISES: usize = 999;
|
||||
@@ -42,10 +42,14 @@ fn check_cargo_toml(
|
||||
|
||||
if old_bins != new_bins {
|
||||
if cfg!(debug_assertions) {
|
||||
bail!("The file `dev/Cargo.toml` is outdated. Run `cargo run -- dev update` to update it. Then run `cargo run -- dev check` again");
|
||||
bail!(
|
||||
"The file `dev/Cargo.toml` is outdated. Run `cargo dev update` to update it. Then run `cargo run -- dev check` again"
|
||||
);
|
||||
}
|
||||
|
||||
bail!("The file `Cargo.toml` is outdated. Run `rustlings dev update` to update it. Then run `rustlings dev check` again");
|
||||
bail!(
|
||||
"The file `Cargo.toml` is outdated. Run `rustlings dev update` to update it. Then run `rustlings dev check` again"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -63,7 +67,9 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
||||
bail!("Found an empty exercise name in `info.toml`");
|
||||
}
|
||||
if name.len() > MAX_EXERCISE_NAME_LEN {
|
||||
bail!("The length of the exercise name `{name}` is bigger than the maximum {MAX_EXERCISE_NAME_LEN}");
|
||||
bail!(
|
||||
"The length of the exercise name `{name}` is bigger than the maximum {MAX_EXERCISE_NAME_LEN}"
|
||||
);
|
||||
}
|
||||
if let Some(c) = forbidden_char(name) {
|
||||
bail!("Char `{c}` in the exercise name `{name}` is not allowed");
|
||||
@@ -79,7 +85,9 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
||||
}
|
||||
|
||||
if exercise_info.hint.trim_ascii().is_empty() {
|
||||
bail!("The exercise `{name}` has an empty hint. Please provide a hint or at least tell the user why a hint isn't needed for this exercise");
|
||||
bail!(
|
||||
"The exercise `{name}` has an empty hint. Please provide a hint or at least tell the user why a hint isn't needed for this exercise"
|
||||
);
|
||||
}
|
||||
|
||||
if !names.insert(name) {
|
||||
@@ -96,20 +104,28 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
||||
.with_context(|| format!("Failed to read the file {path}"))?;
|
||||
|
||||
if !file_buf.contains("fn main()") {
|
||||
bail!("The `main` function is missing in the file `{path}`.\nCreate at least an empty `main` function to avoid language server errors");
|
||||
bail!(
|
||||
"The `main` function is missing in the file `{path}`.\nCreate at least an empty `main` function to avoid language server errors"
|
||||
);
|
||||
}
|
||||
|
||||
if !file_buf.contains("// TODO") {
|
||||
bail!("Didn't find any `// TODO` comment in the file `{path}`.\nYou need to have at least one such comment to guide the user.");
|
||||
bail!(
|
||||
"Didn't find any `// TODO` comment in the file `{path}`.\nYou need to have at least one such comment to guide the user."
|
||||
);
|
||||
}
|
||||
|
||||
let contains_tests = file_buf.contains("#[test]\n");
|
||||
if exercise_info.test {
|
||||
if !contains_tests {
|
||||
bail!("The file `{path}` doesn't contain any tests. If you don't want to add tests to this exercise, set `test = false` for this exercise in the `info.toml` file");
|
||||
bail!(
|
||||
"The file `{path}` doesn't contain any tests. If you don't want to add tests to this exercise, set `test = false` for this exercise in the `info.toml` file"
|
||||
);
|
||||
}
|
||||
} else if contains_tests {
|
||||
bail!("The file `{path}` contains tests annotated with `#[test]` but the exercise `{name}` has `test = false` in the `info.toml` file");
|
||||
bail!(
|
||||
"The file `{path}` contains tests annotated with `#[test]` but the exercise `{name}` has `test = false` in the `info.toml` file"
|
||||
);
|
||||
}
|
||||
|
||||
file_buf.clear();
|
||||
@@ -125,7 +141,10 @@ fn check_info_file_exercises(info_file: &InfoFile) -> Result<HashSet<PathBuf>> {
|
||||
// Only one level of directory nesting is allowed.
|
||||
fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> Result<()> {
|
||||
let unexpected_file = |path: &Path| {
|
||||
anyhow!("Found the file `{}`. Only `README.md` and Rust files related to an exercise in `info.toml` are allowed in the `{dir}` directory", path.display())
|
||||
anyhow!(
|
||||
"Found the file `{}`. Only `README.md` and Rust files related to an exercise in `info.toml` are allowed in the `{dir}` directory",
|
||||
path.display()
|
||||
)
|
||||
};
|
||||
|
||||
for entry in read_dir(dir).with_context(|| format!("Failed to open the `{dir}` directory"))? {
|
||||
@@ -154,7 +173,10 @@ fn check_unexpected_files(dir: &str, allowed_rust_files: &HashSet<PathBuf>) -> R
|
||||
let path = entry.path();
|
||||
|
||||
if !entry.file_type().unwrap().is_file() {
|
||||
bail!("Found `{}` but expected only files. Only one level of exercise nesting is allowed", path.display());
|
||||
bail!(
|
||||
"Found `{}` but expected only files. Only one level of exercise nesting is allowed",
|
||||
path.display()
|
||||
);
|
||||
}
|
||||
|
||||
let file_name = path.file_name().unwrap();
|
||||
@@ -224,8 +246,12 @@ fn check_exercises_unsolved(
|
||||
|
||||
fn check_exercises(info_file: &'static InfoFile, cmd_runner: &'static CmdRunner) -> Result<()> {
|
||||
match info_file.format_version.cmp(&CURRENT_FORMAT_VERSION) {
|
||||
Ordering::Less => bail!("`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\nPlease migrate to the latest format version"),
|
||||
Ordering::Greater => bail!("`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"),
|
||||
Ordering::Less => bail!(
|
||||
"`format_version` < {CURRENT_FORMAT_VERSION} (supported version)\nPlease migrate to the latest format version"
|
||||
),
|
||||
Ordering::Greater => bail!(
|
||||
"`format_version` > {CURRENT_FORMAT_VERSION} (supported version)\nTry updating the Rustlings program"
|
||||
),
|
||||
Ordering::Equal => (),
|
||||
}
|
||||
|
||||
@@ -287,7 +313,7 @@ fn check_solutions(
|
||||
fmt_cmd
|
||||
.arg("--check")
|
||||
.arg("--edition")
|
||||
.arg("2021")
|
||||
.arg("2024")
|
||||
.arg("--color")
|
||||
.arg("always")
|
||||
.stdin(Stdio::null());
|
||||
@@ -353,7 +379,7 @@ pub fn check(require_solutions: bool) -> Result<()> {
|
||||
}
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
// A hack to make `cargo run -- dev check` work when developing Rustlings.
|
||||
// A hack to make `cargo dev check` work when developing Rustlings.
|
||||
check_cargo_toml(&info_file.exercises, "dev/Cargo.toml", b"../")?;
|
||||
} else {
|
||||
check_cargo_toml(&info_file.exercises, "Cargo.toml", b"")?;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use std::{
|
||||
env::set_current_dir,
|
||||
fs::{self, create_dir},
|
||||
@@ -6,7 +6,7 @@ use std::{
|
||||
process::Command,
|
||||
};
|
||||
|
||||
use crate::{init::RUST_ANALYZER_TOML, CURRENT_FORMAT_VERSION};
|
||||
use crate::{CURRENT_FORMAT_VERSION, init::RUST_ANALYZER_TOML};
|
||||
|
||||
// Create a directory relative to the current directory and print its path.
|
||||
fn create_rel_dir(dir_name: &str, current_dir: &str) -> Result<()> {
|
||||
@@ -55,7 +55,9 @@ pub fn new(path: &Path, no_git: bool) -> Result<()> {
|
||||
write_rel_file(
|
||||
"info.toml",
|
||||
&dir_path_str,
|
||||
format!("{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"),
|
||||
format!(
|
||||
"{INFO_FILE_BEFORE_FORMAT_VERSION}{CURRENT_FORMAT_VERSION}{INFO_FILE_AFTER_FORMAT_VERSION}"
|
||||
),
|
||||
)?;
|
||||
|
||||
write_rel_file("Cargo.toml", &dir_path_str, CARGO_TOML)?;
|
||||
@@ -130,7 +132,7 @@ bin = []
|
||||
|
||||
[package]
|
||||
name = "exercises"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
# Don't publish the exercises on crates.io!
|
||||
publish = false
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ pub fn update() -> Result<()> {
|
||||
let info_file = InfoFile::parse()?;
|
||||
|
||||
if cfg!(debug_assertions) {
|
||||
// A hack to make `cargo run -- dev update` work when developing Rustlings.
|
||||
// A hack to make `cargo dev update` work when developing Rustlings.
|
||||
update_cargo_toml(&info_file.exercises, "dev/Cargo.toml", b"../")
|
||||
.context("Failed to update the file `dev/Cargo.toml`")?;
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||
QueueableCommand,
|
||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||
};
|
||||
use std::io::{self, StdoutLock, Write};
|
||||
|
||||
use crate::{
|
||||
cmd::CmdRunner,
|
||||
term::{self, terminal_file_link, write_ansi, CountedWrite},
|
||||
term::{self, CountedWrite, terminal_file_link, write_ansi},
|
||||
};
|
||||
|
||||
/// The initial capacity of the output buffer.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{bail, Context, Error, Result};
|
||||
use anyhow::{Context, Error, Result, bail};
|
||||
use serde::Deserialize;
|
||||
use std::{fs, io::ErrorKind};
|
||||
|
||||
|
||||
13
src/init.rs
13
src/init.rs
@@ -1,7 +1,7 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use crossterm::{
|
||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||
QueueableCommand,
|
||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use std::{
|
||||
@@ -57,7 +57,9 @@ pub fn init() -> Result<()> {
|
||||
if !workspace_manifest_content.contains("[workspace]\n")
|
||||
&& !workspace_manifest_content.contains("workspace.")
|
||||
{
|
||||
bail!("The current directory is already part of a Cargo project.\nPlease initialize Rustlings in a different directory");
|
||||
bail!(
|
||||
"The current directory is already part of a Cargo project.\nPlease initialize Rustlings in a different directory"
|
||||
);
|
||||
}
|
||||
|
||||
stdout.write_all(b"This command will create the directory `rustlings/` as a member of this Cargo workspace.\nPress ENTER to continue ")?;
|
||||
@@ -75,7 +77,9 @@ pub fn init() -> Result<()> {
|
||||
.stdout(Stdio::null())
|
||||
.status()?;
|
||||
if !status.success() {
|
||||
bail!("Failed to initialize a new Cargo workspace member.\nPlease initialize Rustlings in a different directory");
|
||||
bail!(
|
||||
"Failed to initialize a new Cargo workspace member.\nPlease initialize Rustlings in a different directory"
|
||||
);
|
||||
}
|
||||
|
||||
stdout.write_all(b"The directory `rustlings` has been added to `workspace.members` in the `Cargo.toml` file of this Cargo workspace.\n")?;
|
||||
@@ -174,6 +178,7 @@ const INIT_SOLUTION_FILE: &[u8] = b"fn main() {
|
||||
|
||||
pub const RUST_ANALYZER_TOML: &[u8] = br#"check.command = "clippy"
|
||||
check.extraArgs = ["--profile", "test"]
|
||||
cargo.targetDir = true
|
||||
"#;
|
||||
|
||||
const GITIGNORE: &[u8] = b"Cargo.lock
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::{
|
||||
cursor,
|
||||
QueueableCommand, cursor,
|
||||
event::{
|
||||
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind, MouseEventKind,
|
||||
},
|
||||
terminal::{
|
||||
disable_raw_mode, enable_raw_mode, DisableLineWrap, EnableLineWrap, EnterAlternateScreen,
|
||||
LeaveAlternateScreen,
|
||||
DisableLineWrap, EnableLineWrap, EnterAlternateScreen, LeaveAlternateScreen,
|
||||
disable_raw_mode, enable_raw_mode,
|
||||
},
|
||||
QueueableCommand,
|
||||
};
|
||||
use std::io::{self, StdoutLock, Write};
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::{
|
||||
QueueableCommand,
|
||||
cursor::{MoveTo, MoveToNextLine},
|
||||
style::{
|
||||
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
|
||||
},
|
||||
terminal::{self, BeginSynchronizedUpdate, Clear, ClearType, EndSynchronizedUpdate},
|
||||
QueueableCommand,
|
||||
};
|
||||
use std::{
|
||||
fmt::Write as _,
|
||||
@@ -15,7 +15,7 @@ use std::{
|
||||
use crate::{
|
||||
app_state::AppState,
|
||||
exercise::Exercise,
|
||||
term::{progress_bar, CountedWrite, MaxLenWriter},
|
||||
term::{CountedWrite, MaxLenWriter, progress_bar},
|
||||
};
|
||||
|
||||
use super::scroll_state::ScrollState;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use anyhow::{bail, Context, Result};
|
||||
use anyhow::{Context, Result, bail};
|
||||
use app_state::StateFileStatus;
|
||||
use clap::{Parser, Subcommand};
|
||||
use std::{
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use anyhow::Result;
|
||||
use crossterm::{
|
||||
style::{Color, ResetColor, SetForegroundColor},
|
||||
QueueableCommand,
|
||||
style::{Color, ResetColor, SetForegroundColor},
|
||||
};
|
||||
use std::{
|
||||
io::{self, Write},
|
||||
@@ -10,7 +10,7 @@ use std::{
|
||||
|
||||
use crate::{
|
||||
app_state::{AppState, ExercisesProgress},
|
||||
exercise::{solution_link_line, RunnableExercise, OUTPUT_CAPACITY},
|
||||
exercise::{OUTPUT_CAPACITY, RunnableExercise, solution_link_line},
|
||||
};
|
||||
|
||||
pub fn run(app_state: &mut AppState) -> Result<ExitCode> {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crossterm::{
|
||||
Command, QueueableCommand,
|
||||
cursor::MoveTo,
|
||||
style::{Attribute, Color, ResetColor, SetAttribute, SetForegroundColor},
|
||||
terminal::{Clear, ClearType},
|
||||
Command, QueueableCommand,
|
||||
};
|
||||
use std::{
|
||||
fmt, fs,
|
||||
|
||||
@@ -74,7 +74,9 @@ fn run_watch(
|
||||
|
||||
let mut watcher = RecommendedWatcher::new(
|
||||
notify_event_handler,
|
||||
Config::default().with_poll_interval(Duration::from_secs(1)),
|
||||
Config::default()
|
||||
.with_follow_symlinks(false)
|
||||
.with_poll_interval(Duration::from_secs(1)),
|
||||
)
|
||||
.inspect_err(|_| eprintln!("{NOTIFY_ERR}"))?;
|
||||
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
use anyhow::{Context, Result};
|
||||
use notify::{
|
||||
event::{AccessKind, AccessMode, MetadataKind, ModifyKind, RenameMode},
|
||||
Event, EventKind,
|
||||
event::{AccessKind, AccessMode, MetadataKind, ModifyKind, RenameMode},
|
||||
};
|
||||
use std::{
|
||||
sync::{
|
||||
atomic::Ordering::Relaxed,
|
||||
mpsc::{sync_channel, RecvTimeoutError, Sender, SyncSender},
|
||||
mpsc::{RecvTimeoutError, Sender, SyncSender, sync_channel},
|
||||
},
|
||||
thread,
|
||||
time::Duration,
|
||||
};
|
||||
|
||||
use super::{WatchEvent, EXERCISE_RUNNING};
|
||||
use super::{EXERCISE_RUNNING, WatchEvent};
|
||||
|
||||
const DEBOUNCE_DURATION: Duration = Duration::from_millis(200);
|
||||
|
||||
|
||||
@@ -1,24 +1,25 @@
|
||||
use anyhow::{Context, Result};
|
||||
use crossterm::{
|
||||
QueueableCommand,
|
||||
style::{
|
||||
Attribute, Attributes, Color, ResetColor, SetAttribute, SetAttributes, SetForegroundColor,
|
||||
},
|
||||
terminal, QueueableCommand,
|
||||
terminal,
|
||||
};
|
||||
use std::{
|
||||
io::{self, Read, StdoutLock, Write},
|
||||
sync::mpsc::{sync_channel, Sender, SyncSender},
|
||||
sync::mpsc::{Sender, SyncSender, sync_channel},
|
||||
thread,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
app_state::{AppState, ExercisesProgress},
|
||||
clear_terminal,
|
||||
exercise::{solution_link_line, RunnableExercise, OUTPUT_CAPACITY},
|
||||
exercise::{OUTPUT_CAPACITY, RunnableExercise, solution_link_line},
|
||||
term::progress_bar,
|
||||
};
|
||||
|
||||
use super::{terminal_event::terminal_event_handler, InputPauseGuard, WatchEvent};
|
||||
use super::{InputPauseGuard, WatchEvent, terminal_event::terminal_event_handler};
|
||||
|
||||
const HEADING_ATTRIBUTES: Attributes = Attributes::none()
|
||||
.with(Attribute::Bold)
|
||||
|
||||
@@ -4,7 +4,7 @@ use std::sync::{
|
||||
mpsc::{Receiver, Sender},
|
||||
};
|
||||
|
||||
use super::{WatchEvent, EXERCISE_RUNNING};
|
||||
use super::{EXERCISE_RUNNING, WatchEvent};
|
||||
|
||||
pub enum InputEvent {
|
||||
Next,
|
||||
|
||||
@@ -7,5 +7,5 @@ bin = [
|
||||
|
||||
[package]
|
||||
name = "test_exercises"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
publish = false
|
||||
|
||||
Reference in New Issue
Block a user