about summary refs log tree commit diff
path: root/src/libstd/path
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2013-10-07 19:16:58 -0700
committerKevin Ballard <kevin@sb.org>2013-10-16 10:26:48 -0700
commitbab7eb20dff32294c65fa28cece552481c40cf0b (patch)
treefc81daee54a1f01c62c792ccbfba362e61d52d76 /src/libstd/path
parentc01a97b7a981fb5ae008be7e06df4bf6a85eba4f (diff)
downloadrust-bab7eb20dff32294c65fa28cece552481c40cf0b.tar.gz
rust-bab7eb20dff32294c65fa28cece552481c40cf0b.zip
path2: Update based on more review feedback
Standardize the is_sep() functions to be the same in both posix and
windows, and re-export from path. Update extra::glob to use this.

Remove the usage of either, as it's going away.

Move the WindowsPath-specific methods out of WindowsPath and make them
top-level functions of path::windows instead. This way you cannot
accidentally write code that will fail to compile on non-windows
architectures without typing ::windows anywhere.

Remove GenericPath::from_c_str() and just impl BytesContainer for
CString instead.

Remove .join_path() and .push_path() and just implement BytesContainer
for Path instead.

Remove FilenameDisplay and add a boolean flag to Display instead.

Remove .each_parent(). It only had one caller, so just inline its
definition there.
Diffstat (limited to 'src/libstd/path')
-rw-r--r--src/libstd/path/mod.rs156
-rw-r--r--src/libstd/path/posix.rs131
-rw-r--r--src/libstd/path/windows.rs247
3 files changed, 217 insertions, 317 deletions
diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs
index ff370e9d7c1..278a4ab36ff 100644
--- a/src/libstd/path/mod.rs
+++ b/src/libstd/path/mod.rs
@@ -30,9 +30,7 @@ no restriction on paths beyond disallowing NUL).
 ## Usage
 
 Usage of this module is fairly straightforward. Unless writing platform-specific
-code, `Path` should be used to refer to the platform-native path, and methods
-used should be restricted to those defined in `GenericPath`, and those methods
-that are declared identically on both `PosixPath` and `WindowsPath`.
+code, `Path` should be used to refer to the platform-native path.
 
 Creation of a path is typically done with either `Path::new(some_str)` or
 `Path::new(some_vec)`. This path can be modified with `.push()` and
@@ -69,7 +67,6 @@ debug2!("path exists: {}", b);
 use container::Container;
 use c_str::CString;
 use clone::Clone;
-use either::{Left, Right};
 use fmt;
 use iter::Iterator;
 use option::{Option, None, Some};
@@ -121,6 +118,19 @@ pub use StrComponentIter = self::windows::StrComponentIter;
 #[cfg(windows)]
 pub use RevStrComponentIter = self::windows::RevStrComponentIter;
 
+/// Typedef for the platform-native separator char func
+#[cfg(unix)]
+pub use is_sep = self::posix::is_sep;
+/// Typedef for the platform-native separator char func
+#[cfg(windows)]
+pub use is_sep = self::windows::is_sep;
+/// Typedef for the platform-native separator byte func
+#[cfg(unix)]
+pub use is_sep_byte = self::posix::is_sep_byte;
+/// Typedef for the platform-native separator byte func
+#[cfg(windows)]
+pub use is_sep_byte = self::windows::is_sep_byte;
+
 pub mod posix;
 pub mod windows;
 
@@ -162,19 +172,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
         }
     }
 
-    /// Creates a new Path from a CString.
-    /// The resulting Path will always be normalized.
-    ///
-    /// See individual Path impls for potential restrictions.
-    #[inline]
-    fn from_c_str(path: CString) -> Self {
-        // CStrings can't contain NULs
-        let v = path.as_bytes();
-        // v is NUL-terminated. Strip it off
-        let v = v.slice_to(v.len()-1);
-        unsafe { GenericPathUnsafe::new_unchecked(v) }
-    }
-
     /// Returns the path as a string, if possible.
     /// If the path is not representable in utf-8, this returns None.
     #[inline]
@@ -195,15 +192,15 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
     ///
     /// This will print the equivalent of `to_display_str()` when used with a {} format parameter.
     fn display<'a>(&'a self) -> Display<'a, Self> {
-        Display{ path: self }
+        Display{ path: self, filename: false }
     }
 
     /// Returns an object that implements `fmt::Default` for printing filenames
     ///
     /// This will print the equivalent of `to_filename_display_str()` when used with a {}
     /// format parameter. If there is no filename, nothing will be printed.
-    fn filename_display<'a>(&'a self) -> FilenameDisplay<'a, Self> {
-        FilenameDisplay{ path: self }
+    fn filename_display<'a>(&'a self) -> Display<'a, Self> {
+        Display{ path: self, filename: true }
     }
 
     /// Returns the directory component of `self`, as a byte vector (with no trailing separator).
@@ -314,13 +311,17 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
     /// Raises the `null_byte` condition if the filestem contains a NUL.
     fn set_filestem<T: BytesContainer>(&mut self, filestem: T) {
         // borrowck is being a pain here
+        enum Value<T> {
+            Checked(T),
+            Unchecked(~[u8])
+        }
         let val = {
             match self.filename() {
-                None => Left(filestem),
+                None => Checked(filestem),
                 Some(name) => {
                     let dot = '.' as u8;
                     match name.rposition_elem(&dot) {
-                        None | Some(0) => Left(filestem),
+                        None | Some(0) => Checked(filestem),
                         Some(idx) => {
                             let mut v;
                             if contains_nul(filestem.container_as_bytes()) {
@@ -336,15 +337,15 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
                                 v.push_all(filestem);
                             }
                             v.push_all(name.slice_from(idx));
-                            Right(v)
+                            Unchecked(v)
                         }
                     }
                 }
             }
         };
         match val {
-            Left(v)  => self.set_filename(v),
-            Right(v) => unsafe { self.set_filename_unchecked(v) }
+            Checked(v)  => self.set_filename(v),
+            Unchecked(v) => unsafe { self.set_filename_unchecked(v) }
         }
     }
     /// Replaces the extension with the given byte vector or string.
@@ -545,12 +546,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
             unsafe { self.push_unchecked(path) }
         }
     }
-    /// Pushes a Path onto `self`.
-    /// If the argument represents an absolute path, it replaces `self`.
-    #[inline]
-    fn push_path(&mut self, path: &Self) {
-        self.push(path.as_vec())
-    }
     /// Pushes multiple paths (as byte vectors or strings) onto `self`.
     /// See `push` for details.
     #[inline]
@@ -590,14 +585,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
         p.push(path);
         p
     }
-    /// Returns a new Path constructed by joining `self` with the given path.
-    /// If the given path is absolute, the new Path will represent just that.
-    #[inline]
-    fn join_path(&self, path: &Self) -> Self {
-        let mut p = self.clone();
-        p.push_path(path);
-        p
-    }
     /// Returns a new Path constructed by joining `self` with the given paths
     /// (as byte vectors or strings).
     /// See `join` for details.
@@ -632,21 +619,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
     /// 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
-    }
-
     /// Returns whether the relative path `child` is a suffix of `self`.
     fn ends_with_path(&self, child: &Self) -> bool;
 }
@@ -674,7 +646,7 @@ pub trait BytesContainer {
     fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
         str::from_utf8_slice_opt(self.container_as_bytes())
     }
-    /// Returns whether the concrete receiver is a string type
+    /// Returns whether .container_as_str() is guaranteed to not fail
     // FIXME (#8888): Remove unused arg once ::<for T> works
     #[inline]
     fn is_str(_: Option<Self>) -> bool { false }
