Compare commits

..

No commits in common. "d8c2ab8349854cbc7f4a994c7413d266cc38bc24" and "86684b7fc9dd5e8bedad6056565645d1d980925c" have entirely different histories.

116 changed files with 222 additions and 364 deletions

16
Cargo.lock generated
View file

@ -656,9 +656,9 @@ checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.34" version = "0.38.33"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" checksum = "e3cc72858054fcff6d7dea32df2aeaee6a7c24227366d7ea429aada2f26b16ad"
dependencies = [ dependencies = [
"bitflags 2.5.0", "bitflags 2.5.0",
"errno", "errno",
@ -669,7 +669,7 @@ dependencies = [
[[package]] [[package]]
name = "rustlings" name = "rustlings"
version = "6.0.0-beta.0" version = "6.0.0-alpha.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"assert_cmd", "assert_cmd",
@ -687,11 +687,9 @@ dependencies = [
[[package]] [[package]]
name = "rustlings-macros" name = "rustlings-macros"
version = "6.0.0-beta.0" version = "6.0.0-alpha.0"
dependencies = [ dependencies = [
"quote", "quote",
"serde",
"toml_edit",
] ]
[[package]] [[package]]
@ -954,11 +952,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]] [[package]]
name = "winapi-util" name = "winapi-util"
version = "0.1.7" version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "134306a13c5647ad6453e8deaec55d3a44d6021970129e6188735e74bf546697" checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "winapi",
] ]
[[package]] [[package]]

View file

