简体   繁体   中英

Conditional compilation based on if name exists

I am doing advent of code, which is a collection of 25 programming problems, one for each of day of the advent.

I structure each day in it's own separate file/module, so for example year 2021 day 7 would be at src/years/year2021/day07.rs . So src/years/year2021/mod.rs ends up being just pub mod s

pub mod day01;
pub mod day02;
pub mod day04;
// and so on...

Is there a way I could generate this list dynamically (with something like a recursive macro), so check if module day01 is accessible from this context (or alternatively if./day01.rs exists) and generate the pub mod automatically, and add more as files are created.

The best would be the ability to check if any name exists, like a module or a function inside a module.

You could use the build.rs to generate a module based on the files that exist at build time.

Something like this possably

let years_path = path::Path::new("./src/years");
let mut mod_file = fs::File::create(years_path.join("mod.rs")).unwrap();

let paths = fs::read_dir(years_path).unwrap();

for entry in paths {
    let entry = entry.unwrap();
    if entry.metadata().unwrap().is_dir() {
        writeln!(
            mod_file,
            "mod {};",
            entry.path().file_name().unwrap().to_str().unwrap()
        )
        .unwrap();
    }
}

I'm using a version of build.rs quite similar to @pidgeonhands one. It's a bit more resilient (it only crashes when it can't create or write to the files) to weird files inside the folders and does work for multiple years:

use std::{
    error::Error,
    ffi::OsString,
    fs::{self, File},
    io::Write,
    path::Path,
};

fn main() -> Result<(), Box<dyn Error>> {
    println!("cargo:rerun-if-changed=src/years");
    let years_path = Path::new("src/years");
    let mut years_mod_file = File::create(years_path.join("mod.rs"))?;
    for year in fs::read_dir("src/years")? {
        let Ok(year) = year else {continue};
        let year_name = year.file_name();
        let Some(year_name) = year_name.to_str() else {continue};
        if year_name != OsString::from("mod.rs") {
            writeln!(years_mod_file, "pub mod {year_name};")?;
            let mut year_mod_file = File::create(year.path().join("mod.rs"))?;

            for day in fs::read_dir(year.path())? {
                let Ok(day) = day else {continue};
                if day.file_name() != OsString::from("mod.rs") {
                    let day_name = day.path();
                    let Some(day_name) = day_name.file_stem() else {continue};
                    let Some(day_name) = day_name.to_str() else {continue};
                    writeln!(year_mod_file, "pub mod {day_name};")?;
                    println!("{:?}", day_name);
                }
            }
        }
    }
    Ok(())
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM