about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/path2/mod.rs23
-rw-r--r--src/libstd/path2/posix.rs68
-rw-r--r--src/libstd/path2/windows.rs79
3 files changed, 152 insertions, 18 deletions
diff --git a/src/libstd/path2/mod.rs b/src/libstd/path2/mod.rs
index 5831b200e09..ba572cce78a 100644
--- a/src/libstd/path2/mod.rs
+++ b/src/libstd/path2/mod.rs
@@ -540,13 +540,13 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
     }
     /// Pops the last path component off of `self` and returns it.
     /// If `self` represents the root of the file hierarchy, None is returned.
-    fn pop_opt(&mut self) -> Option<~[u8]>;
+    fn pop(&mut self) -> Option<~[u8]>;
     /// Pops the last path component off of `self` and returns it as a string, if possible.
     /// `self` will still be modified even if None is returned.
-    /// See `pop_opt` for details.
+    /// See `pop` for details.
     #[inline]
-    fn pop_opt_str(&mut self) -> Option<~str> {
-        self.pop_opt().and_then(|v| str::from_utf8_owned_opt(v))
+    fn pop_str(&mut self) -> Option<~str> {
+        self.pop().and_then(|v| str::from_utf8_owned_opt(v))
     }
 
     /// Returns a new Path constructed by joining `self` with the given path (as a byte vector).
@@ -593,6 +593,21 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
     /// If `self` is absolute and `base` is relative, or on Windows if both
     /// paths refer to separate drives, an absolute path is returned.
     fn path_relative_from(&self, base: &Self) -> Option<Self>;
+
+    /// Executes a callback with the receiver and every parent
+    fn each_parent(&self, f: &fn(&Self) -> bool) -> bool {
+        let mut p = self.clone();
+        loop {
+            if !f(&p) {
+                return false;
+            }
+            let f = p.pop();
+            if f.is_none() || bytes!("..") == f.unwrap() {
+                break;
+            }
+        }
+        true
+    }
 }
 
 /// A trait that represents the unsafe operations on GenericPaths
diff --git a/src/libstd/path2/posix.rs b/src/libstd/path2/posix.rs
index 8e928f1df78..233458dfc9b 100644
--- a/src/libstd/path2/posix.rs
+++ b/src/libstd/path2/posix.rs
@@ -196,7 +196,7 @@ impl GenericPath for Path {
         }
     }
 
