Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Checking that a provided string is a single path component

Tags:

rust

I have a function that accepts a string which will be used to create a file with that name (e.g. f("foo") will create a /some/fixed/path/foo.txt file). I'd like to prevent users from mistakenly passing strings with / separators that would introduce additional sub-directories. Since PathBuf::push() accepts strings with multiple components (and, confusingly, so does PathBuf::set_file_name()) it doesn't seem possible to prevent pushing multiple components onto a PathBuf without a separate check first.

Naively, I could do a .contains() check:

assert!(!name.contains("/"), "name should be a single path element");

But obviously that's not cross-platform. There is path::is_separator() so I could do:

name.chars().any(std::path::is_separator)

Alternatively I looked at Path for any sort of is_single_component() check or similar, I could check the file_name() equals the whole path:

let name = Path::new(name);
assert_eq!(Some(name.as_os_str()), name.file_name(),
           "name should be a single path element");

or that iterating over the path yields one element:

assert_eq!(Path::new(name).iter().count(), 1,
           "name should be a single path element");

I'm leaning towards this last approach, but I'm just curious if there's a more idiomatic way to ensure pushing a string onto a PathBuf will just add one path component.

like image 246
dimo414 Avatar asked May 13 '26 20:05

dimo414


1 Answers

If you are fine with limiting yourself to path names that are valid UTF-8, I suggest this succinct implementation:

fn has_single_component(path: &str) -> bool {
    !path.contains(std::path::is_separator)
}

In contrast to your Path-based approaches, it will stop at the first separator found, and it's easy to read.

Note that testing whether a path only consists of a single component is a rather uncommon thing to do, so there isn't a standard way of doing it.

like image 147
Sven Marnach Avatar answered May 15 '26 17:05

Sven Marnach