Macro to call method in submodules


#1

Hi I have a source structure like

src/main.rs
src/elements/element1.rs
src/elements/element2.rs
src/elements/element3.rs

I want to create a macro that reads src/elements dir and calls a function in each file.

What I have so far is something like

macro_rules! read_elements {
    () => {
        let paths = fs::read_dir("src/elements").unwrap();
        let names =
            paths.filter_map(|entry| {
            entry.ok().and_then(|e|
                e.path().file_stem()
                .and_then(|n| n.to_str().map(|s| String::from(s)))
            )
            }).collect::<Vec<String>>();

         // for n in &names {
         //     elements::n::get_type_information();
         //   }

    };
}

The problem occurs in the commented area above where I have to call a function in each file.
Does anyone know if I can get the macro to call a function in a module given the module name ?

Thanks


#2

I’m afraid Rust is not that dynamic.

macro_rules! macros generate code, but don’t run it. In this case it’s not any different than if you copy&pasted that code directly into fn main().

And that code at run time can’t load any .rs files. Everything has to be known and compiled before even a single line of code runs, which means you can’t use fs::read_dir to discover program’s source code.

If you really have to read files from disk dynamically like that, then perhaps you could achieve that with “macros 1.1” that can run Rust code at compile time.


#3

Maybe this would work for you:

macro_rules! mods {
    ( $( $x:ident ),* ) => {
        $(
            mod $x;
        )*
        fn init_elements() {
            $(
                $x::init();
            )*
        }
    }
}

mod elements {
    mods!(element1, element2, element3);
}

fn main() {
    elements::init_elements();
}

#4

Thanks makes sense. I will play around with your example.