Reputation: 97
I want to change the first ancestor of a &Path
, possibly by returning a new PathBuf
like so.
fn change_parent(path: &Path, new_parent: &Path) -> PathBuf;
Here's how I expect it to work.
let old_path = change_root(Path::new("/hello/world.html"), Path::new("/html"));
let new_path = PathBuf::from("/html/world.html");
assert_eq!(old_path, new_path)
I tried .ancestors()
but the Path::new("/hello/world.html").ancestors();
returns an iterator over ["/hello/world.html", "/hello", "/"]
which is kind of the opposite of what I want. What I want is ["/hello/world.html", "hello/world.html", "/world.html"]
so I can append a new path easily.
Should I switch to using split
on "(/|\)"
then replacing the first result instead?
Upvotes: 2
Views: 985
Reputation: 1109
Using Path::components I was able to come up with this solution:
use std::path::{Component, Path};
use std::{ffi::OsString, path::PathBuf};
let path = Path::new("/tmp/foo.txt");
let mut b: Vec<_> = path.components().collect();
// b[0] is the root directory "/" and b[1] is the
// "tmp" directory.
let html = OsString::from("html");
b[1] = Component::Normal(&html);
let pb: PathBuf = b.iter().collect();
I couldn't find a simpler way to do this. The Path
and PathBuf
implementations are both based on a single OsString
. So, with both types, to get access to individual components in the path, the underlying OsString
would need to be split by something and components
is the way to do the splitting. So, I don't think there's really another solution.
Upvotes: 4
Reputation: 97
This is using strip_prefix
provided by conradludgate on The Rust Programming Language Community (Discord):
use std::path::{Path, PathBuf, StripPrefixError};
fn replace_prefix(p: impl AsRef<Path>, from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<PathBuf, StripPrefixError> {
p.as_ref().strip_prefix(from).map(|p| to.as_ref().join(p))
}
(
replace_prefix("/public/file.html", "/public", "/.html_output"),
replace_prefix("/public/folder/nested/file.html", "/public", "/.html_output"),
replace_prefix("/folder/nested/file.html", "/public", "/.html_output"),
)
(Ok("/.html_output/file.html"), Ok("/.html_output/folder/nested/file.html"), Err(StripPrefixError(())))
Upvotes: 2