proc_macro_crate_name_test_macros/
lib.rs

1use proc_macro::TokenStream;
2use std::path::PathBuf;
3use walkdir::WalkDir;
4
5fn proc_macro_caller_crate_root() -> PathBuf {
6    let crate_name =
7        std::env::var("CARGO_PKG_NAME").expect("failed to read ENV var `CARGO_PKG_NAME`!");
8    let current_dir = std::env::current_dir().expect("failed to unwrap env::current_dir()!");
9    let search_entry = format!("name=\"{crate_name}\"");
10    for entry in WalkDir::new(&current_dir)
11        .into_iter()
12        .filter_entry(|e| !e.file_name().eq_ignore_ascii_case("target"))
13    {
14        let Ok(entry) = entry else { continue };
15        if !entry.file_type().is_file() {
16            continue;
17        }
18        let Some(file_name) = entry.path().file_name() else { continue };
19        if !file_name.eq_ignore_ascii_case("Cargo.toml") {
20            continue;
21        }
22        let Ok(cargo_toml) = std::fs::read_to_string(&entry.path()) else {
23            continue
24        };
25        if cargo_toml
26            .chars()
27            .filter(|&c| !c.is_whitespace())
28            .collect::<String>()
29            .contains(search_entry.as_str())
30        {
31            return entry.path().parent().unwrap().to_path_buf();
32        }
33    }
34    current_dir
35}
36
37#[proc_macro]
38pub fn my_macro(_tokens: TokenStream) -> TokenStream {
39    let crate_name = std::env::var("CARGO_PKG_NAME").unwrap();
40    let working_dir = std::env::current_dir().unwrap().display().to_string();
41    let root = proc_macro_caller_crate_root()
42        .as_path()
43        .to_str()
44        .unwrap()
45        .to_string();
46    println!("CRATE_NAME: {}", crate_name);
47    println!("WORKING_DIR: {}", working_dir);
48    println!("CRATE_ROOT: {}", root);
49    format!("(\"{crate_name}\", \"{working_dir}\", \"{root}\")")
50        .parse()
51        .unwrap()
52}