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/// let path = abs_file!();
22/// println!("Absolute file path: {:?}", path);
23/// ```
24///
25/// # Edge Cases
26/// - If the `file!()` output already includes the crate name, it is stripped.
27/// - Ensures that the output is always an **absolute** path.
28/// - Does not depend on runtime conditions.
29///
30/// # Testing
31/// This macro is tested in two ways:
32/// 1. **As part of the full workspace**
33///    ```sh
34///    cargo test --workspace
35///    ```
36/// 2. **Within an individual crate**
37///    ```sh
38///    cd test-workspace-1
39///    cargo test
40///    ```
41///
42/// This helps catch cases where path resolution might differ based on the working directory.
43#[macro_export]
44macro_rules! abs_file {
45    () => {{
46        use std::path::{Path, PathBuf};
47
48        const MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR");
49        const FILE_PATH: &str = file!(); // Expands where the macro is used
50
51        let manifest_dir = Path::new(MANIFEST_DIR);
52        let file_path = Path::new(FILE_PATH);
53
54        let crate_name = manifest_dir.file_name().unwrap();
55
56        let relative_file_path = if file_path.starts_with(crate_name) {
57            file_path.strip_prefix(crate_name).unwrap()
58        } else {
59            file_path
60        };
61
62        PathBuf::from(MANIFEST_DIR).join(relative_file_path)
63    }};
64}