@@ -703,11 +675,8 @@ pub trait GenericPathUnsafe {
 
 /// Helper struct for printing paths with format!()
 pub struct Display<'self, P> {
-    priv path: &'self P
-}
-/// Helper struct for printing filenames with format!()
-pub struct FilenameDisplay<'self, P> {
-    priv path: &'self P
+    priv path: &'self P,
+    priv filename: bool
 }
 
 impl<'self, P: GenericPath> fmt::Default for Display<'self, P> {
@@ -724,7 +693,14 @@ impl<'self, P: GenericPath> ToStr for Display<'self, P> {
     /// If the path is not UTF-8, invalid sequences with be replaced with the
     /// unicode replacement char. This involves allocation.
     fn to_str(&self) -> ~str {
-        from_utf8_with_replacement(self.path.as_vec())
+        if self.filename {
+            match self.path.filename() {
+                None => ~"",
+                Some(v) => from_utf8_with_replacement(v)
+            }
+        } else {
+            from_utf8_with_replacement(self.path.as_vec())
+        }
     }
 }
 
@@ -735,47 +711,9 @@ impl<'self, P: GenericPath> Display<'self, P> {
     /// unicode replacement char. This involves allocation.
     #[inline]
     pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T {
-        match self.path.as_str() {
-            Some(s) => f(s),
-            None => {
-                let s = self.to_str();
-                f(s.as_slice())
-            }
-        }
-    }
-}
-
-impl<'self, P: GenericPath> fmt::Default for FilenameDisplay<'self, P> {
-    fn fmt(d: &FilenameDisplay<P>, f: &mut fmt::Formatter) {
-        do d.with_str |s| {
-            f.pad(s)
-        }
-    }
-}
-
-impl<'self, P: GenericPath> ToStr for FilenameDisplay<'self, P> {
-    /// Returns the filename as a string. If there is no filename, ~"" will be
-    /// returned.
-    ///
-    /// If the filename is not UTF-8, invalid sequences will be replaced with
-    /// the unicode replacement char. This involves allocation.
-    fn to_str(&self) -> ~str {
-        match self.path.filename() {
-            None => ~"",
-            Some(v) => from_utf8_with_replacement(v)
-        }
-    }
-}
-
-impl<'self, P: GenericPath> FilenameDisplay<'self, P> {
-    /// Provides the filename as a string to a closure. If there is no
-    /// filename, "" will be provided.
-    ///
-    /// If the filename is not UTF-8, invalid sequences will be replaced with
-    /// the unicode replacement char. This involves allocation.
-    #[inline]
-    pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T {
-        match self.path.filename_str() {
+        let opt = if self.filename { self.path.filename_str() }
+                  else { self.path.as_str() };
+        match opt {
             Some(s) => f(s),
             None => {
                 let s = self.to_str();
@@ -865,6 +803,14 @@ impl BytesContainer for @[u8] {
     }
 }
 
+impl BytesContainer for CString {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        let s = self.as_bytes();
+        s.slice_to(s.len()-1)
+    }
+}
+
 #[inline(always)]
 fn contains_nul(v: &[u8]) -> bool {
     v.iter().any(|&x| x == 0)
@@ -1121,13 +1067,13 @@ mod tests {
     use c_str::ToCStr;
 
     #[test]
-    fn test_from_c_str() {
+    fn test_cstring() {
         let input = "/foo/bar/baz";
-        let path: PosixPath = GenericPath::from_c_str(input.to_c_str());
+        let path: PosixPath = PosixPath::new(input.to_c_str());
         assert_eq!(path.as_vec(), input.as_bytes());
 
         let input = "\\foo\\bar\\baz";
-        let path: WindowsPath = GenericPath::from_c_str(input.to_c_str());
+        let path: WindowsPath = WindowsPath::new(input.to_c_str());
         assert_eq!(path.as_str().unwrap(), input.as_slice());
     }
 }
diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs
index 8acc1346bcc..fdc943fb882 100644
--- a/src/libstd/path/posix.rs
+++ b/src/libstd/path/posix.rs
@@ -48,12 +48,19 @@ pub struct Path {
 }
 
 /// The standard path separator character
-pub static sep: u8 = '/' as u8;
+pub static sep: char = '/';
+static sep_byte: u8 = sep as u8;
 
 /// Returns whether the given byte is a path separator
 #[inline]
-pub fn is_sep(u: &u8) -> bool {
-    *u == sep
+pub fn is_sep_byte(u: &u8) -> bool {
+    *u as char == sep
+}
+
+/// Returns whether the given char is a path separator
+#[inline]
+pub fn is_sep(c: char) -> bool {
+    c == sep
 }
 
 impl Eq for Path {
@@ -89,11 +96,29 @@ impl IterBytes for Path {
     }
 }
 
+impl BytesContainer for Path {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_vec()
+    }
+    #[inline]
+    fn container_into_owned_bytes(self) -> ~[u8] {
+        self.into_vec()
+    }
+}
+
+impl<'self> BytesContainer for &'self Path {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_vec()
+    }
+}
+
 impl GenericPathUnsafe for Path {
     unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
         let path = Path::normalize(path.container_as_bytes());
         assert!(!path.is_empty());
-        let idx = path.rposition_elem(&sep);
+        let idx = path.rposition_elem(&sep_byte);
         Path{ repr: path, sepidx: idx }
     }
 
@@ -106,11 +131,11 @@ impl GenericPathUnsafe for Path {
             None => {
                 let mut v = vec::with_capacity(dirname.len() + self.repr.len() + 1);
                 v.push_all(dirname);
-                v.push(sep);
+                v.push(sep_byte);
                 v.push_all(self.repr);
                 self.repr = Path::normalize(v);
             }
-            Some(0) if self.repr.len() == 1 && self.repr[0] == sep => {
+            Some(0) if self.repr.len() == 1 && self.repr[0] == sep_byte => {
                 self.repr = Path::normalize(dirname);
             }
             Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
@@ -127,7 +152,7 @@ impl GenericPathUnsafe for Path {
                 self.repr = Path::normalize(v);
             }
         }
-        self.sepidx = self.repr.rposition_elem(&sep);
+        self.sepidx = self.repr.rposition_elem(&sep_byte);
     }
 
     unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
@@ -136,7 +161,7 @@ impl GenericPathUnsafe for Path {
             None if bytes!("..") == self.repr => {
                 let mut v = vec::with_capacity(3 + filename.len());
                 v.push_all(dot_dot_static);
-                v.push(sep);
+                v.push(sep_byte);
                 v.push_all(filename);
                 self.repr = Path::normalize(v);
             }
@@ -146,7 +171,7 @@ impl GenericPathUnsafe for Path {
             Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
                 let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
                 v.push_all(self.repr);
-                v.push(sep);
+                v.push(sep_byte);
                 v.push_all(filename);
                 self.repr = Path::normalize(v);
             }
@@ -157,22 +182,22 @@ impl GenericPathUnsafe for Path {
                 self.repr = Path::normalize(v);
             }
         }
-        self.sepidx = self.repr.rposition_elem(&sep);
+        self.sepidx = self.repr.rposition_elem(&sep_byte);
     }
 
     unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
         let path = path.container_as_bytes();
         if !path.is_empty() {
-            if path[0] == sep {
+            if path[0] == sep_byte {
                 self.repr = Path::normalize(path);
             }  else {
                 let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
                 v.push_all(self.repr);
-                v.push(sep);
+                v.push(sep_byte);
                 v.push_all(path);
                 self.repr = Path::normalize(v);
             }
-            self.sepidx = self.repr.rposition_elem(&sep);
+            self.sepidx = self.repr.rposition_elem(&sep_byte);
         }
     }
 }
@@ -228,7 +253,7 @@ impl GenericPath for Path {
                 } else {
                     self.repr.truncate(idx);
                 }
-                self.sepidx = self.repr.rposition_elem(&sep);
+                self.sepidx = self.repr.rposition_elem(&sep_byte);
                 Some(v)
             }
         }
@@ -244,7 +269,7 @@ impl GenericPath for Path {
 
     #[inline]
     fn is_absolute(&self) -> bool {
-        self.repr[0] == sep
+        self.repr[0] == sep_byte
     }
 
     fn is_ancestor_of(&self, other: &Path) -> bool {
@@ -305,7 +330,7 @@ impl GenericPath for Path {
                     }
                 }
             }
-            Some(Path::new(comps.connect_vec(&sep)))
+            Some(Path::new(comps.connect_vec(&sep_byte)))
         }
     }
 
