I was experimenting with filtering directories when iterating over them and it surprised me that std::path::Path has starts_with and ends_with methods but no contains. contains in this context would check if a path contains a component like /my/test/dir contains test.
Now you could use the component iterator to accomplish this. However to me it seems like a simple utility which is a natural complement to starts_with and ends_with. Is there a reason for not having a contains method? If not should we consider implementing it?
When would you use it? After all, the meaning of a path depends on what comes before it. The only thing I can think of is checking for .., but in situations where you’re doing that you usually want to check other things about the path anyway (like whether it has a symlink in the middle).
One case I can think of is enforcing naming rules on other platforms. For example, /path/with/NUL/in/it is bad because Windows cannot represent this path given the reserved name NUL anywhere. However, the rules are complex enough that .contains() doesn't make sense even as such a solution IMO.
If all you want to do is check if a path contains some component, you can do that with path.iter().any(...): Rust Playground
But I would expect the actual use case for contains to span path components, like starts_with and ends_with do. It is possible to do a contains check as long as the path is representable as a string, even though there are some hoops to jump through.
This isn't saying anything about whether Path::contains() is justified. But if it is, it would be better than hoping that the path is representable as a string.
pub fn path_contains(haystack: &Path, needle: &Path) -> bool {
haystack.starts_with(needle) || {
let mut iter = haystack.iter();
_ = iter.next();
let rest = iter.as_path();
!rest.as_os_str().is_empty() && path_contains(rest, needle)
}
}
I don't think std can do much better internally than this external impl, basically only by swapping the terminal condition from haystack.len() == 0 to haystack.len() < needle.len()
My initial example was too simplistic. @parasyte's suggestion is more a long the lines of what I was thinking. Where Path::contains checks for a span of components similar to the example in @CAD97 's response.
@jrose My case was to check for commonly used directory names like .git, target, node_modules etc.
I was thinking about this incorrectly. It felt like a gap in the methods implemented for std::path::Path but I can see how this is probably not a common use case.