Skip to main content

ms_pdb/utils/
path.rs

1//! Utilities for working with filesystem paths
2
3use std::path::Path;
4
5/// Tests whether `container_path` is equal to `nested_path` or is an ancestor of `nested_path`.
6pub fn path_contains(container_path: &str, nested_path: &str) -> bool {
7    let c_path = Path::new(container_path);
8    let n_path = Path::new(nested_path);
9
10    if c_path.is_absolute() != n_path.is_absolute() {
11        return false;
12    }
13
14    let mut ci = c_path.components();
15    let mut ni = n_path.components();
16
17    loop {
18        match (ci.next(), ni.next()) {
19            (Some(ce), Some(ne)) => {
20                // Ignore case, because Windows.
21                if !ce.as_os_str().eq_ignore_ascii_case(ne.as_os_str()) {
22                    return false;
23                }
24            }
25
26            // We ran out of nested elements, but still have more container elements. Not a match.
27            (Some(_), None) => return false,
28
29            // We ran out of container elements, so it's a match.
30            (None, _) => return true,
31        }
32    }
33}
34
35#[test]
36#[cfg(windows)]
37fn test_path_contains() {
38    assert!(!path_contains(r"d:\src", r"foo.c"));
39
40    assert!(path_contains(r"d:\src", r"d:\src\foo.c"));
41    assert!(path_contains(r"d:\src", r"D:\SRC\\foo.c"));
42    assert!(path_contains(r"d:\src\", r"d:\src"));
43    assert!(path_contains(r"d:\src", r"d:\src\"));
44
45    // negative cases
46    assert!(!path_contains(r"d:\src", r"e:\src\foo.c"));
47    assert!(!path_contains(r"d:\src", r"d:\bar"));
48}