summaryrefslogtreecommitdiffstats
path: root/src/pathutil.rs
diff options
context:
space:
mode:
authorAndrew Gallant <jamslam@gmail.com>2016-09-15 22:06:04 -0400
committerAndrew Gallant <jamslam@gmail.com>2016-09-15 22:06:04 -0400
commit0e46171e3b189b2bd89f45c3a492dea36361d8bc (patch)
tree3ae494e5fcf54c3a679ae42991050c78c7552dce /src/pathutil.rs
parentf5c85827cea05d11e1c0c50aa34e07361313f659 (diff)
Rework glob sets.
We try to reduce the pressure on regexes and offload some of it to Aho-Corasick or exact lookups.
Diffstat (limited to 'src/pathutil.rs')
-rw-r--r--src/pathutil.rs80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/pathutil.rs b/src/pathutil.rs
new file mode 100644
index 00000000..e92416e5
--- /dev/null
+++ b/src/pathutil.rs
@@ -0,0 +1,80 @@
+/*!
+The pathutil module provides platform specific operations on paths that are
+typically faster than the same operations as provided in std::path. In
+particular, we really want to avoid the costly operation of parsing the path
+into its constituent components. We give up on Windows, but on Unix, we deal
+with the raw bytes directly.
+
+On large repositories (like chromium), this can have a ~25% performance
+improvement on just listing the files to search (!).
+*/
+use std::ffi::OsStr;
+use std::path::Path;
+
+/// Strip `prefix` from the `path` and return the remainder.
+///
+/// If `path` doesn't have a prefix `prefix`, then return `None`.
+#[cfg(unix)]
+pub fn strip_prefix<'a, P: AsRef<Path>>(
+ prefix: P,
+ path: &'a Path,
+) -> Option<&'a Path> {
+ use std::os::unix::ffi::OsStrExt;
+
+ let prefix = prefix.as_ref().as_os_str().as_bytes();
+ let path = path.as_os_str().as_bytes();
+ if prefix.len() > path.len() || prefix != &path[0..prefix.len()] {
+ None
+ } else {
+ Some(&Path::new(OsStr::from_bytes(&path[prefix.len()..])))
+ }
+}
+
+/// Strip `prefix` from the `path` and return the remainder.
+///
+/// If `path` doesn't have a prefix `prefix`, then return `None`.
+#[cfg(not(unix))]
+pub fn strip_prefix<'a>(prefix: &Path, path: &'a Path) -> Option<&'a Path> {
+ path.strip_prefix(prefix).ok()
+}
+
+/// 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;
+
+ 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 mut last_slash = 0;
+ for (i, &b) in path.iter().enumerate().rev() {
+ if b == b'/' {
+ last_slash = i;
+ break;
+ }
+ }
+ Some(OsStr::from_bytes(&path[last_slash + 1..]))
+}
+
+/// 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()
+}