@ -8,34 +8,23 @@ exclude = [
] ]
[workspace.package] [workspace.package]
version = "6.0.0-beta.0" version = "6.0.0-alpha.0"
authors = [ authors = [
"Liv <mokou@fastmail.com>", "Liv <mokou@fastmail.com>",
"Mo Bitar <mo8it@proton.me>",
# Alumni
"Carol (Nichols || Goulding) <carol.nichols@gmail.com>", "Carol (Nichols || Goulding) <carol.nichols@gmail.com>",
"Mo <mo8it@proton.me>",
] ]
repository = "https://github.com/rust-lang/rustlings"
license = "MIT" license = "MIT"
edition = "2021" edition = "2021"
[workspace.dependencies]
serde = { version = "1.0.198", features = ["derive"] }
toml_edit = { version = "0.22.12", default-features = false, features = ["parse", "serde"] }
[package] [package]
name = "rustlings" name = "rustlings"
description = "Small exercises to get you used to reading and writing Rust code!" description = "Small exercises to get you used to reading and writing Rust code!"
default-run = "rustlings" default-run = "rustlings"
version.workspace = true version.workspace = true
authors.workspace = true authors.workspace = true
repository.workspace = true
license.workspace = true license.workspace = true
edition.workspace = true edition.workspace = true
keywords = [
"exercise",
"learning",
]
include = [ include = [
"/exercises/", "/exercises/",
"/info.toml", "/info.toml",
@ -51,9 +40,9 @@ crossterm = "0.27.0"
hashbrown = "0.14.3" hashbrown = "0.14.3"
notify-debouncer-mini = "0.4.1" notify-debouncer-mini = "0.4.1"
ratatui = "0.26.2" ratatui = "0.26.2"
rustlings-macros = { path = "rustlings-macros", version = "6.0.0-beta.0" } rustlings-macros = { path = "rustlings-macros", version = "6.0.0-alpha.0" }
serde.workspace = true serde = { version = "1.0.198", features = ["derive"] }
toml_edit.workspace = true toml_edit = { version = "0.22.12", default-features = false, features = ["parse", "serde"] }
which = "6.0.1" which = "6.0.1"
[dev-dependencies] [dev-dependencies]

View file

@ -90,6 +90,11 @@ You can also get the hint for the next pending exercise with the following comma
rustlings hint rustlings hint
``` ```
## Quizzes
After every couple of sections, there will be a quiz that'll test your knowledge on a bunch of sections at once.
These quizzes are found in `exercises/quizN.rs`.
## Continuing On ## Continuing On
<!-- TODO: Mention third-party exercises --> <!-- TODO: Mention third-party exercises -->

View file

@ -7,4 +7,3 @@ Within your program, you can also have independent parts that run simultaneously
- [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html) - [Dining Philosophers example](https://doc.rust-lang.org/1.4.0/book/dining-philosophers.html)
- [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html) - [Using Threads to Run Code Simultaneously](https://doc.rust-lang.org/book/ch16-01-threads.html)
- [Using Message Passing to Transfer Data Between Threads](https://doc.rust-lang.org/book/ch16-02-message-passing.html)

View file

@ -1,3 +0,0 @@
# Quizzes
After every couple of sections, there will be a quiz in this directory that'll test your knowledge on a bunch of sections at once.

View file

@ -175,7 +175,10 @@ mode = "run"
hint = """ hint = """
The error message points to the function `sale_price` and says it expects a type The error message points to the function `sale_price` and says it expects a type
after the `->`. This is where the function's return type should be -- take a after the `->`. This is where the function's return type should be -- take a
look at the `is_even` function for an example!""" look at the `is_even` function for an example!
Also: Did you figure out that, technically, `u32` would be the more fitting type
for the inputs of the functions here, since the original prices shouldn't be negative? If so, kudos!"""
[[exercises]] [[exercises]]
name = "functions5" name = "functions5"
@ -233,7 +236,6 @@ Make sure the type is consistent across all arms."""
[[exercises]] [[exercises]]
name = "quiz1" name = "quiz1"
dir = "quizzes"
mode = "test" mode = "test"
hint = "No hints this time ;)" hint = "No hints this time ;)"
@ -635,7 +637,6 @@ Learn more at https://doc.rust-lang.org/book/ch08-03-hash-maps.html#updating-a-v
[[exercises]] [[exercises]]
name = "quiz2" name = "quiz2"
dir = "quizzes"
mode = "test" mode = "test"
hint = "No hints this time ;)" hint = "No hints this time ;)"
@ -869,7 +870,6 @@ See the documentation at: https://doc.rust-lang.org/book/ch10-02-traits.html#spe
[[exercises]] [[exercises]]
name = "quiz3" name = "quiz3"
dir = "quizzes"
mode = "test" mode = "test"
hint = """ hint = """
To find the best solution to this challenge you're going to need to think back To find the best solution to this challenge you're going to need to think back

View file

@ -1,9 +1,8 @@
[package] [package]
name = "rustlings-macros" name = "rustlings-macros"
description = "A macros crate intended to be used only by Rustlings" description = "A macros crate intended to be only used by rustlings"
version.workspace = true version.workspace = true
authors.workspace = true authors.workspace = true
repository.workspace = true
license.workspace = true license.workspace = true
edition.workspace = true edition.workspace = true
@ -12,5 +11,3 @@ proc-macro = true
[dependencies] [dependencies]
quote = "1.0.36" quote = "1.0.36"
serde.workspace = true
toml_edit.workspace = true

View file

@ -1,39 +1,86 @@
use proc_macro::TokenStream; use proc_macro::TokenStream;
use quote::quote; use quote::quote;
use serde::Deserialize; use std::{fs::read_dir, panic, path::PathBuf};
#[derive(Deserialize)] fn path_to_string(path: PathBuf) -> String {
struct ExerciseInfo { path.into_os_string()
name: String, .into_string()
dir: String, .unwrap_or_else(|original| {
} panic!("The path {} is invalid UTF8", original.to_string_lossy());
})
#[derive(Deserialize)]
struct InfoFile {
exercises: Vec<ExerciseInfo>,
} }
#[proc_macro] #[proc_macro]
pub fn include_files(_: TokenStream) -> TokenStream { pub fn include_files(_: TokenStream) -> TokenStream {
let exercises = toml_edit::de::from_str::<InfoFile>(include_str!("../../info.toml")) let mut files = Vec::with_capacity(8);
.expect("Failed to parse `info.toml`") let mut dirs = Vec::with_capacity(128);
.exercises;
let exercise_files = exercises for entry in read_dir("exercises").expect("Failed to open the `exercises` directory") {
.iter() let entry = entry.expect("Failed to read the `exercises` directory");
.map(|exercise| format!("../exercises/{}/{}.rs", exercise.dir, exercise.name));
let solution_files = exercises if entry.file_type().unwrap().is_file() {
.iter() let path = entry.path();
.map(|exercise| format!("../solutions/{}/{}.rs", exercise.dir, exercise.name)); if path.file_name().unwrap() != "README.md" {
let dirs = exercises.iter().map(|exercise| &exercise.dir); files.push(path_to_string(path));
let readmes = exercises }
.iter()
.map(|exercise| format!("../exercises/{}/README.md", exercise.dir)); continue;
}
let dir_path = entry.path();
let dir_files = read_dir(&dir_path).unwrap_or_else(|e| {
panic!("Failed to open the directory {}: {e}", dir_path.display());
});
let dir_path = path_to_string(dir_path);
let dir_files = dir_files.filter_map(|entry| {
let entry = entry.unwrap_or_else(|e| {
panic!("Failed to read the directory {dir_path}: {e}");
});
let path = entry.path();
if !entry.file_type().unwrap().is_file() {
panic!("Found {} but expected only files", path.display());
}
if path.file_name().unwrap() == "README.md" {
return None;
}
Some(path_to_string(path))
});
dirs.push(quote! {
EmbeddedFlatDir {
path: #dir_path,
readme: EmbeddedFile {
path: ::std::concat!(#dir_path, "/README.md"),
content: ::std::include_bytes!(::std::concat!("../", #dir_path, "/README.md")),
},
content: &[
#(EmbeddedFile {
path: #dir_files,
content: ::std::include_bytes!(::std::concat!("../", #dir_files)),
}),*
],
}
});
}
quote! { quote! {
EmbeddedFiles { EmbeddedFiles {
exercise_files: &[#(ExerciseFiles { exercise: include_bytes!(#exercise_files), solution: include_bytes!(#solution_files) }),*], exercises_dir: ExercisesDir {
exercise_dirs: &[#(ExerciseDir { name: #dirs, readme: include_bytes!(#readmes) }),*] readme: EmbeddedFile {
path: "exercises/README.md",
content: ::std::include_bytes!("../exercises/README.md"),
},
files: &[#(
EmbeddedFile {
path: #files,
content: ::std::include_bytes!(::std::concat!("../", #files)),
}
),*],
dirs: &[#(#dirs),*],
},
} }
} }
.into() .into()

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

View file

@ -1 +0,0 @@
// TODO

Some files were not shown because too many files have changed in this diff Show more