Nth ancestor of a Path

I often find myself needing to find a folder 2-3-4 levels above a given file in the filesystem. Rust provides the parent method which is the immediate parent and the ancestors that iterates over al the parts in the directory path. I would like something that would be path.parent(3) that would be something like
path.parent().parent().parent().

I implemented it in two ways. I'd be glad to get your feedback on the implementation, and if you think this addition to the std::path::Path sounds like a good idea then how should I go about proposing it?

use std::path::Path;

fn main() {
    let path = Path::new("one/two/three/four/five/six.rs");


    //match ancestor(&path, 0) {
    //    Some(val) => println!("ancestor: '{}'", val.display()),
    //    None => println!("No such ancestor"),
    //}
    assert_eq!(ancestor(&path, 0), Some(Path::new("one/two/three/four/five/six.rs")));
    assert_eq!(ancestor(&path, 1), Some(Path::new("one/two/three/four/five")));
    assert_eq!(ancestor(&path, 5), Some(Path::new("one")));
    assert_eq!(ancestor(&path, 6), Some(Path::new("")));
    assert_eq!(ancestor(&path, 7), None);

    assert_eq!(parentn(&path, 0), Some(Path::new("one/two/three/four/five/six.rs")));
    assert_eq!(parentn(&path, 1), Some(Path::new("one/two/three/four/five")));
    assert_eq!(parentn(&path, 5), Some(Path::new("one")));
    assert_eq!(parentn(&path, 6), Some(Path::new("")));
    assert_eq!(parentn(&path, 7), None);
}

fn ancestor(mut path: &Path, mut n: u16) -> Option<&Path> {
    while n > 0 {
        match path.parent() {
            Some(value) => path = value,
            None => return None,
        }
        n = n - 1;
    }
    return Some(path);
}

// recursive
fn parentn(path: &Path, n: u16) -> Option<&Path> {
    if n == 0 {
        return Some(path);
    }
    match path.parent() {
        Some(value) => parentn(value, n-1),
        None => None,
    }
}

You can use the question mark operator to simplify this:

fn ancestor(mut path: &Path, n: u16) -> Option<&Path> {
    for _ in 0..n {
        path = path.parent()?;
    }
    Some(path)
}
3 Likes

Nice. Thank you.

there is Path::ancestors.

So I would use path.ancestors().nth(n).

9 Likes

Oh, I knew ancestors, but I was not aware the nth() thing. Very nice.

nth is available on all iterators, just to be clear.

4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.