@@ -347,14 +372,14 @@ impl Path {
     fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
         // borrowck is being very picky
         let val = {
-            let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == sep;
+            let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == sep_byte;
             let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
             let comps = normalize_helper(v_, is_abs);
             match comps {
                 None => None,
                 Some(comps) => {
                     if is_abs && comps.is_empty() {
-                        Some(~[sep])
+                        Some(~[sep_byte])
                     } else {
                         let n = if is_abs { comps.len() } else { comps.len() - 1} +
                                 comps.iter().map(|v| v.len()).sum();
@@ -367,7 +392,7 @@ impl Path {
                             }
                         }
                         for comp in it {
-                            v.push(sep);
+                            v.push(sep_byte);
                             v.push_all(comp);
                         }
                         Some(v)
@@ -386,10 +411,10 @@ impl Path {
     /// /a/b/c and a/b/c yield the same set of components.
     /// A path of "/" yields no components. A path of "." yields one component.
     pub fn component_iter<'a>(&'a self) -> ComponentIter<'a> {
-        let v = if self.repr[0] == sep {
+        let v = if self.repr[0] == sep_byte {
             self.repr.slice_from(1)
         } else { self.repr.as_slice() };
-        let mut ret = v.split_iter(is_sep);
+        let mut ret = v.split_iter(is_sep_byte);
         if v.is_empty() {
             // consume the empty "" component
             ret.next();
@@ -400,10 +425,10 @@ impl Path {
     /// Returns an iterator that yields each component of the path in reverse.
     /// See component_iter() for details.
     pub fn rev_component_iter<'a>(&'a self) -> RevComponentIter<'a> {
-        let v = if self.repr[0] == sep {
+        let v = if self.repr[0] == sep_byte {
             self.repr.slice_from(1)
         } else { self.repr.as_slice() };
-        let mut ret = v.rsplit_iter(is_sep);
+        let mut ret = v.rsplit_iter(is_sep_byte);
         if v.is_empty() {
             // consume the empty "" component
             ret.next();
@@ -432,7 +457,7 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<~[&'a [u8]]> {
     let mut comps: ~[&'a [u8]] = ~[];
     let mut n_up = 0u;
     let mut changed = false;
-    for comp in v.split_iter(is_sep) {
+    for comp in v.split_iter(is_sep_byte) {
         if comp.is_empty() { changed = true }
         else if comp == bytes!(".") { changed = true }
         else if comp == bytes!("..") {
@@ -928,7 +953,7 @@ mod tests {
                 {
                     let mut p = Path::new($path);
                     let push = Path::new($push);
-                    p.push_path(&push);
+                    p.push(&push);
                     assert_eq!(p.as_str(), Some($exp));
                 }
             )
@@ -1049,7 +1074,7 @@ mod tests {
                 {
                     let path = Path::new($path);
                     let join = Path::new($join);
-                    let res = path.join_path(&join);
+                    let res = path.join(&join);
                     assert_eq!(res.as_str(), Some($exp));
                 }
             )
@@ -1598,58 +1623,4 @@ mod tests {
         // str_component_iter is a wrapper around component_iter, so no need to do
         // the full set of tests
     }
-
-    #[test]
-    fn test_each_parent() {
-        assert!(Path::new("/foo/bar").each_parent(|_| true));
-        assert!(!Path::new("/foo/bar").each_parent(|_| false));
-
-        macro_rules! t(
-            (s: $path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($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::new($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/path/windows.rs b/src/libstd/path/windows.rs
index 86c4bb6f8a3..5f8e1dc58fa 100644
--- a/src/libstd/path/windows.rs
+++ b/src/libstd/path/windows.rs
@@ -121,6 +121,44 @@ impl IterBytes for Path {
     }
 }
 
+impl BytesContainer for Path {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_vec()
+    }
+    #[inline]
+    fn container_into_owned_bytes(self) -> ~[u8] {
+        self.into_vec()
+    }
+    #[inline]
+    fn container_as_str<'a>(&'a self) -> &'a str {
+        self.as_str().unwrap()
+    }
+    #[inline]
+    fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
+        self.as_str()
+    }
+    #[inline]
+    fn is_str(_: Option<Path>) -> bool { true }
+}
+
+impl<'self> BytesContainer for &'self Path {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_vec()
+    }
+    #[inline]
+    fn container_as_str<'a>(&'a self) -> &'a str {
+        self.as_str().unwrap()
+    }
+    #[inline]
+    fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
+        self.as_str()
+    }
+    #[inline]
+    fn is_str(_: Option<&'self Path>) -> bool { true }
+}
+
 impl GenericPathUnsafe for Path {
     /// See `GenericPathUnsafe::from_vec_unchecked`.
     ///
@@ -235,7 +273,7 @@ impl GenericPathUnsafe for Path {
         fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool {
             // assume prefix is Some(DiskPrefix)
             let rest = path.slice_from(prefix_len(prefix));
-            !rest.is_empty() && rest[0].is_ascii() && is_sep2(rest[0] as char)
+            !rest.is_empty() && rest[0].is_ascii() && is_sep(rest[0] as char)
         }
         fn shares_volume(me: &Path, path: &str) -> bool {
             // path is assumed to have a prefix of Some(DiskPrefix)
@@ -246,8 +284,8 @@ impl GenericPathUnsafe for Path {
             }
         }
         fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
-            u.is_ascii() && if prefix_is_verbatim(prefix) { is_sep(u as char) }
-                            else { is_sep2(u as char) }
+            if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
+            else { is_sep(u as char) }
         }
 
         fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) {
@@ -262,7 +300,7 @@ impl GenericPathUnsafe for Path {
         fn append_path(me: &mut Path, path: &str) {
             // appends a path that has no prefix
             // if me is verbatim, we need to pre-normalize the new path
-            let path_ = if me.is_verbatim() { Path::normalize__(path, None) }
+            let path_ = if is_verbatim(me) { Path::normalize__(path, None) }
                         else { None };
             let pathlen = path_.map_default(path.len(), |p| p.len());
             let mut s = str::with_capacity(me.repr.len() + 1 + pathlen);
@@ -291,7 +329,7 @@ impl GenericPathUnsafe for Path {
                 }
                 None if !path.is_empty() && is_sep_(self.prefix, path[0]) => {
                     // volume-relative path
-                    if self.prefix().is_some() {
+                    if self.prefix.is_some() {
                         // truncate self down to the prefix, then append
                         let n = self.prefix_len();
                         self.repr.truncate(n);
@@ -419,11 +457,6 @@ impl GenericPath for Path {
     }
 
     #[inline]
-    fn push_path(&mut self, path: &Path) {
-        self.push(path.as_str().unwrap())
-    }
-
-    #[inline]
     fn pop(&mut self) -> Option<~[u8]> {
         self.pop_str().map_move(|s| s.into_bytes())
     }
@@ -463,7 +496,7 @@ impl GenericPath for Path {
                 }
                 _ => self.repr.slice_to(self.prefix_len())
             }))
-        } else if self.is_vol_relative() {
+        } else if is_vol_relative(self) {
             Some(Path::new(self.repr.slice_to(1)))
         } else {
             None
@@ -493,14 +526,14 @@ impl GenericPath for Path {
 
     #[inline]
     fn is_relative(&self) -> bool {
-        self.prefix.is_none() && !self.is_vol_relative()
+        self.prefix.is_none() && !is_vol_relative(self)
     }
 
     fn is_ancestor_of(&self, other: &Path) -> bool {
         if !self.equiv_prefix(other) {
             false
         } else if self.is_absolute() != other.is_absolute() ||
-                  self.is_vol_relative() != other.is_vol_relative() {
+                  is_vol_relative(self) != is_vol_relative(other) {
             false
         } else {
             let mut ita = self.str_component_iter().map(|x|x.unwrap());
@@ -544,8 +577,8 @@ impl GenericPath for Path {
             } else {
                 None
             }
-        } else if self.is_vol_relative() != base.is_vol_relative() {
-            if self.is_vol_relative() {
+        } else if is_vol_relative(self) != is_vol_relative(base) {
+            if is_vol_relative(self) {
                 Some(self.clone())
             } else {
                 None
@@ -555,8 +588,8 @@ impl GenericPath for Path {
             let mut itb = base.str_component_iter().map(|x|x.unwrap());
             let mut comps = ~[];
 
-            let a_verb = self.is_verbatim();
-            let b_verb = base.is_verbatim();
+            let a_verb = is_verbatim(self);
+            let b_verb = is_verbatim(base);
             loop {
                 match (ita.next(), itb.next()) {
                     (None, None) => break,
@@ -598,20 +631,6 @@ impl GenericPath for Path {
         }
     }
 
-    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
-    }
-
     fn ends_with_path(&self, child: &Path) -> bool {
         if !child.is_relative() { return false; }
         let mut selfit = self.str_component_iter().invert();
@@ -694,34 +713,6 @@ impl Path {
         self.rev_str_component_iter().map(convert)
     }
 
-    /// Returns whether the path is considered "volume-relative", which means a path
-    /// that looks like "\foo". Paths of this form are relative to the current volume,
-    /// but absolute within that volume.
-    #[inline]
-    pub fn is_vol_relative(&self) -> bool {
-        self.prefix.is_none() && self.repr[0] == sep as u8
-    }
-
-    /// Returns whether the path is considered "cwd-relative", which means a path
-    /// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths
-    /// of this form are relative to the cwd on the given volume.
-    #[inline]
-    pub fn is_cwd_relative(&self) -> bool {
-        self.prefix == Some(DiskPrefix) && !self.is_absolute()
-    }
-
-    /// Returns the PathPrefix for this Path
-    #[inline]
-    pub fn prefix(&self) -> Option<PathPrefix> {
-        self.prefix
-    }
-
-    /// Returns whether the prefix is a verbatim prefix, i.e. \\?\
-    #[inline]
-    pub fn is_verbatim(&self) -> bool {
-        prefix_is_verbatim(self.prefix)
-    }
-
     fn equiv_prefix(&self, other: &Path) -> bool {
         match (self.prefix, other.prefix) {
             (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
@@ -866,8 +857,8 @@ impl Path {
         let s = if self.has_nonsemantic_trailing_slash() {
                     self.repr.slice_to(self.repr.len()-1)
                 } else { self.repr.as_slice() };
-        let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep2 }
-                          else { is_sep });
+        let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
+                          else { is_sep_verbatim });
         let prefixlen = self.prefix_len();
         self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
     }
@@ -893,7 +884,7 @@ impl Path {
     }
 
     fn has_nonsemantic_trailing_slash(&self) -> bool {
-        self.is_verbatim() && self.repr.len() > self.prefix_len()+1 &&
+        is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
             self.repr[self.repr.len()-1] == sep as u8
     }
 
@@ -905,23 +896,65 @@ impl Path {
     }
 }
 
+/// Returns whether the path is considered "volume-relative", which means a path
+/// that looks like "\foo". Paths of this form are relative to the current volume,
+/// but absolute within that volume.
+#[inline]
+pub fn is_vol_relative(path: &Path) -> bool {
+    path.prefix.is_none() && is_sep_byte(&path.repr[0])
+}
+
+/// Returns whether the path is considered "cwd-relative", which means a path
+/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths
+/// of this form are relative to the cwd on the given volume.
+#[inline]
+pub fn is_cwd_relative(path: &Path) -> bool {
+    path.prefix == Some(DiskPrefix) && !path.is_absolute()
+}
+
+/// Returns the PathPrefix for this Path
+#[inline]
+pub fn prefix(path: &Path) -> Option<PathPrefix> {
+    path.prefix
+}
+
+/// Returns whether the Path's prefix is a verbatim prefix, i.e. \\?\
+#[inline]
+pub fn is_verbatim(path: &Path) -> bool {
+    prefix_is_verbatim(path.prefix)
+}
+
 /// The standard path separator character
 pub static sep: char = '\\';
 /// The alternative path separator character
 pub static sep2: char = '/';
 
-/// Returns whether the given byte is a path separator.
-/// Only allows the primary separator '\'; use is_sep2 to allow '/'.
+/// Returns whether the given char is a path separator.
+/// Allows both the primary separator '\' and the alternative separator '/'.
 #[inline]
 pub fn is_sep(c: char) -> bool {
+    c == sep || c == sep2
+}
+
+/// Returns whether the given char is a path separator.
+/// Only allows the primary separator '\'; use is_sep to allow '/'.
+#[inline]
+pub fn is_sep_verbatim(c: char) -> bool {
     c == sep
 }
 
 /// Returns whether the given byte is a path separator.
 /// Allows both the primary separator '\' and the alternative separator '/'.
 #[inline]
-pub fn is_sep2(c: char) -> bool {
-    c == sep || c == sep2
+pub fn is_sep_byte(u: &u8) -> bool {
+    *u as char == sep || *u as char == sep2
+}
+
+/// Returns whether the given byte is a path separator.
+/// Only allows the primary separator '\'; use is_sep_byte to allow '/'.
+#[inline]
+pub fn is_sep_byte_verbatim(u: &u8) -> bool {
+    *u as char == sep
 }
 
 /// Prefix types for Path
@@ -953,7 +986,7 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
             if path.starts_with("UNC\\") {
                 // \\?\UNC\server\share
                 path = path.slice_from(4);
-                let (idx_a, idx_b) = match parse_two_comps(path, is_sep) {
+                let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
                     Some(x) => x,
                     None => (path.len(), 0)
                 };
@@ -977,7 +1010,7 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
             let idx = path.find('\\').unwrap_or(path.len());
             return Some(DeviceNSPrefix(idx));
         }
-        match parse_two_comps(path, is_sep2) {
+        match parse_two_comps(path, is_sep) {
             Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {
                 // \\server\share
                 return Some(UNCPrefix(idx_a, idx_b));
@@ -1006,14 +1039,14 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
 
 // None result means the string didn't need normalizing
 fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<~[&'a str]>) {
-    let f = if !prefix_is_verbatim(prefix) { is_sep2 } else { is_sep };
+    let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
     let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
     let s_ = s.slice_from(prefix_len(prefix));
     let s_ = if is_abs { s_.slice_from(1) } else { s_ };
 
     if is_abs && s_.is_empty() {
         return (is_abs, match prefix {
-            Some(DiskPrefix) | None => (if is_sep(s.char_at(prefix_len(prefix))) { None }
+            Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
                                         else { Some(~[]) }),
             Some(_) => Some(~[]), // need to trim the trailing separator
         });
@@ -1036,7 +1069,7 @@ fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<
         } else { comps.push(comp) }
     }
     if !changed && !prefix_is_verbatim(prefix) {
-        changed = s.find(is_sep2).is_some();
+        changed = s.find(is_sep).is_some();
     }
     if changed {
         if comps.is_empty() && !is_abs && prefix.is_none() {
@@ -1078,8 +1111,8 @@ fn prefix_len(p: Option<PathPrefix>) -> uint {
 }
 
 fn prefix_is_sep(p: Option<PathPrefix>, c: u8) -> bool {
-    c.is_ascii() && if !prefix_is_verbatim(p) { is_sep2(c as char) }
-                    else { is_sep(c as char) }
+    c.is_ascii() && if !prefix_is_verbatim(p) { is_sep(c as char) }
+                    else { is_sep_verbatim(c as char) }
 }
 
 // Stat support
@@ -1636,9 +1669,9 @@ mod tests {
 
         // we do want to check one odd case though to ensure the prefix is re-parsed
         let mut p = Path::new("\\\\?\\C:");
-        assert_eq!(p.prefix(), Some(VerbatimPrefix(2)));
+        assert_eq!(prefix(&p), Some(VerbatimPrefix(2)));
         p.push("foo");
-        assert_eq!(p.prefix(), Some(VerbatimDiskPrefix));
+        assert_eq!(prefix(&p), Some(VerbatimDiskPrefix));
         assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
 
         // and another with verbatim non-normalized paths
@@ -1654,7 +1687,7 @@ mod tests {
                 {
                     let mut p = Path::new($path);
                     let push = Path::new($push);
-                    p.push_path(&push);
+                    p.push(&push);
                     assert_eq!(p.as_str(), Some($exp));
                 }
             )
@@ -1837,7 +1870,7 @@ mod tests {
                 {
                     let path = Path::new($path);
                     let join = Path::new($join);
-                    let res = path.join_path(&join);
+                    let res = path.join(&join);
                     assert_eq!(res.as_str(), Some($exp));
                 }
             )
@@ -1849,7 +1882,7 @@ mod tests {
         t!(s: "a\\b", "\\c\\d", "\\c\\d");
         t!(s: ".", "a\\b", "a\\b");
         t!(s: "\\", "a\\b", "\\a\\b");
-        // join_path is implemented using push_path, so there's no need for
+        // join is implemented using push, so there's no need for
         // the full set of prefix tests
     }
 
@@ -2217,11 +2250,11 @@ mod tests {
                     let b = path.is_absolute();
                     assert!(b == abs, "Path '{}'.is_absolute(): expected {:?}, found {:?}",
                             path.as_str().unwrap(), abs, b);
-                    let b = path.is_vol_relative();
-                    assert!(b == vol, "Path '{}'.is_vol_relative(): expected {:?}, found {:?}",
+                    let b = is_vol_relative(&path);
+                    assert!(b == vol, "is_vol_relative('{}'): expected {:?}, found {:?}",
                             path.as_str().unwrap(), vol, b);
-                    let b = path.is_cwd_relative();
-                    assert!(b == cwd, "Path '{}'.is_cwd_relative(): expected {:?}, found {:?}",
+                    let b = is_cwd_relative(&path);
+                    assert!(b == cwd, "is_cwd_relative('{}'): expected {:?}, found {:?}",
                             path.as_str().unwrap(), cwd, b);
                     let b = path.is_relative();
                     assert!(b == rel, "Path '{}'.is_relativf(): expected {:?}, found {:?}",
@@ -2614,54 +2647,4 @@ mod tests {
         t!(s: ".", [b!(".")]);
         // since this is really a wrapper around str_component_iter, those tests suffice
     }
-
-    #[test]
-    fn test_each_parent() {
-        assert!(Path::new("/foo/bar").each_parent(|_| true));
-        assert!(!Path::new("/foo/bar").each_parent(|_| false));
-
-        macro_rules! t(
-            (s: $path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($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"]);
-    }
 }