diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/path2/mod.rs | 23 | ||||
| -rw-r--r-- | src/libstd/path2/posix.rs | 68 | ||||
| -rw-r--r-- | src/libstd/path2/windows.rs | 79 |
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"]); + } } |
