abs_file_macro/
lib.rs

1#[cfg(doctest)]
2doc_comment::doctest!("../README.md");
3
4/// A macro that returns the absolute file path of the Rust source file
5/// in which it is invoked.
6///
7/// This macro ensures that the correct absolute path is resolved, even
8/// when used within a Cargo workspace or a nested crate. It prevents
9/// issues with duplicated path segments by properly handling the crate
10/// root.
11///
12/// # How It Works
13/// - `file!()` provides the relative path of the current source file.
14/// - `env!("CARGO_MANIFEST_DIR")` provides the absolute path of the crate root.
15/// - The macro joins these paths while ensuring no duplicate segments.
16///
17/// # Example
18/// ```
19/// use abs_file_macro::abs_file;
20///
21/// fn main() {
22///     let path = abs_file!();
23///     println!("Absolute file path: {:?}", path);
24/// }
25/// ```
26///
27/// # Edge Cases
28/// - If the `file!()` output already includes the crate name, it is stripped.
29/// - Ensures that the output is always an **absolute** path.
30/// - Does not depend on runtime conditions.
31///
32/// # Testing
33/// This macro is tested in two ways:
34/// 1. **As part of the full workspace**
35///    ```sh
36///    cargo test --workspace
37///    ```
38/// 2. **Within an individual crate**
39///    ```sh
40///    cd test-workspace-1
41///    cargo test
42///    ```
43///
44/// This ensures correctness across different usage scenarios.
45#[macro_export]
46macro_rules! abs_file {
47    () => {{
48        use std::path::{Path, PathBuf};
49
50        const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
51        const FILE_PATH: &str = file!(); // Expands where the macro is used
52
53        let manifest_dir = Path::new(MANIFEST_DIR);
54        let file_path = Path::new(FILE_PATH);
55
56        let crate_name = manifest_dir.file_name().unwrap();
57
58        let relative_file_path = if file_path.starts_with(crate_name) {
59            file_path.strip_prefix(crate_name).unwrap()
60        } else {
61            file_path
62        };
63
64        PathBuf::from(MANIFEST_DIR).join(relative_file_path)
65    }};
66}