trybuild/
path.rs

1use std::path::{Path, PathBuf};
2
3macro_rules! path {
4    ($($tt:tt)+) => {
5        tokenize_path!([] [] $($tt)+)
6    };
7}
8
9// Private implementation detail.
10macro_rules! tokenize_path {
11    ([$(($($component:tt)+))*] [$($cur:tt)+] /) => {
12        crate::directory::Directory::new(tokenize_path!([$(($($component)+))*] [$($cur)+]))
13    };
14
15    ([$(($($component:tt)+))*] [$($cur:tt)+] / $($rest:tt)+) => {
16        tokenize_path!([$(($($component)+))* ($($cur)+)] [] $($rest)+)
17    };
18
19    ([$(($($component:tt)+))*] [$($cur:tt)*] $first:tt $($rest:tt)*) => {
20        tokenize_path!([$(($($component)+))*] [$($cur)* $first] $($rest)*)
21    };
22
23    ([$(($($component:tt)+))*] [$($cur:tt)+]) => {
24        tokenize_path!([$(($($component)+))* ($($cur)+)])
25    };
26
27    ([$(($($component:tt)+))*]) => {{
28        let mut path = std::path::PathBuf::new();
29        $(
30            path.push(&($($component)+));
31        )*
32        path
33    }};
34}
35
36#[derive(Eq, PartialEq, Ord, PartialOrd, Clone)]
37pub(crate) struct CanonicalPath(PathBuf);
38
39impl CanonicalPath {
40    pub(crate) fn new(path: &Path) -> Self {
41        if let Ok(canonical) = path.canonicalize() {
42            CanonicalPath(canonical)
43        } else {
44            CanonicalPath(path.to_owned())
45        }
46    }
47}
48
49#[test]
50fn test_path_macro() {
51    struct Project {
52        dir: PathBuf,
53    }
54
55    let project = Project {
56        dir: PathBuf::from("../target/tests"),
57    };
58
59    let cargo_dir = path!(project.dir / ".cargo" / "config.toml");
60    assert_eq!(cargo_dir, Path::new("../target/tests/.cargo/config.toml"));
61}