It is isolated and complex enough that it deserves attention all on its own. It's also eminently reusable.
39 lines
1.1 KiB
Rust
39 lines
1.1 KiB
Rust
use std::ffi::OsStr;
|
|
use std::path::Path;
|
|
|
|
/// The final component of the path, if it is a normal file.
|
|
///
|
|
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
|
/// file_name will return None.
|
|
#[cfg(unix)]
|
|
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
|
path: &'a P,
|
|
) -> Option<&'a OsStr> {
|
|
use std::os::unix::ffi::OsStrExt;
|
|
use memchr::memrchr;
|
|
|
|
let path = path.as_ref().as_os_str().as_bytes();
|
|
if path.is_empty() {
|
|
return None;
|
|
} else if path.len() == 1 && path[0] == b'.' {
|
|
return None;
|
|
} else if path.last() == Some(&b'.') {
|
|
return None;
|
|
} else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] {
|
|
return None;
|
|
}
|
|
let last_slash = memrchr(b'/', path).map(|i| i + 1).unwrap_or(0);
|
|
Some(OsStr::from_bytes(&path[last_slash..]))
|
|
}
|
|
|
|
/// The final component of the path, if it is a normal file.
|
|
///
|
|
/// If the path terminates in ., .., or consists solely of a root of prefix,
|
|
/// file_name will return None.
|
|
#[cfg(not(unix))]
|
|
pub fn file_name<'a, P: AsRef<Path> + ?Sized>(
|
|
path: &'a P,
|
|
) -> Option<&'a OsStr> {
|
|
path.as_ref().file_name()
|
|
}
|