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}