mirror of
https://github.com/rust-lang/rustlings.git
synced 2025-01-09 20:03:24 +03:00
Compare commits
No commits in common. "d8c2ab8349854cbc7f4a994c7413d266cc38bc24" and "86684b7fc9dd5e8bedad6056565645d1d980925c" have entirely different histories.
d8c2ab8349
...
86684b7fc9
16
Cargo.lock
generated
16
Cargo.lock
generated
|
@ -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]]
|
||||||
|
|
21
Cargo.toml
21
Cargo.toml
|
@ -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]
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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.
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
|
@ -1 +0,0 @@
|
||||||
// TODO
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue