with_paths

Macro with_paths 

Source
macro_rules! with_paths {
    {
        $( $name:ident = $( $path:ident ) / + ),*
    } => { ... };
    {
        $( $name:ident = $( $path:ident ) / + ),*
        => $( $statements:stmt );* $(;)?
    } => { ... };
}
Expand description

with_paths! allows paths to be joined with small path optimization: if the total length of all joined paths is less then 128, no PathBuf will be allocated.

There are two ways to use it:

// Declaration mode
let p1 = "path";
let p2 = "to";
let p3 = "thing";

// Declares a variable `my_path` of type &Path
with_paths! {
    my_path = p1 / p2 / p3
};

let path_exists = my_path.exists();
// Expression mode
let p1 = "path";
let p2 = "to";
let p3 = "thing";

// Declares a variable my_path of type &Path,
// only usable within this block
let my_result = with_paths! {
    my_path = p1 / p2 / p3
    => my_path.exists()
};

§Syntax

There are two modes of use for with_paths! - declaration mode, and expression mode.

§Declaration mode

Declares paths usable in outer scope. Here, with_paths! simply expands to a set of statements, and any path variables it declares are usable outside the macro:

// This example illustrates syntax

with_paths! {
    <declarations>
};

<statements>

§Checking Existence with Declaration Mode

use path_no_alloc::with_paths;

let p1 = "some_dir";
let p2 = "file.txt";
with_paths! {
    path = p1 / p2
};

// path can be used after it's declared. It's just a variable.
let exists = path.exists();

§Expression mode

Declarations followed by statements. Here, with_paths! encapsulates a block. Paths defined by this mode are not usable outside the block.

// This example illustrates syntax

let my_path_computation = with_paths! { <declarations> => <statements> };

§Checking Existence with Expression Mode

use path_no_alloc::with_paths;

let p1 = "some_dir";
let p2 = "file.txt";
let exists: bool = with_paths! {
    my_path = p1 / p2 => my_path.exists()
};

// `my_path` only exists in the context of the block. It's not in scope anymore.

§Constraints

You can use arbitrary objects that are convertible to a Path via .as_ref():

use path_no_alloc::with_paths;
use std::path::Path;

// Check that a file exists in the given path
fn has_file<P: AsRef<Path>, Q: AsRef<Path>>(path: P, file: Q) -> bool {
    with_paths! {
        full_path = path / file => full_path.exists()
    }
}

You can also join arbitrary numbers of paths together:

use std::path::Path;
use path_no_alloc::with_paths;

let p1 = "path";
let p2 = "to";
let p3 = "thing";

with_paths! {
    path1 = p1 / p2 / p3,
    path2 = p3 / p2 / p1
    => println!("Path1 = {path1:?}, Path2 = {path2:?}")
}

This will print:

Path1 = "path/to/thing", Path2 = "thing/to/path"

Paths joined in the context of with_paths! act as though they’ve been joined via Path.join. In other words, joining paths A and B will just produce B in the case that B is absolute:

use path_no_alloc::with_paths;
use std::path::Path;

let p1 = "some/path";
let p2 = "/absolute/path";

// declare my_path, to be used in following statements
with_paths! {
    my_path = p1 / p2
}

println!("{my_path:?} should equal '/absolute/path'");
assert_eq!(my_path, Path::new(p1).join(p2));
assert_eq!(my_path, Path::new("/absolute/path"));