-
Notifications
You must be signed in to change notification settings - Fork 25
Description
Proposal
Problem statement
There’s a popular pattern for working with Rust paths: doing path.join(first).join(second) to create a PathBuf from multiple components. Unfortunately, that could result in extra unneeded allocations (which may or may not be optimized out).
More optimal version looks like this:
let mut path_buf = path.to_path_buf();
path_buf.push(first);
path_buf.push(second);which is not pretty.
Motivation, use-cases
Extremely common. Spotted in rust-lang/rust:
https://github.com/rust-lang/rust/blob/edcbb295c9827ce38cbef4093e2c3d184923f362/src/bootstrap/doc.rs#L205
https://github.com/rust-lang/rust/blob/edcbb295c9827ce38cbef4093e2c3d184923f362/src/bootstrap/dist.rs#L2251
It’s easy to find more examples:
https://github.com/search?q=language%3Arust%20%2F%5C.join%5C(.*%3F%5C)%5C.join%2F&type=code
I’m not sure that ever happens on a hot path though.
Notably, there is a one-line way to do it, but it’s hard to discover, so one possible alternative would be to document it better.
[path, first, second].into_iter().collect()It also doesn’t handle the case where base path and other parts have different types well, which seems to be quite common.
Solution sketches
impl Path {
// name bikesheddable
pub fn join_multi<P: AsRef<Path>>(&self, paths: impl IntoIterator<Item = P>) -> PathBuf;
}
impl PathBuf {
// name extremely bikesheddable
pub fn with_multi<P: AsRef<Path>>(self, paths: impl IntoIterator<Item = P>) -> Self;
}Used like
path.join_multi([first, second])Another alternative design could be a builder-like interface to PathBuf:
impl PathBuf {
fn with(self, path: impl AsRef<Path>) -> Self;
}used like
path.to_path_buf().with(first).with(second)or even
path.join(first).with(second)It could be a bit more wordy, but has a benefit of not requiring first and second to be the same type.
Links and related work
Zig has a join() function for concatenating a list of paths: https://ziglang.org/documentation/0.6.0/std/#std;fs.path.join
I don’t think C++ has such a method.
This issue is much less relevant to GCed languages, so I don’t think it’s very useful to look at their APIs, but e.g. Python has os.path.join() / PurePath.joinpath() and Go has path.Join().
What happens now?
This issue is part of the libs-api team API change proposal process. Once this issue is filed the libs-api team will review open proposals in its weekly meeting. You should receive feedback within a week or two.