summaryrefslogtreecommitdiff
path: root/rustlings-macros
diff options
context:
space:
mode:
authorMo <76752051+mo8it@users.noreply.github.com>2024-04-04 15:48:07 +0200
committerGitHub <noreply@github.com>2024-04-04 15:48:07 +0200
commit8c8f30d8ce3b732de649938d8945496bd769ac22 (patch)
tree3679a78e468872f05cec1de4e489acbbc08a11a8 /rustlings-macros
parent459c52137ac7b8aa8500a46f04b0e848ba48a969 (diff)
parentb6c434c445d91a9e886e5639b078635e5eca4eb3 (diff)
Merge pull request #1931 from mo8it/standalone-binary
Standalone binary
Diffstat (limited to 'rustlings-macros')
-rw-r--r--rustlings-macros/Cargo.toml12
-rw-r--r--rustlings-macros/src/lib.rs95
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()
+}