summaryrefslogtreecommitdiffstats
path: root/globset/src/pathutil.rs
diff options
context:
space:
mode:
Diffstat (limited to 'globset/src/pathutil.rs')
-rw-r--r--globset/src/pathutil.rs93
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());
}
};