Looking for a macro for making a list of module names in a project directory

Hello!

I am looking for a procedural macro which is very similar to dirmod, but instead of making a simple list of module declarations, it simply makes a static array with their names:

For example, for this file structure:

base/
    module_1.rs
    module_2.rs
    ...
    module_n.rs
    mod.rs

Dirmod can convert...

/* In base/mod.rs */
dirmod::all!();

...into this:

mod module_1;
mod module_2;
/* ... */
mod module_n;

And I need something that can turn...

something_like_this!();

...into:

pub const MODULE_LIST:  [&str; (n-1)] = [
    "module_1",
    "module_2",
    /*...*/
    "module_n"
];

Would anyone happen to know of something, or what I should look at to learn how to implement a procedural macro like this one?

I forgot ChatGPT existed. This is both convenient and scary:

Sure! Here's an example of how you can implement a Rust procedural macro to achieve the desired functionality:

extern crate proc_macro;

use proc_macro::TokenStream;
use quote::quote;
use std::fs;
use std::path::Path;
use syn::{parse_macro_input, LitStr};

#[proc_macro]
pub fn generate_module_list(input: TokenStream) -> TokenStream {
    // Parse the input as a string literal representing the base directory path
    let base_path = parse_macro_input!(input as LitStr).value();

    // Generate the module list by reading the directory and collecting the module names
    let module_list = fs::read_dir(base_path)
        .expect("Failed to read directory")
        .map(|entry| {
            entry
                .expect("Failed to read entry")
                .file_name()
                .into_string()
                .expect("Failed to convert OsString to String")
        })
        .filter(|name| name.ends_with(".rs") && name != "mod.rs")
        .collect::<Vec<String>>();

    // Generate the static array of string slices
    let module_array = quote! {
        [
            #(#module_list),*
        ]
    };

    // Generate the output as a const static array of string slices
    let output = quote! {
        pub const MODULE_LIST: [&str; #module_array.len()] = [#module_array];
    };

    // Return the output as a TokenStream
    output.into()
}

To use this macro, you can include it in your Rust code as follows:

rustCopy code

use my_macro::generate_module_list;

// Specify the path to the base directory and generate the module list
generate_module_list!("base");

Note that in order to use this procedural macro, you'll need to add the my_macro crate as a dependency in your Cargo.toml and import it into your Rust code. Also, make sure to add the necessary dependencies (proc-macro2 and quote) to your Cargo.toml as well.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.