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}