mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-11 00:00:04 +03:00
Compare commits
No commits in common. "d9df809838191962a82e98ff01aaaa73950ba670" and "5e7afce019325226c7515fe9cb462dda2685f7a3" have entirely different histories.
d9df809838
...
5e7afce019
91
Cargo.lock
generated
91
Cargo.lock
generated
|
@ -31,48 +31,47 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.14"
|
version = "0.6.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b"
|
checksum = "d96bd03f33fe50a863e394ee9718a706f988b9079b20c3784fb726e7678b62fb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"anstyle-parse",
|
"anstyle-parse",
|
||||||
"anstyle-query",
|
"anstyle-query",
|
||||||
"anstyle-wincon",
|
"anstyle-wincon",
|
||||||
"colorchoice",
|
"colorchoice",
|
||||||
"is_terminal_polyfill",
|
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle"
|
name = "anstyle"
|
||||||
version = "1.0.7"
|
version = "1.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b"
|
checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-parse"
|
name = "anstyle-parse"
|
||||||
version = "0.2.4"
|
version = "0.2.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4"
|
checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"utf8parse",
|
"utf8parse",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-query"
|
name = "anstyle-query"
|
||||||
version = "1.0.3"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5"
|
checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstyle-wincon"
|
name = "anstyle-wincon"
|
||||||
version = "3.0.3"
|
version = "3.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19"
|
checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anstyle",
|
"anstyle",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
|
@ -80,9 +79,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyhow"
|
name = "anyhow"
|
||||||
version = "1.0.83"
|
version = "1.0.82"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3"
|
checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cmd"
|
name = "assert_cmd"
|
||||||
|
@ -101,9 +100,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.3.0"
|
version = "1.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
|
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
|
@ -191,9 +190,9 @@ checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "colorchoice"
|
name = "colorchoice"
|
||||||
version = "1.0.1"
|
version = "1.0.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422"
|
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "compact_str"
|
name = "compact_str"
|
||||||
|
@ -360,12 +359,6 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "is_terminal_polyfill"
|
|
||||||
version = "1.70.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itertools"
|
name = "itertools"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -403,9 +396,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.154"
|
version = "0.2.153"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346"
|
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "lock_api"
|
name = "lock_api"
|
||||||
|
@ -487,9 +480,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-traits"
|
name = "num-traits"
|
||||||
version = "0.2.19"
|
version = "0.2.18"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
|
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"autocfg",
|
"autocfg",
|
||||||
]
|
]
|
||||||
|
@ -535,9 +528,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "paste"
|
name = "paste"
|
||||||
version = "1.0.15"
|
version = "1.0.14"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
|
checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "predicates"
|
name = "predicates"
|
||||||
|
@ -571,9 +564,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro2"
|
name = "proc-macro2"
|
||||||
version = "1.0.82"
|
version = "1.0.81"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b"
|
checksum = "3d1597b0c024618f09a9c3b8655b7e430397a36d23fdafec26d6965e9eec3eba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"unicode-ident",
|
"unicode-ident",
|
||||||
]
|
]
|
||||||
|
@ -684,15 +677,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustversion"
|
name = "rustversion"
|
||||||
version = "1.0.16"
|
version = "1.0.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0"
|
checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.18"
|
version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
|
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "same-file"
|
name = "same-file"
|
||||||
|
@ -711,18 +704,18 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde"
|
name = "serde"
|
||||||
version = "1.0.201"
|
version = "1.0.199"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c"
|
checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"serde_derive",
|
"serde_derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_derive"
|
name = "serde_derive"
|
||||||
version = "1.0.201"
|
version = "1.0.199"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865"
|
checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -731,9 +724,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "serde_json"
|
name = "serde_json"
|
||||||
version = "1.0.117"
|
version = "1.0.116"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
|
checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa",
|
||||||
"ryu",
|
"ryu",
|
||||||
|
@ -831,9 +824,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "2.0.63"
|
version = "2.0.60"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704"
|
checksum = "909518bc7b1c9b779f1bbf07f2929d35af9f0f37e47c6e9ef7f9dddc1e1821f3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
@ -1095,27 +1088,27 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winnow"
|
name = "winnow"
|
||||||
version = "0.6.8"
|
version = "0.6.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d"
|
checksum = "14b9415ee827af173ebb3f15f9083df5a122eb93572ec28741fb153356ea2578"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy"
|
name = "zerocopy"
|
||||||
version = "0.7.34"
|
version = "0.7.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
|
checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"zerocopy-derive",
|
"zerocopy-derive",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zerocopy-derive"
|
name = "zerocopy-derive"
|
||||||
version = "0.7.34"
|
version = "0.7.32"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
|
checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
@ -47,7 +47,7 @@ include = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.83"
|
anyhow = "1.0.82"
|
||||||
clap = { version = "4.5.4", features = ["derive"] }
|
clap = { version = "4.5.4", features = ["derive"] }
|
||||||
crossterm = "0.27.0"
|
crossterm = "0.27.0"
|
||||||
hashbrown = "0.14.5"
|
hashbrown = "0.14.5"
|
||||||
|
@ -55,7 +55,7 @@ notify-debouncer-mini = { version = "0.4.1", default-features = false }
|
||||||
os_pipe = "1.1.5"
|
os_pipe = "1.1.5"
|
||||||
ratatui = { version = "0.26.2", default-features = false, features = ["crossterm"] }
|
ratatui = { version = "0.26.2", default-features = false, features = ["crossterm"] }
|
||||||
rustlings-macros = { path = "rustlings-macros", version = "=6.0.0-beta.6" }
|
rustlings-macros = { path = "rustlings-macros", version = "=6.0.0-beta.6" }
|
||||||
serde_json = "1.0.117"
|
serde_json = "1.0.116"
|
||||||
serde.workspace = true
|
serde.workspace = true
|
||||||
toml_edit.workspace = true
|
toml_edit.workspace = true
|
||||||
|
|
||||||
|
|
|
@ -25,28 +25,14 @@ pub fn include_files(_: TokenStream) -> TokenStream {
|
||||||
let solution_files = exercises
|
let solution_files = exercises
|
||||||
.iter()
|
.iter()
|
||||||
.map(|exercise| format!("../solutions/{}/{}.rs", exercise.dir, exercise.name));
|
.map(|exercise| format!("../solutions/{}/{}.rs", exercise.dir, exercise.name));
|
||||||
|
let dirs = exercises.iter().map(|exercise| &exercise.dir);
|
||||||
let mut dirs = Vec::with_capacity(32);
|
let readmes = exercises
|
||||||
let mut dir_inds = vec![0; exercises.len()];
|
|
||||||
|
|
||||||
for (exercise, dir_ind) in exercises.iter().zip(&mut dir_inds) {
|
|
||||||
// The directory is often the last one inserted.
|
|
||||||
if let Some(ind) = dirs.iter().rev().position(|dir| *dir == exercise.dir) {
|
|
||||||
*dir_ind = dirs.len() - 1 - ind;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
dirs.push(exercise.dir.as_str());
|
|
||||||
*dir_ind = dirs.len() - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
let readmes = dirs
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|dir| format!("../exercises/{dir}/README.md"));
|
.map(|exercise| format!("../exercises/{}/README.md", exercise.dir));
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
EmbeddedFiles {
|
EmbeddedFiles {
|
||||||
exercise_files: &[#(ExerciseFiles { exercise: include_bytes!(#exercise_files), solution: include_bytes!(#solution_files), dir_ind: #dir_inds }),*],
|
exercise_files: &[#(ExerciseFiles { exercise: include_bytes!(#exercise_files), solution: include_bytes!(#solution_files) }),*],
|
||||||
exercise_dirs: &[#(ExerciseDir { name: #dirs, readme: include_bytes!(#readmes) }),*]
|
exercise_dirs: &[#(ExerciseDir { name: #dirs, readme: include_bytes!(#readmes) }),*]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,12 +193,12 @@ impl AppState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_current_exercise_ind(&mut self, exercise_ind: usize) -> Result<()> {
|
pub fn set_current_exercise_ind(&mut self, ind: usize) -> Result<()> {
|
||||||
if exercise_ind >= self.exercises.len() {
|
if ind >= self.exercises.len() {
|
||||||
bail!(BAD_INDEX_ERR);
|
bail!(BAD_INDEX_ERR);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.current_exercise_ind = exercise_ind;
|
self.current_exercise_ind = ind;
|
||||||
|
|
||||||
self.write()
|
self.write()
|
||||||
}
|
}
|
||||||
|
@ -215,11 +215,8 @@ impl AppState {
|
||||||
self.write()
|
self.write()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_pending(&mut self, exercise_ind: usize) -> Result<()> {
|
pub fn set_pending(&mut self, ind: usize) -> Result<()> {
|
||||||
let exercise = self
|
let exercise = self.exercises.get_mut(ind).context(BAD_INDEX_ERR)?;
|
||||||
.exercises
|
|
||||||
.get_mut(exercise_ind)
|
|
||||||
.context(BAD_INDEX_ERR)?;
|
|
||||||
|
|
||||||
if exercise.done {
|
if exercise.done {
|
||||||
exercise.done = false;
|
exercise.done = false;
|
||||||
|
@ -232,10 +229,16 @@ impl AppState {
|
||||||
|
|
||||||
// Official exercises: Dump the original file from the binary.
|
// Official exercises: Dump the original file from the binary.
|
||||||
// Third-party exercises: Reset the exercise file with `git stash`.
|
// Third-party exercises: Reset the exercise file with `git stash`.
|
||||||
fn reset(&self, exercise_ind: usize, path: &str) -> Result<()> {
|
fn reset(&self, ind: usize, dir_name: Option<&str>, path: &str) -> Result<()> {
|
||||||
if self.official_exercises {
|
if self.official_exercises {
|
||||||
return EMBEDDED_FILES
|
return EMBEDDED_FILES
|
||||||
.write_exercise_to_disk(exercise_ind, path)
|
.write_exercise_to_disk(
|
||||||
|
ind,
|
||||||
|
dir_name.context(
|
||||||
|
"Official exercises must be nested in the `exercises` directory",
|
||||||
|
)?,
|
||||||
|
path,
|
||||||
|
)
|
||||||
.with_context(|| format!("Failed to reset the exercise {path}"));
|
.with_context(|| format!("Failed to reset the exercise {path}"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +265,7 @@ impl AppState {
|
||||||
pub fn reset_current_exercise(&mut self) -> Result<&'static str> {
|
pub fn reset_current_exercise(&mut self) -> Result<&'static str> {
|
||||||
self.set_pending(self.current_exercise_ind)?;
|
self.set_pending(self.current_exercise_ind)?;
|
||||||
let exercise = self.current_exercise();
|
let exercise = self.current_exercise();
|
||||||
self.reset(self.current_exercise_ind, exercise.path)?;
|
self.reset(self.current_exercise_ind, exercise.dir, exercise.path)?;
|
||||||
|
|
||||||
Ok(exercise.path)
|
Ok(exercise.path)
|
||||||
}
|
}
|
||||||
|
@ -274,7 +277,7 @@ impl AppState {
|
||||||
|
|
||||||
self.set_pending(exercise_ind)?;
|
self.set_pending(exercise_ind)?;
|
||||||
let exercise = &self.exercises[exercise_ind];
|
let exercise = &self.exercises[exercise_ind];
|
||||||
self.reset(exercise_ind, exercise.path)?;
|
self.reset(exercise_ind, exercise.dir, exercise.path)?;
|
||||||
|
|
||||||
Ok(exercise.path)
|
Ok(exercise.path)
|
||||||
}
|
}
|
||||||
|
@ -312,9 +315,18 @@ impl AppState {
|
||||||
let current_exercise = self.current_exercise();
|
let current_exercise = self.current_exercise();
|
||||||
|
|
||||||
if self.official_exercises {
|
if self.official_exercises {
|
||||||
EMBEDDED_FILES
|
let dir_name = current_exercise
|
||||||
.write_solution_to_disk(self.current_exercise_ind, current_exercise.name)
|
.dir
|
||||||
.map(Some)
|
.context("Official exercises must be nested in the `exercises` directory")?;
|
||||||
|
let solution_path = format!("solutions/{dir_name}/{}.rs", current_exercise.name);
|
||||||
|
|
||||||
|
EMBEDDED_FILES.write_solution_to_disk(
|
||||||
|
self.current_exercise_ind,
|
||||||
|
dir_name,
|
||||||
|
&solution_path,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(Some(solution_path))
|
||||||
} else {
|
} else {
|
||||||
let solution_path = if let Some(dir) = current_exercise.dir {
|
let solution_path = if let Some(dir) = current_exercise.dir {
|
||||||
format!("solutions/{dir}/{}.rs", current_exercise.name)
|
format!("solutions/{dir}/{}.rs", current_exercise.name)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use anyhow::{Context, Error, Result};
|
use anyhow::{bail, Context, Error, Result};
|
||||||
use std::{
|
use std::{
|
||||||
fs::{create_dir, create_dir_all, OpenOptions},
|
fs::{create_dir, create_dir_all, OpenOptions},
|
||||||
io::{self, Write},
|
io::{self, Write},
|
||||||
|
@ -25,16 +25,15 @@ impl WriteStrategy {
|
||||||
.open(path),
|
.open(path),
|
||||||
};
|
};
|
||||||
|
|
||||||
file.with_context(|| format!("Failed to open the file `{path}` in write mode"))?
|
file.context("Failed to open the file `{path}` in write mode")?
|
||||||
.write_all(content)
|
.write_all(content)
|
||||||
.with_context(|| format!("Failed to write the file {path}"))
|
.context("Failed to write the file {path}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExerciseFiles {
|
struct ExerciseFiles {
|
||||||
exercise: &'static [u8],
|
exercise: &'static [u8],
|
||||||
solution: &'static [u8],
|
solution: &'static [u8],
|
||||||
dir_ind: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ExerciseDir {
|
struct ExerciseDir {
|
||||||
|
@ -44,10 +43,11 @@ struct ExerciseDir {
|
||||||
|
|
||||||
impl ExerciseDir {
|
impl ExerciseDir {
|
||||||
fn init_on_disk(&self) -> Result<()> {
|
fn init_on_disk(&self) -> Result<()> {
|
||||||
// 20 = 10 + 10
|
let path_prefix = "exercises/";
|
||||||
// exercises/ + /README.md
|
let readme_path_postfix = "/README.md";
|
||||||
let mut dir_path = String::with_capacity(20 + self.name.len());
|
let mut dir_path =
|
||||||
dir_path.push_str("exercises/");
|
String::with_capacity(path_prefix.len() + self.name.len() + readme_path_postfix.len());
|
||||||
|
dir_path.push_str(path_prefix);
|
||||||
dir_path.push_str(self.name);
|
dir_path.push_str(self.name);
|
||||||
|
|
||||||
if let Err(e) = create_dir(&dir_path) {
|
if let Err(e) = create_dir(&dir_path) {
|
||||||
|
@ -60,9 +60,10 @@ impl ExerciseDir {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut readme_path = dir_path;
|
let readme_path = {
|
||||||
readme_path.push_str("/README.md");
|
dir_path.push_str(readme_path_postfix);
|
||||||
|
dir_path
|
||||||
|
};
|
||||||
WriteStrategy::Overwrite.write(&readme_path, self.readme)?;
|
WriteStrategy::Overwrite.write(&readme_path, self.readme)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -94,71 +95,30 @@ impl EmbeddedFiles {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write_exercise_to_disk(&self, exercise_ind: usize, path: &str) -> Result<()> {
|
pub fn write_exercise_to_disk(
|
||||||
let exercise_files = &EMBEDDED_FILES.exercise_files[exercise_ind];
|
&self,
|
||||||
let dir = &EMBEDDED_FILES.exercise_dirs[exercise_files.dir_ind];
|
exercise_ind: usize,
|
||||||
|
dir_name: &str,
|
||||||
|
path: &str,
|
||||||
|
) -> Result<()> {
|
||||||
|
let Some(dir) = self.exercise_dirs.iter().find(|dir| dir.name == dir_name) else {
|
||||||
|
bail!("`{dir_name}` not found in the embedded directories");
|
||||||
|
};
|
||||||
|
|
||||||
dir.init_on_disk()?;
|
dir.init_on_disk()?;
|
||||||
WriteStrategy::Overwrite.write(path, exercise_files.exercise)
|
WriteStrategy::Overwrite.write(path, self.exercise_files[exercise_ind].exercise)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write the solution file to disk and return its path.
|
|
||||||
pub fn write_solution_to_disk(
|
pub fn write_solution_to_disk(
|
||||||
&self,
|
&self,
|
||||||
exercise_ind: usize,
|
exercise_ind: usize,
|
||||||
exercise_name: &str,
|
dir_name: &str,
|
||||||
) -> Result<String> {
|
path: &str,
|
||||||
let exercise_files = &EMBEDDED_FILES.exercise_files[exercise_ind];
|
) -> Result<()> {
|
||||||
let dir = &EMBEDDED_FILES.exercise_dirs[exercise_files.dir_ind];
|
let dir_path = format!("solutions/{dir_name}");
|
||||||
|
|
||||||
// 14 = 10 + 1 + 3
|
|
||||||
// solutions/ + / + .rs
|
|
||||||
let mut dir_path = String::with_capacity(14 + dir.name.len() + exercise_name.len());
|
|
||||||
dir_path.push_str("solutions/");
|
|
||||||
dir_path.push_str(dir.name);
|
|
||||||
create_dir_all(&dir_path)
|
create_dir_all(&dir_path)
|
||||||
.with_context(|| format!("Failed to create the directory {dir_path}"))?;
|
.with_context(|| format!("Failed to create the directory {dir_path}"))?;
|
||||||
|
|
||||||
let mut solution_path = dir_path;
|
WriteStrategy::Overwrite.write(path, self.exercise_files[exercise_ind].solution)
|
||||||
solution_path.push('/');
|
|
||||||
solution_path.push_str(exercise_name);
|
|
||||||
solution_path.push_str(".rs");
|
|
||||||
|
|
||||||
WriteStrategy::Overwrite.write(&solution_path, exercise_files.solution)?;
|
|
||||||
|
|
||||||
Ok(solution_path)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct ExerciseInfo {
|
|
||||||
dir: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
|
||||||
struct InfoFile {
|
|
||||||
exercises: Vec<ExerciseInfo>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn dirs() {
|
|
||||||
let exercises = toml_edit::de::from_str::<InfoFile>(include_str!("../info.toml"))
|
|
||||||
.expect("Failed to parse `info.toml`")
|
|
||||||
.exercises;
|
|
||||||
|
|
||||||
assert_eq!(exercises.len(), EMBEDDED_FILES.exercise_files.len());
|
|
||||||
|
|
||||||
for (exercise, exercise_files) in exercises.iter().zip(EMBEDDED_FILES.exercise_files) {
|
|
||||||
assert_eq!(
|
|
||||||
exercise.dir,
|
|
||||||
EMBEDDED_FILES.exercise_dirs[exercise_files.dir_ind].name,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue