While I think that trentcl's answer is cleaner, it's worth showing some non-allocating versions.
Using Path::strip_prefix
To use Path::strip_prefix
, you need to know the prefix. We can generate it by walking up the parent
s of the original path until we find one that ends_with
"foo".
use std::path::Path;
fn thing1<P>(path: &P) -> Result<&Path, ()>
where
P: AsRef<Path> + ?Sized,
{
let original = path.as_ref();
let mut prefix = original;
while !prefix.ends_with("foo") {
prefix = match prefix.parent() {
Some(p) => p,
None => return Err(()),
};
}
original.strip_prefix(prefix).map_err(|_| ())
}
fn main() {
let x = thing1("some/unknown/path/foo/bar/baz");
println!("{:?}", x);
}
With an iterator
We can iterate over the pieces of the path, taking values while it's not "foo". Once we've advanced the iterator enough, we can get the remainder as a path.
use std::path::Path;
fn thing2<P>(path: &P) -> &Path
where
P: AsRef<Path> + ?Sized,
{
let path = path.as_ref();
let mut i = path.iter();
for _ in i.by_ref().take_while(|c| *c != "foo") {}
i.as_path()
}
fn main() {
let x = thing2("some/unknown/path/foo/bar/baz");
println!("{:?}", x);
}
This returns an empty path when "foo" doesn't exist.