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}