diff options
Diffstat (limited to 'globset/src/pathutil.rs')
-rw-r--r-- | globset/src/pathutil.rs | 93 |
1 files changed, 30 insertions, 63 deletions
diff --git a/globset/src/pathutil.rs b/globset/src/pathutil.rs index 4b808e86..62a68322 100644 --- a/globset/src/pathutil.rs +++ b/globset/src/pathutil.rs @@ -1,41 +1,30 @@ use std::borrow::Cow; -use std::ffi::OsStr; -use std::path::Path; + +use bstr::BStr; /// 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(); +pub fn file_name<'a>(path: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> { if path.is_empty() { return None; } else if path.len() == 1 && path[0] == b'.' { return None; - } else if path.last() == Some(&b'.') { + } else if path.last() == Some(b'.') { return None; - } else if path.len() >= 2 && &path[path.len() - 2..] == &b".."[..] { + } else if path.len() >= 2 && &path[path.len() - 2..] == ".." { 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() + let last_slash = path.rfind_byte(b'/').map(|i| i + 1).unwrap_or(0); + Some(match *path { + Cow::Borrowed(path) => Cow::Borrowed(&path[last_slash..]), + Cow::Owned(ref path) => { + let mut path = path.clone(); + path.drain_bytes(..last_slash); + Cow::Owned(path) + } + }) } /// Return a file extension given a path's file name. @@ -54,59 +43,34 @@ pub fn file_name<'a, P: AsRef<Path> + ?Sized>( /// a pattern like `*.rs` is obviously trying to match files with a `rs` /// extension, but it also matches files like `.rs`, which doesn't have an /// extension according to std::path::Path::extension. -pub fn file_name_ext(name: &OsStr) -> Option<Cow<[u8]>> { +pub fn file_name_ext<'a>(name: &Cow<'a, BStr>) -> Option<Cow<'a, BStr>> { if name.is_empty() { return None; } - let name = os_str_bytes(name); let last_dot_at = { let result = name - .iter().enumerate().rev() - .find(|&(_, &b)| b == b'.') + .bytes().enumerate().rev() + .find(|&(_, b)| b == b'.') .map(|(i, _)| i); match result { None => return None, Some(i) => i, } }; - Some(match name { + Some(match *name { Cow::Borrowed(name) => Cow::Borrowed(&name[last_dot_at..]), - Cow::Owned(mut name) => { - name.drain(..last_dot_at); + Cow::Owned(ref name) => { + let mut name = name.clone(); + name.drain_bytes(..last_dot_at); Cow::Owned(name) } }) } -/// Return raw bytes of a path, transcoded to UTF-8 if necessary. -pub fn path_bytes(path: &Path) -> Cow<[u8]> { - os_str_bytes(path.as_os_str()) -} - -/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8. -#[cfg(unix)] -pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> { - use std::os::unix::ffi::OsStrExt; - Cow::Borrowed(s.as_bytes()) -} - -/// Return the raw bytes of the given OS string, possibly transcoded to UTF-8. -#[cfg(not(unix))] -pub fn os_str_bytes(s: &OsStr) -> Cow<[u8]> { - // TODO(burntsushi): On Windows, OS strings are WTF-8, which is a superset - // of UTF-8, so even if we could get at the raw bytes, they wouldn't - // be useful. We *must* convert to UTF-8 before doing path matching. - // Unfortunate, but necessary. - match s.to_string_lossy() { - Cow::Owned(s) => Cow::Owned(s.into_bytes()), - Cow::Borrowed(s) => Cow::Borrowed(s.as_bytes()), - } -} - /// Normalizes a path to use `/` as a separator everywhere, even on platforms /// that recognize other characters as separators. #[cfg(unix)] -pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> { +pub fn normalize_path(path: Cow<BStr>) -> Cow<BStr> { // UNIX only uses /, so we're good. path } @@ -114,7 +78,7 @@ pub fn normalize_path(path: Cow<[u8]>) -> Cow<[u8]> { /// Normalizes a path to use `/` as a separator everywhere, even on platforms /// that recognize other characters as separators. #[cfg(not(unix))] -pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> { +pub fn normalize_path(mut path: Cow<BStr>) -> Cow<BStr> { use std::path::is_separator; for i in 0..path.len() { @@ -129,7 +93,8 @@ pub fn normalize_path(mut path: Cow<[u8]>) -> Cow<[u8]> { #[cfg(test)] mod tests { use std::borrow::Cow; - use std::ffi::OsStr; + + use bstr::{B, BString}; use super::{file_name_ext, normalize_path}; @@ -137,8 +102,9 @@ mod tests { ($name:ident, $file_name:expr, $ext:expr) => { #[test] fn $name() { - let got = file_name_ext(OsStr::new($file_name)); - assert_eq!($ext.map(|s| Cow::Borrowed(s.as_bytes())), got); + let bs = BString::from($file_name); + let got = file_name_ext(&Cow::Owned(bs)); + assert_eq!($ext.map(|s| Cow::Borrowed(B(s))), got); } }; } @@ -153,7 +119,8 @@ mod tests { ($name:ident, $path:expr, $expected:expr) => { #[test] fn $name() { - let got = normalize_path(Cow::Owned($path.to_vec())); + let bs = BString::from_slice($path); + let got = normalize_path(Cow::Owned(bs)); assert_eq!($expected.to_vec(), got.into_owned()); } }; |