diff options
Diffstat (limited to 'rustlings-macros')
| -rw-r--r-- | rustlings-macros/Cargo.toml | 2 | ||||
| -rw-r--r-- | rustlings-macros/src/lib.rs | 99 |
2 files changed, 28 insertions, 73 deletions
diff --git a/rustlings-macros/Cargo.toml b/rustlings-macros/Cargo.toml index 095deaa..f925f69 100644 --- a/rustlings-macros/Cargo.toml +++ b/rustlings-macros/Cargo.toml @@ -11,3 +11,5 @@ proc-macro = true [dependencies] quote = "1.0.36" +serde.workspace = true +toml_edit.workspace = true diff --git a/rustlings-macros/src/lib.rs b/rustlings-macros/src/lib.rs index d95a93a..0bf3dbd 100644 --- a/rustlings-macros/src/lib.rs +++ b/rustlings-macros/src/lib.rs @@ -1,86 +1,39 @@ use proc_macro::TokenStream; use quote::quote; -use std::{fs::read_dir, panic, path::PathBuf}; +use serde::Deserialize; -fn path_to_string(path: PathBuf) -> String { - path.into_os_string() - .into_string() - .unwrap_or_else(|original| { - panic!("The path {} is invalid UTF8", original.to_string_lossy()); - }) +#[derive(Deserialize)] +struct ExerciseInfo { + name: String, + dir: String, +} + +#[derive(Deserialize)] +struct InfoFile { + exercises: Vec<ExerciseInfo>, } #[proc_macro] pub fn include_files(_: TokenStream) -> TokenStream { - let mut files = Vec::with_capacity(8); - let mut dirs = Vec::with_capacity(128); - - for entry in read_dir("exercises").expect("Failed to open the `exercises` directory") { - let entry = entry.expect("Failed to read the `exercises` directory"); - - if entry.file_type().unwrap().is_file() { - let path = entry.path(); - if path.file_name().unwrap() != "README.md" { - files.push(path_to_string(path)); - } - - 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)), - }),* - ], - } - }); - } + let exercises = toml_edit::de::from_str::<InfoFile>(include_str!("../../info.toml")) + .expect("Failed to parse `info.toml`") + .exercises; + + let exercise_files = exercises + .iter() + .map(|exercise| format!("../exercises/{}/{}.rs", exercise.dir, exercise.name)); + let solution_files = exercises + .iter() + .map(|exercise| format!("../solutions/{}/{}.rs", exercise.dir, exercise.name)); + let dirs = exercises.iter().map(|exercise| &exercise.dir); + let readmes = exercises + .iter() + .map(|exercise| format!("../exercises/{}/README.md", exercise.dir)); quote! { EmbeddedFiles { - exercises_dir: ExercisesDir { - 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),*], - }, + exercise_files: &[#(ExerciseFiles { exercise: include_bytes!(#exercise_files), solution: include_bytes!(#solution_files) }),*], + exercise_dirs: &[#(ExerciseDir { name: #dirs, readme: include_bytes!(#readmes) }),*] } } .into() |
