diff options
| author | Mo <76752051+mo8it@users.noreply.github.com> | 2024-04-04 15:48:07 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-04-04 15:48:07 +0200 |
| commit | 8c8f30d8ce3b732de649938d8945496bd769ac22 (patch) | |
| tree | 3679a78e468872f05cec1de4e489acbbc08a11a8 /rustlings-macros | |
| parent | 459c52137ac7b8aa8500a46f04b0e848ba48a969 (diff) | |
| parent | b6c434c445d91a9e886e5639b078635e5eca4eb3 (diff) | |
Merge pull request #1931 from mo8it/standalone-binary
Standalone binary
Diffstat (limited to 'rustlings-macros')
| -rw-r--r-- | rustlings-macros/Cargo.toml | 12 | ||||
| -rw-r--r-- | rustlings-macros/src/lib.rs | 95 |
2 files changed, 107 insertions, 0 deletions
diff --git a/rustlings-macros/Cargo.toml b/rustlings-macros/Cargo.toml new file mode 100644 index 0000000..0114c8f --- /dev/null +++ b/rustlings-macros/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rustlings-macros" +version.workspace = true +authors.workspace = true +license.workspace = true +edition.workspace = true + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.35" diff --git a/rustlings-macros/src/lib.rs b/rustlings-macros/src/lib.rs new file mode 100644 index 0000000..598b5c3 --- /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: ::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! { + 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: &[#( + EmbeddedFile { + path: #files, + content: ::std::include_bytes!(::std::concat!("../", #files)), + } + ),*], + dirs: &[#(#dirs),*], + }, + } + } + .into() +} |
