summaryrefslogtreecommitdiff
path: root/rustlings-macros/src
diff options
context:
space:
mode:
authormo8it <mo8it@proton.me>2024-03-28 17:34:48 +0100
committermo8it <mo8it@proton.me>2024-03-28 17:34:48 +0100
commite5efc68a9101d7d7e38263c8a6ee44dda991fc6a (patch)
tree0a1a34fc0b8ec2f746ed069f8a00b2a6eb843204 /rustlings-macros/src
parent9691c3cb55484ce9676c85ad4673b38e06100303 (diff)
Done macro
Diffstat (limited to 'rustlings-macros/src')
-rw-r--r--rustlings-macros/src/lib.rs95
1 files changed, 95 insertions, 0 deletions
diff --git a/rustlings-macros/src/lib.rs b/rustlings-macros/src/lib.rs
new file mode 100644
index 0000000..dd1a588
--- /dev/null
+++ b/rustlings-macros/src/lib.rs
@@ -0,0 +1,95 @@
+use proc_macro::TokenStream;
+use quote::quote;
+use std::{fs::read_dir, panic, path::PathBuf};
+
+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());
+ })
+}
+
+#[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;
+ }
+
+ if path.extension() != Some("rs".as_ref()) {
+ panic!(
+ "Found {} but expected only README.md and .rs files",
+ path.display(),
+ );
+ }
+
+ Some(path_to_string(path))
+ });
+
+ dirs.push(quote! {
+ EmbeddedFlatDir {
+ path: #dir_path,
+ readme: EmbeddedFile {
+ path: concat!(#dir_path, "/README.md"),
+ content: ::std::include_bytes!(concat!("../", #dir_path, "/README.md")),
+ },
+ content: vec![
+ #(EmbeddedFile {
+ path: #dir_files,
+ content: ::std::include_bytes!(concat!("../", #dir_files)),
+ }),*
+ ],
+ }
+ });
+ }
+
+ quote! {
+ EmbeddedFiles {
+ info_toml_content: ::std::include_str!("../info.toml"),
+ exercises_dir: ExercisesDir {
+ readme: EmbeddedFile {
+ path: "exercises/README.md",
+ content: ::std::include_bytes!("../exercises/README.md"),
+ },
+ files: vec![#(
+ EmbeddedFile {
+ path: #files,
+ content: ::std::include_bytes!(concat!("../", #files)),
+ }
+ ),*],
+ dirs: vec![#(#dirs),*],
+ },
+ }
+ }
+ .into()
+}