-    fn pop_opt(&mut self) -> Option<~[u8]> {
+    fn pop(&mut self) -> Option<~[u8]> {
         match self.sepidx {
             None if bytes!(".") == self.repr => None,
             None => {
@@ -400,7 +400,7 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<~[&'a [u8]]> {
         else if comp == bytes!("..") {
             if is_abs && comps.is_empty() { changed = true }
             else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 }
-            else { comps.pop_opt(); changed = true }
+            else { comps.pop(); changed = true }
         } else { comps.push(comp) }
     }
     if changed {
@@ -861,7 +861,7 @@ mod tests {
             (s: $path:expr, $left:expr, $right:expr) => (
                 {
                     let mut p = Path::from_str($path);
-                    let file = p.pop_opt_str();
+                    let file = p.pop_str();
                     assert_eq!(p.as_str(), Some($left));
                     assert_eq!(file.map(|s| s.as_slice()), $right);
                 }
@@ -869,7 +869,7 @@ mod tests {
             (v: [$($path:expr),+], [$($left:expr),+], Some($($right:expr),+)) => (
                 {
                     let mut p = Path::from_vec(b!($($path),+));
-                    let file = p.pop_opt();
+                    let file = p.pop();
                     assert_eq!(p.as_vec(), b!($($left),+));
                     assert_eq!(file.map(|v| v.as_slice()), Some(b!($($right),+)));
                 }
@@ -877,7 +877,7 @@ mod tests {
             (v: [$($path:expr),+], [$($left:expr),+], None) => (
                 {
                     let mut p = Path::from_vec(b!($($path),+));
-                    let file = p.pop_opt();
+                    let file = p.pop();
                     assert_eq!(p.as_vec(), b!($($left),+));
                     assert_eq!(file, None);
                 }
@@ -899,8 +899,8 @@ mod tests {
         t!(s: "/a", "/", Some("a"));
         t!(s: "/", "/", None);
 
-        assert_eq!(Path::from_vec(b!("foo/bar", 0x80)).pop_opt_str(), None);
-        assert_eq!(Path::from_vec(b!("foo", 0x80, "/bar")).pop_opt_str(), Some(~"bar"));
+        assert_eq!(Path::from_vec(b!("foo/bar", 0x80)).pop_str(), None);
+        assert_eq!(Path::from_vec(b!("foo", 0x80, "/bar")).pop_str(), Some(~"bar"));
     }
 
     #[test]
@@ -1310,4 +1310,58 @@ mod tests {
         t!(s: "../..", ["..", ".."]);
         t!(s: "../../foo", ["..", "..", "foo"]);
     }
+
+    #[test]
+    fn test_each_parent() {
+        assert!(Path::from_str("/foo/bar").each_parent(|_| true));
+        assert!(!Path::from_str("/foo/bar").each_parent(|_| false));
+
+        macro_rules! t(
+            (s: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::from_str($path);
+                    let exp: &[&str] = $exp;
+                    let mut comps = exp.iter().map(|&x|x);
+                    do path.each_parent |p| {
+                        let p = p.as_str();
+                        assert!(p.is_some());
+                        let e = comps.next();
+                        assert!(e.is_some());
+                        assert_eq!(p.unwrap(), e.unwrap());
+                        true
+                    };
+                    assert!(comps.next().is_none());
+                }
+            );
+            (v: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::from_vec($path);
+                    let exp: &[&[u8]] = $exp;
+                    let mut comps = exp.iter().map(|&x|x);
+                    do path.each_parent |p| {
+                        let p = p.as_vec();
+                        let e = comps.next();
+                        assert!(e.is_some());
+                        assert_eq!(p, e.unwrap());
+                        true
+                    };
+                    assert!(comps.next().is_none());
+                }
+            )
+        )
+
+        t!(s: "/foo/bar", ["/foo/bar", "/foo", "/"]);
+        t!(s: "/foo/bar/baz", ["/foo/bar/baz", "/foo/bar", "/foo", "/"]);
+        t!(s: "/foo", ["/foo", "/"]);
+        t!(s: "/", ["/"]);
+        t!(s: "foo/bar/baz", ["foo/bar/baz", "foo/bar", "foo", "."]);
+        t!(s: "foo/bar", ["foo/bar", "foo", "."]);
+        t!(s: "foo", ["foo", "."]);
+        t!(s: ".", ["."]);
+        t!(s: "..", [".."]);
+        t!(s: "../../foo", ["../../foo", "../.."]);
+
+        t!(v: b!("foo/bar", 0x80), [b!("foo/bar", 0x80), b!("foo"), b!(".")]);
+        t!(v: b!(0xff, "/bar"), [b!(0xff, "/bar"), b!(0xff), b!(".")]);
+    }
 }
diff --git a/src/libstd/path2/windows.rs b/src/libstd/path2/windows.rs
index 728adf25ae1..c23dc86d7df 100644
--- a/src/libstd/path2/windows.rs
+++ b/src/libstd/path2/windows.rs
@@ -446,11 +446,11 @@ impl GenericPath for Path {
     }
 
     #[inline]
-    fn pop_opt(&mut self) -> Option<~[u8]> {
-        self.pop_opt_str().map_move(|s| s.into_bytes())
+    fn pop(&mut self) -> Option<~[u8]> {
+        self.pop_str().map_move(|s| s.into_bytes())
     }
 
-    fn pop_opt_str(&mut self) -> Option<~str> {
+    fn pop_str(&mut self) -> Option<~str> {
         match self.sepidx_or_prefix_len() {
             None if "." == self.repr => None,
             None => {
@@ -599,6 +599,21 @@ impl GenericPath for Path {
             Some(Path::from_str(comps.connect("\\")))
         }
     }
+
+    /// Executes a callback with the receiver and every parent
+    fn each_parent(&self, f: &fn(&Path) -> bool) -> bool {
+        let mut p = self.clone();
+        loop {
+            if !f(&p) {
+                return false;
+            }
+            let f = p.pop();
+            if f.is_none() || (!p.is_verbatim() && bytes!("..") == f.unwrap()) {
+                break;
+            }
+        }
+        true
+    }
 }
 
 impl Path {
@@ -1013,7 +1028,7 @@ fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<
             };
             if (is_abs || has_abs_prefix) && comps.is_empty() { changed = true }
             else if comps.len() == n_up { comps.push(".."); n_up += 1 }
-            else { comps.pop_opt(); changed = true }
+            else { comps.pop(); changed = true }
         } else { comps.push(comp) }
     }
     if !changed && !prefix_is_verbatim(prefix) {
@@ -1654,7 +1669,7 @@ mod tests {
                 {
                     let pstr = $path;
                     let mut p = Path::from_str(pstr);
-                    let file = p.pop_opt_str();
+                    let file = p.pop_str();
                     let left = $left;
                     assert!(p.as_str() == Some(left),
                         "`%s`.pop() failed; expected remainder `%s`, found `%s`",
@@ -1668,7 +1683,7 @@ mod tests {
             (v: [$($path:expr),+], [$($left:expr),+], Some($($right:expr),+)) => (
                 {
                     let mut p = Path::from_vec(b!($($path),+));
-                    let file = p.pop_opt();
+                    let file = p.pop();
                     assert_eq!(p.as_vec(), b!($($left),+));
                     assert_eq!(file.map(|v| v.as_slice()), Some(b!($($right),+)));
                 }
@@ -1676,7 +1691,7 @@ mod tests {
             (v: [$($path:expr),+], [$($left:expr),+], None) => (
                 {
                     let mut p = Path::from_vec(b!($($path),+));
-                    let file = p.pop_opt();
+                    let file = p.pop();
                     assert_eq!(p.as_vec(), b!($($left),+));
                     assert_eq!(file, None);
                 }
@@ -2373,4 +2388,54 @@ mod tests {
         t!(s: "\\\\.\\foo\\bar", ["bar"]);
         t!(s: "\\\\.\\foo", []);
     }
+
+    #[test]
+    fn test_each_parent() {
+        assert!(Path::from_str("/foo/bar").each_parent(|_| true));
+        assert!(!Path::from_str("/foo/bar").each_parent(|_| false));
+
+        macro_rules! t(
+            (s: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::from_str($path);
+                    let exp: &[&str] = $exp;
+                    let mut comps = exp.iter().map(|&x|x);
+                    do path.each_parent |p| {
+                        let p = p.as_str();
+                        assert!(p.is_some());
+                        let e = comps.next();
+                        assert!(e.is_some());
+                        assert_eq!(p.unwrap(), e.unwrap());
+                        true
+                    };
+                    assert!(comps.next().is_none());
+                }
+            )
+        )
+
+        t!(s: "\\foo\\bar", ["\\foo\\bar", "\\foo", "\\"]);
+        t!(s: "\\foo\\bar\\baz", ["\\foo\\bar\\baz", "\\foo\\bar", "\\foo", "\\"]);
+        t!(s: "\\foo", ["\\foo", "\\"]);
+        t!(s: "\\", ["\\"]);
+        t!(s: "foo\\bar\\baz", ["foo\\bar\\baz", "foo\\bar", "foo", "."]);
+        t!(s: "foo\\bar", ["foo\\bar", "foo", "."]);
+        t!(s: "foo", ["foo", "."]);
+        t!(s: ".", ["."]);
+        t!(s: "..", [".."]);
+        t!(s: "..\\..\\foo", ["..\\..\\foo", "..\\.."]);
+        t!(s: "C:\\a\\b", ["C:\\a\\b", "C:\\a", "C:\\"]);
+        t!(s: "C:\\", ["C:\\"]);
+        t!(s: "C:a\\b", ["C:a\\b", "C:a", "C:"]);
+        t!(s: "C:", ["C:"]);
+        t!(s: "C:..\\..\\a", ["C:..\\..\\a", "C:..\\.."]);
+        t!(s: "C:..", ["C:.."]);
+        t!(s: "\\\\a\\b\\c", ["\\\\a\\b\\c", "\\\\a\\b"]);
+        t!(s: "\\\\a\\b", ["\\\\a\\b"]);
+        t!(s: "\\\\?\\a\\b\\c", ["\\\\?\\a\\b\\c", "\\\\?\\a\\b", "\\\\?\\a"]);
+        t!(s: "\\\\?\\C:\\a\\b", ["\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", "\\\\?\\C:\\"]);
+        t!(s: "\\\\?\\UNC\\a\\b\\c", ["\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b"]);
+        t!(s: "\\\\.\\a\\b\\c", ["\\\\.\\a\\b\\c", "\\\\.\\a\\b", "\\\\.\\a"]);
+        t!(s: "\\\\?\\a\\..\\b\\.\\c/d", ["\\\\?\\a\\..\\b\\.\\c/d", "\\\\?\\a\\..\\b\\.",
+                                          "\\\\?\\a\\..\\b", "\\\\?\\a\\..", "\\\\?\\a"]);
+    }
 }