pathbuf/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2
3//! `pathbuf` provides a single macro, [`pathbuf!`][pathbuf], which gives a [`vec!`][std_vec]-like syntax
4//! for constructing [`PathBuf`][std_path_pathbuf]s.
5//!
6//! # Example
7//!
8//! ```
9//! # use pathbuf::pathbuf;
10//! # use std::path::Path;
11//! #
12//! fn do_something(dir: &Path) {
13//! let file_name = pathbuf![dir, "filename.txt"];
14//!
15//! if file_name.exists() {
16//! // do something...
17//! }
18//! }
19//! ```
20//!
21//! # Security
22//!
23//! As the macro relies on [`std::path::PathBuf::push`] there is also no protection against path traversal attacks.
24//! Therefore no path element shall be untrusted user input without validation or sanitisation.
25//!
26//! An example for a path traversal/override on an UNIX system:
27//!
28//! ```
29//! # use pathbuf::pathbuf;
30//! # use std::path::PathBuf;
31//! #
32//! # #[cfg(unix)]
33//! # {
34//! let user_input = "/etc/shadow";
35//! assert_eq!(pathbuf!["/tmp", user_input], PathBuf::from("/etc/shadow"));
36//! # }
37//! ```
38//!
39//! [pathbuf]: macro.pathbuf.html
40//! [std_vec]: https://doc.rust-lang.org/std/macro.vec.html "Documentation for std::vec (macro)"
41//! [std_path_pathbuf]: https://doc.rust-lang.org/std/path/struct.PathBuf.html "Documentation for std::path::PathBuf (struct)"
42
43/// Creates a [`PathBuf`][std_path_pathbuf] containing the arguments.
44///
45/// `pathbuf!` allows [`PathBuf`][std_path_pathbuf]s to be defined with the same syntax as array expressions, like so:
46///
47/// ```
48/// # use pathbuf::pathbuf;
49/// # use std::path::Path;
50/// #
51/// fn do_something(dir: &Path) {
52/// let file_name = pathbuf![dir, "filename.txt"];
53///
54/// if file_name.exists() {
55/// // do something...
56/// }
57/// }
58/// ```
59///
60/// [std_path_pathbuf]: https://doc.rust-lang.org/std/path/struct.PathBuf.html "Documentation for std::path::PathBuf (struct)"
61#[macro_export]
62macro_rules! pathbuf {
63 ( $( $part:expr ),* ) => {{
64 use std::path::PathBuf;
65
66 let mut temp = PathBuf::with_capacity( $( std::mem::size_of_val($part) + )* 0);
67
68 $(
69 temp.push($part);
70 )*
71
72 temp
73 }};
74
75 ($( $part:expr, )*) => ($crate::pathbuf![$($part),*])
76}
77
78#[cfg(test)]
79mod tests {
80 use crate::pathbuf;
81 use std::path::PathBuf;
82
83 #[test]
84 fn it_works() {
85 let p = pathbuf!["hello", "filename.txt"];
86
87 let expected = {
88 let mut temp = PathBuf::new();
89 temp.push("hello");
90 temp.push("filename.txt");
91 temp
92 };
93
94 assert_eq!(p, expected);
95 }
96}