#[cfg(doc)]
#[macro_export]
macro_rules! path {
($(&)? ident / $(ident_or_literal_or_expr) / * ) => {};
(literal / $(ident_or_literal_or_expr) / * ) => {};
($(&)? ( path_expression ) / $(ident_or_literal_or_expr) / *) => {};
}
#[cfg(not(doc))]
#[macro_export]
macro_rules! path {
($first:ident / $($rest_segs:tt)* ) => {{
let mut x = $first;
$crate::__path_internal!(x / $($rest_segs)*)
}};
( & $first:ident / $($rest_segs:tt)* ) => {{
let mut x = std::path::PathBuf::from($first.to_owned());
$crate::__path_internal!(x / $($rest_segs)*)
}};
($first:literal / $($rest_segs:tt)* ) => {{
let mut x = std::path::PathBuf::from($first);
$crate::__path_internal!(x / $($rest_segs)*)
}};
(( $first:expr ) / $($rest_segs:tt)* ) => {{
let mut x: ::std::path::PathBuf = { $first };
$crate::__path_internal!(x / $($rest_segs)*)
}};
( & ( $first:expr ) / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = {$first}.as_ref();
let mut x = x.to_path_buf();
$crate::__path_internal!(x / $($rest_segs)*)
}};
( $first:block / $($rest_segs:tt)* ) => {{
let mut x: ::std::path::PathBuf = $first;
$crate::__path_internal!(x / $($rest_segs)*)
}};
( & $first:block / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $first.as_ref();
let mut x = x.to_path_buf();
$crate::__path_internal!(x / $($rest_segs)*)
}};
}
#[macro_export]
#[doc(hidden)]
macro_rules! __path_internal {
($first:ident / $second:literal) => {{
$first.push($second); $first
}};
($first:ident / $second:ident) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x); $first
}};
($first:ident / $second:literal / $third:literal) => {{
$first.push($second); $first.push($third); $first
}};
($first:ident / $second:literal / $third:ident) => {{
$first.push($second);
let x: &::std::path::Path = $third.as_ref();
$first.push(x); $first
}};
($first:ident / $second:ident / $third:literal) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
$first.push($third); $first
}};
($first:ident / $second:ident / $third:ident) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
let x: &::std::path::Path = $third.as_ref();
$first.push(x); $first
}};
($first:ident / $second:literal / $third:literal / $($rest_segs:tt)* ) => {{
$first.push($second); $first.push($third);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:literal / $third:ident / $($rest_segs:tt)* ) => {{
$first.push($second);
let x: &::std::path::Path = $third.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:literal / ( $third:expr ) / $($rest_segs:tt)* ) => {{
$first.push($second);
let x: &::std::path::Path = {$third}.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:literal / $third:block / $($rest_segs:tt)* ) => {{
$first.push($second);
let x: &::std::path::Path = $third.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:ident / $third:literal / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
$first.push($third);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:ident / $third:ident / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
let x: &::std::path::Path = $third.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:ident / ( $third:expr ) / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
let x: &::std::path::Path = {$third}.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:ident / $third:block / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
let x: &::std::path::Path = $third.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / ( $second:expr ) / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = {$second}.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:block / $($rest_segs:tt)* ) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
$crate::__path_internal!($first / $($rest_segs)* )
}};
($first:ident / $second:literal / $third:expr) => {{
$first.push($second);
let x: &::std::path::Path = {$third}.as_ref();
$first.push(x); $first
}};
($first:ident / $second:ident / $third:expr) => {{
let x: &::std::path::Path = $second.as_ref();
$first.push(x);
let x: &::std::path::Path = {$third}.as_ref();
$first.push(x); $first
}};
($first:ident / $second:expr) => {{
let x: &::std::path::Path = {$second}.as_ref();
$first.push(x); $first
}};
}
#[cfg(test)]
mod tests {
use std::path::{Path, PathBuf};
fn long_expected() -> PathBuf {
PathBuf::from("a")
.join("b")
.join("c")
.join("d")
.join("e")
.join("f")
.join("g")
.join("h")
.join("i")
.join("j")
}
#[test]
fn long_path_from_literal() {
let c = "c";
let e = String::from("e");
let h = "h";
let p = crate::path!("a" / "b" / (c) / "d" / (e.as_str()) / "f" / "g" / h / "i" / "j");
assert_eq!(p, long_expected());
let _ = (c, h); }
#[test]
fn long_path_from_owned() {
let base = PathBuf::from("a");
let b = "b";
let d = String::from("d");
let g = "g";
let p = crate::path!(base / (b) / "c" / (d.as_str()) / "e" / "f" / g / "h" / "i" / "j");
assert_eq!(p, long_expected());
let _ = (b, g);
}
#[test]
fn long_path_from_borrowed() {
let base = PathBuf::from("a");
let base_ref: &Path = base.as_path();
let c = String::from("c");
let f = "f";
let i = "i";
let p = crate::path!(&base_ref / "b" / (c.as_str()) / "d" / "e" / f / "g" / "h" / i / "j");
assert_eq!(p, long_expected());
let _ = (f, i);
}
#[test]
fn long_path_from_expr_owned() {
let d = "d";
let e = String::from("e");
let f = String::from("f");
let p = crate::path!(
(PathBuf::from("a")) / "b" / "c" / d / (&e) / (f.as_str()) / "g" / "h" / "i" / "j"
);
assert_eq!(p, long_expected());
let _ = d;
}
#[test]
fn long_path_from_expr_borrowed() {
let base = PathBuf::from("a");
let b = "b";
let e = String::from("e");
let j = "j";
let p = crate::path!(
&(base.as_path()) / b / "c" / "d" / (e.as_str()) / "f" / "g" / "h" / "i" / j
);
assert_eq!(p, long_expected());
let _ = (b, j);
}
#[test]
fn long_path_no_consecutive_same_type_even() {
let b = "b";
let c = String::from("c");
let e = "e";
let f = String::from("f");
let h = "h";
let i = String::from("i");
let p = crate::path!(
"a" / b / (c.as_str()) / "d" / e / (f.as_str()) / "g" / h / (i.as_str()) / "j"
);
assert_eq!(p, long_expected());
let _ = (b, e, h);
}
fn nine_expected() -> PathBuf {
PathBuf::from("a")
.join("b")
.join("c")
.join("d")
.join("e")
.join("f")
.join("g")
.join("h")
.join("i")
}
#[test]
fn long_path_no_consecutive_same_type_odd() {
let b = "b";
let c = String::from("c");
let e = "e";
let f = String::from("f");
let h = "h";
let i = String::from("i");
let p =
crate::path!("a" / b / (c.as_str()) / "d" / e / (f.as_str()) / "g" / h / i.as_str());
assert_eq!(p, nine_expected());
let _ = (b, e, h);
}
}