]> git.lizzy.rs Git - rust.git/commitdiff
rollup merge of #21835: alexcrichton/iov2
authorAlex Crichton <alex@alexcrichton.com>
Tue, 3 Feb 2015 23:35:54 +0000 (15:35 -0800)
committerAlex Crichton <alex@alexcrichton.com>
Tue, 3 Feb 2015 23:35:54 +0000 (15:35 -0800)
This commit is an implementation of [RFC 576][rfc] which adds back the `std::io`
module to the standard library. No functionality in `std::old_io` has been
deprecated just yet, and the new `std::io` module is behind the same `io`
feature gate.

[rfc]: https://github.com/rust-lang/rfcs/pull/576

A good bit of functionality was copied over from `std::old_io`, but many tweaks
were required for the new method signatures. Behavior such as precisely when
buffered objects call to the underlying object may have been tweaked slightly in
the transition. All implementations were audited to use composition wherever
possible. For example the custom `pos` and `cap` cursors in `BufReader` were
removed in favor of just using `Cursor<Vec<u8>>`.

A few liberties were taken during this implementation which were not explicitly
spelled out in the RFC:

* The old `LineBufferedWriter` is now named `LineWriter`
* The internal representation of `Error` now favors OS error codes (a
  0-allocation path) and contains a `Box` for extra semantic data.
* The io prelude currently reexports `Seek` as `NewSeek` to prevent conflicts
  with the real prelude reexport of `old_io::Seek`
* The `chars` method was moved from `BufReadExt` to `ReadExt`.
* The `chars` iterator returns a custom error with a variant that explains that
  the data was not valid UTF-8.

79 files changed:
src/compiletest/header.rs
src/compiletest/runtest.rs
src/libarena/lib.rs
src/libcore/error.rs
src/libflate/lib.rs
src/libgetopts/lib.rs
src/libgraphviz/lib.rs
src/libgraphviz/maybe_owned_vec.rs
src/liblibc/lib.rs
src/liblog/macros.rs
src/librand/chacha.rs
src/librand/distributions/exponential.rs
src/librand/distributions/gamma.rs
src/librand/distributions/mod.rs
src/librand/distributions/normal.rs
src/librand/distributions/range.rs
src/librand/isaac.rs
src/librand/lib.rs
src/librand/rand_impls.rs
src/librand/reseeding.rs
src/librbml/lib.rs
src/librustc_back/abi.rs
src/librustc_back/sha2.rs
src/librustc_back/svh.rs
src/librustc_back/target/mod.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_resolve/lib.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/expr.rs
src/librustc_typeck/check/method/confirm.rs
src/librustc_typeck/check/method/suggest.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/check/regionck.rs
src/librustdoc/clean/mod.rs
src/libserialize/collection_impls.rs
src/libserialize/hex.rs
src/libserialize/json.rs
src/libserialize/serialize.rs
src/libstd/collections/hash/map.rs
src/libstd/collections/hash/state.rs
src/libstd/env.rs
src/libstd/ffi/mod.rs
src/libstd/ffi/os_str.rs
src/libstd/lib.rs
src/libstd/old_io/fs.rs
src/libstd/old_io/net/pipe.rs
src/libstd/old_io/process.rs
src/libstd/old_io/tempfile.rs
src/libstd/old_path/mod.rs [new file with mode: 0644]
src/libstd/old_path/posix.rs [new file with mode: 0644]
src/libstd/old_path/windows.rs [new file with mode: 0644]
src/libstd/os.rs
src/libstd/path.rs [new file with mode: 0755]
src/libstd/path/mod.rs [deleted file]
src/libstd/path/posix.rs [deleted file]
src/libstd/path/windows.rs [deleted file]
src/libstd/prelude/v1.rs
src/libstd/rand/os.rs
src/libstd/sys/common/mod.rs
src/libstd/sys/unix/os_str.rs
src/libstd/sys/unix/process.rs
src/libstd/sys/windows/backtrace.rs
src/libstd/sys/windows/os_str.rs
src/libstd/sys/windows/process.rs
src/libstd/time/duration.rs
src/libstd/time/mod.rs
src/libsyntax/parse/token.rs
src/libtest/lib.rs
src/libunicode/u_str.rs
src/test/auxiliary/no_method_suggested_traits.rs
src/test/compile-fail/method-suggestion-no-duplication.rs
src/test/compile-fail/no-method-suggested-traits.rs
src/test/compile-fail/range-3.rs
src/test/compile-fail/range-4.rs
src/test/debuginfo/associated-types.rs
src/test/run-pass/issue-15149.rs
src/test/run-pass/issue-3424.rs
src/test/run-pass/process-spawn-with-unicode-params.rs

index 66059d2d13d263bca1f9895eca4b293b716890e8..005ec013b8e6dd5acc3c638b2478a3944305ee39 100644 (file)
@@ -300,8 +300,8 @@ fn parse_exec_env(line: &str) -> Option<(String, String)> {
                                       .collect();
 
         match strs.len() {
-          1u => (strs.pop().unwrap(), "".to_string()),
-          2u => {
+          1 => (strs.pop().unwrap(), "".to_string()),
+          2 => {
               let end = strs.pop().unwrap();
               (strs.pop().unwrap(), end)
           }
index 5bb0a4031ead5cac3844a717e8db5fd9e3793a0e..a8e644dba99d18a8552d1d359f272f5a96d54840 100644 (file)
@@ -230,9 +230,9 @@ fn run_pretty_test(config: &Config, props: &TestProps, testfile: &Path) {
             let s = File::open(&filepath).read_to_end().unwrap();
             String::from_utf8(s).unwrap()
         }
-        None => { srcs[srcs.len() - 2u].clone() }
+        None => { srcs[srcs.len() - 2].clone() }
     };
-    let mut actual = srcs[srcs.len() - 1u].clone();
+    let mut actual = srcs[srcs.len() - 1].clone();
 
     if props.pp_exact.is_some() {
         // Now we have to care about line endings
@@ -842,7 +842,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
             }).collect();
         // check if each line in props.check_lines appears in the
         // output (in order)
-        let mut i = 0u;
+        let mut i = 0;
         for line in debugger_run_result.stdout.lines() {
             let mut rest = line.trim();
             let mut first = true;
@@ -869,7 +869,7 @@ fn check_debugger_output(debugger_run_result: &ProcRes, check_lines: &[String])
                 first = false;
             }
             if !failed && rest.len() == 0 {
-                i += 1u;
+                i += 1;
             }
             if i == num_check_lines {
                 // all lines checked
@@ -892,13 +892,13 @@ fn check_error_patterns(props: &TestProps,
         fatal(format!("no error pattern specified in {:?}",
                       testfile.display()).as_slice());
     }
-    let mut next_err_idx = 0u;
+    let mut next_err_idx = 0;
     let mut next_err_pat = &props.error_patterns[next_err_idx];
     let mut done = false;
     for line in output_to_check.lines() {
         if line.contains(next_err_pat.as_slice()) {
             debug!("found error pattern {}", next_err_pat);
-            next_err_idx += 1u;
+            next_err_idx += 1;
             if next_err_idx == props.error_patterns.len() {
                 debug!("found all error patterns");
                 done = true;
@@ -910,7 +910,7 @@ fn check_error_patterns(props: &TestProps,
     if done { return; }
 
     let missing_patterns = &props.error_patterns[next_err_idx..];
-    if missing_patterns.len() == 1u {
+    if missing_patterns.len() == 1 {
         fatal_proc_rec(format!("error pattern '{}' not found!",
                               missing_patterns[0]).as_slice(),
                       proc_res);
@@ -1025,7 +1025,7 @@ fn continuation( line: &str) -> bool {
 }
 
 fn is_compiler_error_or_warning(line: &str) -> bool {
-    let mut i = 0u;
+    let mut i = 0;
     return
         scan_until_char(line, ':', &mut i) &&
         scan_char(line, ':', &mut i) &&
@@ -1084,7 +1084,7 @@ fn scan_integer(haystack: &str, idx: &mut uint) -> bool {
 
 fn scan_string(haystack: &str, needle: &str, idx: &mut uint) -> bool {
     let mut haystack_i = *idx;
-    let mut needle_i = 0u;
+    let mut needle_i = 0;
     while needle_i < needle.len() {
         if haystack_i >= haystack.len() {
             return false;
index 0ff6cf7b79a359be37a4964de1252707efe462e3..62d103ae06a88fb20773326e8b6076e4d7ee9052 100644 (file)
@@ -101,7 +101,7 @@ pub struct Arena {
 impl Arena {
     /// Allocates a new Arena with 32 bytes preallocated.
     pub fn new() -> Arena {
-        Arena::new_with_size(32u)
+        Arena::new_with_size(32)
     }
 
     /// Allocates a new Arena with `initial_size` bytes preallocated.
@@ -117,7 +117,7 @@ pub fn new_with_size(initial_size: uint) -> Arena {
 fn chunk(size: uint, is_copy: bool) -> Chunk {
     Chunk {
         data: Rc::new(RefCell::new(Vec::with_capacity(size))),
-        fill: Cell::new(0u),
+        fill: Cell::new(0),
         is_copy: Cell::new(is_copy),
     }
 }
@@ -193,7 +193,7 @@ fn alloc_copy_grow(&self, n_bytes: uint, align: uint) -> *const u8 {
         self.chunks.borrow_mut().push(self.copy_head.borrow().clone());
 
         *self.copy_head.borrow_mut() =
-            chunk((new_min_chunk_size + 1u).next_power_of_two(), true);
+            chunk((new_min_chunk_size + 1).next_power_of_two(), true);
 
         return self.alloc_copy_inner(n_bytes, align);
     }
@@ -234,7 +234,7 @@ fn alloc_noncopy_grow(&self, n_bytes: uint,
         self.chunks.borrow_mut().push(self.head.borrow().clone());
 
         *self.head.borrow_mut() =
-            chunk((new_min_chunk_size + 1u).next_power_of_two(), false);
+            chunk((new_min_chunk_size + 1).next_power_of_two(), false);
 
         return self.alloc_noncopy_inner(n_bytes, align);
     }
@@ -308,7 +308,7 @@ pub fn alloc<T, F>(&self, op: F) -> &mut T where F: FnOnce() -> T {
 #[test]
 fn test_arena_destructors() {
     let arena = Arena::new();
-    for i in 0u..10 {
+    for i in 0..10 {
         // Arena allocate something with drop glue to make sure it
         // doesn't leak.
         arena.alloc(|| Rc::new(i));
@@ -337,7 +337,7 @@ struct Outer<'a> { inner: &'a Inner }
 fn test_arena_destructors_fail() {
     let arena = Arena::new();
     // Put some stuff in the arena.
-    for i in 0u..10 {
+    for i in 0..10 {
         // Arena allocate something with drop glue to make sure it
         // doesn't leak.
         arena.alloc(|| { Rc::new(i) });
@@ -527,7 +527,7 @@ struct Point {
     #[test]
     pub fn test_copy() {
         let arena = TypedArena::new();
-        for _ in 0u..100000 {
+        for _ in 0..100000 {
             arena.alloc(Point {
                 x: 1,
                 y: 2,
@@ -582,7 +582,7 @@ struct Noncopy {
     #[test]
     pub fn test_noncopy() {
         let arena = TypedArena::new();
-        for _ in 0u..100000 {
+        for _ in 0..100000 {
             arena.alloc(Noncopy {
                 string: "hello world".to_string(),
                 array: vec!( 1, 2, 3, 4, 5 ),
index 71d5e88cccff70e9cd647e3bacf66ff9476eab09..161f6c78921630e68c952fdeb90de7fe4627620c 100644 (file)
@@ -51,7 +51,7 @@
 //! use std::error::FromError;
 //! use std::old_io::{File, IoError};
 //! use std::os::{MemoryMap, MapError};
-//! use std::path::Path;
+//! use std::old_path::Path;
 //!
 //! enum MyError {
 //!     Io(IoError),
index e7fb2ba56ab358c37651fb03e43a563bc958b41f..4921a4470895a4b930b1990e4c7dbf44a225a359 100644 (file)
@@ -138,14 +138,14 @@ mod tests {
     fn test_flate_round_trip() {
         let mut r = rand::thread_rng();
         let mut words = vec!();
-        for _ in 0u..20 {
-            let range = r.gen_range(1u, 10);
+        for _ in 0..20 {
+            let range = r.gen_range(1, 10);
             let v = r.gen_iter::<u8>().take(range).collect::<Vec<u8>>();
             words.push(v);
         }
-        for _ in 0u..20 {
+        for _ in 0..20 {
             let mut input = vec![];
-            for _ in 0u..2000 {
+            for _ in 0..2000 {
                 input.push_all(r.choose(words.as_slice()).unwrap().as_slice());
             }
             debug!("de/inflate of {} bytes of random word-sequences",
index b4eb8e9902ae22c4eaabb0b1e721edb2886b69e8..9cfd4933ac22980c9264f1f768ca7fd0ef6c61a2 100644 (file)
@@ -227,8 +227,8 @@ pub enum FailType {
 
 impl Name {
     fn from_str(nm: &str) -> Name {
-        if nm.len() == 1u {
-            Short(nm.char_at(0u))
+        if nm.len() == 1 {
+            Short(nm.char_at(0))
         } else {
             Long(nm.to_string())
         }
@@ -694,7 +694,7 @@ pub fn getopts(args: &[String], optgrps: &[OptGroup]) -> Result {
         }
         i += 1;
     }
-    for i in 0u..n_opts {
+    for i in 0..n_opts {
         let n = vals[i].len();
         let occ = opts[i].occur;
         if occ == Req && n == 0 {
index e9c7f837014b83b102ac7807163d50ffbbf3323d..b33ca3fd7ec01d35639341adc458458629b5351e 100644 (file)
@@ -715,7 +715,7 @@ fn edge_label(&'a self, e: & &'a Edge) -> LabelText<'a> {
 
     impl<'a> GraphWalk<'a, Node, &'a Edge> for LabelledGraph {
         fn nodes(&'a self) -> Nodes<'a,Node> {
-            (0u..self.node_labels.len()).collect()
+            (0..self.node_labels.len()).collect()
         }
         fn edges(&'a self) -> Edges<'a,&'a Edge> {
             self.edges.iter().collect()
index 71f117835935d63c8aa4fadab9005537f191b11e..1c931856fa17c5a9e9c9d82be30304d8e41fe715 100644 (file)
@@ -17,7 +17,7 @@
 use std::default::Default;
 use std::fmt;
 use std::iter::FromIterator;
-use std::path::BytesContainer;
+use std::old_path::BytesContainer;
 use std::slice;
 
 // Note 1: It is not clear whether the flexibility of providing both
index 75867eb38be652236a86bc3a103d28f5c2e34aef..c5ea10beb83c525303da145b09541e5870eecf44 100644 (file)
@@ -1935,7 +1935,7 @@ pub mod extra {
                     pub iSecurityScheme: c_int,
                     pub dwMessageSize: DWORD,
                     pub dwProviderReserved: DWORD,
-                    pub szProtocol: [u8; (WSAPROTOCOL_LEN as uint) + 1u],
+                    pub szProtocol: [u8; (WSAPROTOCOL_LEN as uint) + 1us],
                 }
 
                 pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
index 5c7085b7b6c5f8909a451fcaf892ba473d66b6a7..4a9a9bd40600b73d736244b022a68a46cab331fb 100644 (file)
@@ -24,7 +24,7 @@
 /// fn main() {
 ///     log!(log::WARN, "this is a warning {}", "message");
 ///     log!(log::DEBUG, "this is a debug message");
-///     log!(6, "this is a custom logging level: {level}", level=6u);
+///     log!(6, "this is a custom logging level: {level}", level=6);
 /// }
 /// ```
 ///
@@ -70,7 +70,7 @@ macro_rules! log {
 /// #[macro_use] extern crate log;
 ///
 /// fn main() {
-///     let error = 3u;
+///     let error = 3;
 ///     error!("the build has failed with error code: {}", error);
 /// }
 /// ```
@@ -95,7 +95,7 @@ macro_rules! error {
 /// #[macro_use] extern crate log;
 ///
 /// fn main() {
-///     let code = 3u;
+///     let code = 3;
 ///     warn!("you may like to know that a process exited with: {}", code);
 /// }
 /// ```
index aef6301dad7782db6903df2a11fe851a5fa366f8..9f44f9debf6e2e9fb362b88c4f6903cbbf72036c 100644 (file)
@@ -268,9 +268,9 @@ fn test_rng_true_values() {
         // Store the 17*i-th 32-bit word,
         // i.e., the i-th word of the i-th 16-word block
         let mut v : Vec<u32> = Vec::new();
-        for _ in 0u..16 {
+        for _ in 0..16 {
             v.push(ra.next_u32());
-            for _ in 0u..16 {
+            for _ in 0..16 {
                 ra.next_u32();
             }
         }
@@ -287,7 +287,7 @@ fn test_rng_clone() {
         let seed : &[_] = &[0u32; 8];
         let mut rng: ChaChaRng = SeedableRng::from_seed(seed);
         let mut clone = rng.clone();
-        for _ in 0u..16 {
+        for _ in 0..16 {
             assert_eq!(rng.next_u64(), clone.next_u64());
         }
     }
index d7f80c00c90b579c58b8ceeab17e13a1027a3a31..e4927902cb3bb66184ad59f4c360818ee39491af 100644 (file)
@@ -103,7 +103,7 @@ mod test {
     fn test_exp() {
         let mut exp = Exp::new(10.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             assert!(exp.sample(&mut rng) >= 0.0);
             assert!(exp.ind_sample(&mut rng) >= 0.0);
         }
index 19586cbbd691b6ae75edb458f0f840131036f9e8..38eba0cfc712f7221961113775972f80ad76cdc0 100644 (file)
@@ -332,7 +332,7 @@ mod test {
     fn test_chi_squared_one() {
         let mut chi = ChiSquared::new(1.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             chi.sample(&mut rng);
             chi.ind_sample(&mut rng);
         }
@@ -341,7 +341,7 @@ fn test_chi_squared_one() {
     fn test_chi_squared_small() {
         let mut chi = ChiSquared::new(0.5);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             chi.sample(&mut rng);
             chi.ind_sample(&mut rng);
         }
@@ -350,7 +350,7 @@ fn test_chi_squared_small() {
     fn test_chi_squared_large() {
         let mut chi = ChiSquared::new(30.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             chi.sample(&mut rng);
             chi.ind_sample(&mut rng);
         }
@@ -365,7 +365,7 @@ fn test_chi_squared_invalid_dof() {
     fn test_f() {
         let mut f = FisherF::new(2.0, 32.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             f.sample(&mut rng);
             f.ind_sample(&mut rng);
         }
@@ -375,7 +375,7 @@ fn test_f() {
     fn test_t() {
         let mut t = StudentT::new(11.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             t.sample(&mut rng);
             t.ind_sample(&mut rng);
         }
index 4958784f614503cd031ff6e658d73a14e6cc7ca2..180248aa1560a5e1d20bbf63b47a7b812672d922 100644 (file)
@@ -97,7 +97,7 @@ pub struct Weighted<T> {
 ///                      Weighted { weight: 1, item: 'c' });
 /// let wc = WeightedChoice::new(items.as_mut_slice());
 /// let mut rng = rand::thread_rng();
-/// for _ in 0u..16 {
+/// for _ in 0..16 {
 ///      // on average prints 'a' 4 times, 'b' 8 and 'c' twice.
 ///      println!("{}", wc.ind_sample(&mut rng));
 /// }
@@ -118,7 +118,7 @@ pub fn new(items: &'a mut [Weighted<T>]) -> WeightedChoice<'a, T> {
         // strictly speaking, this is subsumed by the total weight == 0 case
         assert!(!items.is_empty(), "WeightedChoice::new called with no items");
 
-        let mut running_total = 0u;
+        let mut running_total = 0;
 
         // we convert the list from individual weights to cumulative
         // weights so we can binary search. This *could* drop elements
index 8fda21e604db38c055948feaf2c0adcc0788eb92..83f202742d3f33da9dbdf016c32b1cbe541f93ce 100644 (file)
@@ -169,7 +169,7 @@ mod tests {
     fn test_normal() {
         let mut norm = Normal::new(10.0, 10.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             norm.sample(&mut rng);
             norm.ind_sample(&mut rng);
         }
@@ -185,7 +185,7 @@ fn test_normal_invalid_sd() {
     fn test_log_normal() {
         let mut lnorm = LogNormal::new(10.0, 10.0);
         let mut rng = ::test::rng();
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             lnorm.sample(&mut rng);
             lnorm.ind_sample(&mut rng);
         }
index ab0b45e7d326891cd3df73a2f2b7e88b8f669c08..6eb1d68a081aa9d48632a383bfe0315d7f994214 100644 (file)
 /// use std::rand::distributions::{IndependentSample, Range};
 ///
 /// fn main() {
-///     let between = Range::new(10u, 10000u);
+///     let between = Range::new(10, 10000);
 ///     let mut rng = std::rand::thread_rng();
 ///     let mut sum = 0;
-///     for _ in 0u..1000 {
+///     for _ in 0..1000 {
 ///         sum += between.ind_sample(&mut rng);
 ///     }
 ///     println!("{}", sum);
@@ -190,7 +190,7 @@ macro_rules! t {
                                             (Int::min_value(), Int::max_value())];
                    for &(low, high) in v {
                         let mut sampler: Range<$ty> = Range::new(low, high);
-                        for _ in 0u..1000 {
+                        for _ in 0..1000 {
                             let v = sampler.sample(&mut rng);
                             assert!(low <= v && v < high);
                             let v = sampler.ind_sample(&mut rng);
@@ -216,7 +216,7 @@ macro_rules! t {
                                             (-1e35, 1e35)];
                    for &(low, high) in v {
                         let mut sampler: Range<$ty> = Range::new(low, high);
-                        for _ in 0u..1000 {
+                        for _ in 0..1000 {
                             let v = sampler.sample(&mut rng);
                             assert!(low <= v && v < high);
                             let v = sampler.ind_sample(&mut rng);
index d0f4afdde728a2e76a96631759b439744bed1c6c..d399c244e83b8fe4ee8367dc2f56ac2f5b6bdcb4 100644 (file)
@@ -82,7 +82,7 @@ macro_rules! mix {
             }}
         }
 
-        for _ in 0u..4 {
+        for _ in 0..4 {
             mix!();
         }
 
@@ -166,7 +166,7 @@ macro_rules! rngstepn {
                 }}
             }
 
-            for i in range_step(0u, MIDPOINT, 4) {
+            for i in range_step(0, MIDPOINT, 4) {
                 rngstepp!(i + 0, 13);
                 rngstepn!(i + 1, 6);
                 rngstepp!(i + 2, 2);
@@ -323,7 +323,7 @@ macro_rules! mix {
             }}
         }
 
-        for _ in 0u..4 {
+        for _ in 0..4 {
             mix!();
         }
 
@@ -412,10 +412,10 @@ macro_rules! rngstepn {
                     }}
                 }
 
-                rngstepp!(0u, 21);
-                rngstepn!(1u, 5);
-                rngstepp!(2u, 12);
-                rngstepn!(3u, 33);
+                rngstepp!(0, 21);
+                rngstepn!(1, 5);
+                rngstepp!(2, 12);
+                rngstepn!(3, 33);
             }
         }
 
@@ -581,7 +581,7 @@ fn test_rng_32_true_values() {
         let seed: &[_] = &[12345, 67890, 54321, 9876];
         let mut rb: IsaacRng = SeedableRng::from_seed(seed);
         // skip forward to the 10000th number
-        for _ in 0u..10000 { rb.next_u32(); }
+        for _ in 0..10000 { rb.next_u32(); }
 
         let v = (0..10).map(|_| rb.next_u32()).collect::<Vec<_>>();
         assert_eq!(v,
@@ -603,7 +603,7 @@ fn test_rng_64_true_values() {
         let seed: &[_] = &[12345, 67890, 54321, 9876];
         let mut rb: Isaac64Rng = SeedableRng::from_seed(seed);
         // skip forward to the 10000th number
-        for _ in 0u..10000 { rb.next_u64(); }
+        for _ in 0..10000 { rb.next_u64(); }
 
         let v = (0..10).map(|_| rb.next_u64()).collect::<Vec<_>>();
         assert_eq!(v,
@@ -618,7 +618,7 @@ fn test_rng_clone() {
         let seed: &[_] = &[1, 23, 456, 7890, 12345];
         let mut rng: Isaac64Rng = SeedableRng::from_seed(seed);
         let mut clone = rng.clone();
-        for _ in 0u..16 {
+        for _ in 0..16 {
             assert_eq!(rng.next_u64(), clone.next_u64());
         }
     }
index 5290e68033306c0da9423e99fb49dd4452d216b9..afb5d0c6eaab185227c5ded016dd4593c2c8b820 100644 (file)
@@ -222,7 +222,7 @@ fn gen_iter<'a, T: Rand>(&'a mut self) -> Generator<'a, T, Self> {
     /// use std::rand::{thread_rng, Rng};
     ///
     /// let mut rng = thread_rng();
-    /// let n: uint = rng.gen_range(0u, 10);
+    /// let n: uint = rng.gen_range(0, 10);
     /// println!("{}", n);
     /// let m: f64 = rng.gen_range(-40.0f64, 1.3e5f64);
     /// println!("{}", m);
@@ -278,7 +278,7 @@ fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
         if values.is_empty() {
             None
         } else {
-            Some(&values[self.gen_range(0u, values.len())])
+            Some(&values[self.gen_range(0, values.len())])
         }
     }
 
@@ -298,11 +298,11 @@ fn choose<'a, T>(&mut self, values: &'a [T]) -> Option<&'a T> {
     /// ```
     fn shuffle<T>(&mut self, values: &mut [T]) {
         let mut i = values.len();
-        while i >= 2u {
+        while i >= 2 {
             // invariant: elements with index >= i have been locked in place.
-            i -= 1u;
+            i -= 1;
             // lock element i in place.
-            values.swap(i, self.gen_range(0u, i + 1u));
+            values.swap(i, self.gen_range(0, i + 1));
         }
     }
 }
index 3d2368a4a912e371bd789a34e786154fcd682d44..d5c5d5004657e7facfdee32003e8ef9440d5a073 100644 (file)
@@ -241,7 +241,7 @@ fn rand_open() {
         // this is unlikely to catch an incorrect implementation that
         // generates exactly 0 or 1, but it keeps it sane.
         let mut rng = thread_rng();
-        for _ in 0u..1_000 {
+        for _ in 0..1_000 {
             // strict inequalities
             let Open01(f) = rng.gen::<Open01<f64>>();
             assert!(0.0 < f && f < 1.0);
@@ -254,7 +254,7 @@ fn rand_open() {
     #[test]
     fn rand_closed() {
         let mut rng = thread_rng();
-        for _ in 0u..1_000 {
+        for _ in 0..1_000 {
             // strict inequalities
             let Closed01(f) = rng.gen::<Closed01<f64>>();
             assert!(0.0 <= f && f <= 1.0);
index 75ac1b2cf44cc6bd758169e4c4773de08a1b671c..26c7afc21eb9571dc6bf2485dedbbc1b13d66029 100644 (file)
@@ -187,7 +187,7 @@ fn test_reseeding() {
         let mut rs = ReseedingRng::new(Counter {i:0}, 400, ReseedWithDefault);
 
         let mut i = 0;
-        for _ in 0u..1000 {
+        for _ in 0..1000 {
             assert_eq!(rs.next_u32(), i % 100);
             i += 1;
         }
index acc21cbf0600f9dcd957bd7619bb6122de4e0441..cf5397de149b7c4029a095160ab89b2e9cd89d93 100644 (file)
@@ -56,7 +56,7 @@ pub struct Doc<'a> {
 
 impl<'doc> Doc<'doc> {
     pub fn new(data: &'doc [u8]) -> Doc<'doc> {
-        Doc { data: data, start: 0u, end: data.len() }
+        Doc { data: data, start: 0, end: data.len() }
     }
 
     pub fn get<'a>(&'a self, tag: uint) -> Doc<'a> {
@@ -170,25 +170,25 @@ pub struct Res {
     fn vuint_at_slow(data: &[u8], start: uint) -> DecodeResult<Res> {
         let a = data[start];
         if a & 0x80u8 != 0u8 {
-            return Ok(Res {val: (a & 0x7fu8) as uint, next: start + 1u});
+            return Ok(Res {val: (a & 0x7fu8) as uint, next: start + 1});
         }
         if a & 0x40u8 != 0u8 {
-            return Ok(Res {val: ((a & 0x3fu8) as uint) << 8u |
-                        (data[start + 1u] as uint),
-                    next: start + 2u});
+            return Ok(Res {val: ((a & 0x3fu8) as uint) << 8 |
+                        (data[start + 1] as uint),
+                    next: start + 2});
         }
         if a & 0x20u8 != 0u8 {
-            return Ok(Res {val: ((a & 0x1fu8) as uint) << 16u |
-                        (data[start + 1u] as uint) << 8u |
-                        (data[start + 2u] as uint),
-                    next: start + 3u});
+            return Ok(Res {val: ((a & 0x1fu8) as uint) << 16 |
+                        (data[start + 1] as uint) << 8 |
+                        (data[start + 2] as uint),
+                    next: start + 3});
         }
         if a & 0x10u8 != 0u8 {
-            return Ok(Res {val: ((a & 0x0fu8) as uint) << 24u |
-                        (data[start + 1u] as uint) << 16u |
-                        (data[start + 2u] as uint) << 8u |
-                        (data[start + 3u] as uint),
-                    next: start + 4u});
+            return Ok(Res {val: ((a & 0x0fu8) as uint) << 24 |
+                        (data[start + 1] as uint) << 16 |
+                        (data[start + 2] as uint) << 8 |
+                        (data[start + 3] as uint),
+                    next: start + 4});
         }
         Err(IntTooBig(a as uint))
     }
@@ -225,7 +225,7 @@ pub fn vuint_at(data: &[u8], start: uint) -> DecodeResult<Res> {
             let ptr = data.as_ptr().offset(start as int) as *const u32;
             let val = Int::from_be(*ptr);
 
-            let i = (val >> 28u) as uint;
+            let i = (val >> 28) as uint;
             let (shift, mask) = SHIFT_MASK_TABLE[i];
             Ok(Res {
                 val: ((val >> shift) & mask) as uint,
@@ -311,23 +311,23 @@ pub fn with_doc_data<T, F>(d: Doc, f: F) -> T where
 
 
     pub fn doc_as_u8(d: Doc) -> u8 {
-        assert_eq!(d.end, d.start + 1u);
+        assert_eq!(d.end, d.start + 1);
         d.data[d.start]
     }
 
     pub fn doc_as_u16(d: Doc) -> u16 {
-        assert_eq!(d.end, d.start + 2u);
-        u64_from_be_bytes(d.data, d.start, 2u) as u16
+        assert_eq!(d.end, d.start + 2);
+        u64_from_be_bytes(d.data, d.start, 2) as u16
     }
 
     pub fn doc_as_u32(d: Doc) -> u32 {
-        assert_eq!(d.end, d.start + 4u);
-        u64_from_be_bytes(d.data, d.start, 4u) as u32
+        assert_eq!(d.end, d.start + 4);
+        u64_from_be_bytes(d.data, d.start, 4) as u32
     }
 
     pub fn doc_as_u64(d: Doc) -> u64 {
-        assert_eq!(d.end, d.start + 8u);
-        u64_from_be_bytes(d.data, d.start, 8u)
+        assert_eq!(d.end, d.start + 8);
+        u64_from_be_bytes(d.data, d.start, 8)
     }
 
     pub fn doc_as_i8(d: Doc) -> i8 { doc_as_u8(d) as i8 }
@@ -712,11 +712,11 @@ pub struct Encoder<'a, W:'a> {
 
     fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult {
         match size {
-            1u => w.write_all(&[0x80u8 | (n as u8)]),
-            2u => w.write_all(&[0x40u8 | ((n >> 8_u) as u8), n as u8]),
-            3u => w.write_all(&[0x20u8 | ((n >> 16_u) as u8), (n >> 8_u) as u8,
+            1 => w.write_all(&[0x80u8 | (n as u8)]),
+            2 => w.write_all(&[0x40u8 | ((n >> 8) as u8), n as u8]),
+            3 => w.write_all(&[0x20u8 | ((n >> 16) as u8), (n >> 8_u) as u8,
                             n as u8]),
-            4u => w.write_all(&[0x10u8 | ((n >> 24_u) as u8), (n >> 16_u) as u8,
+            4 => w.write_all(&[0x10u8 | ((n >> 24) as u8), (n >> 16_u) as u8,
                             (n >> 8_u) as u8, n as u8]),
             _ => Err(old_io::IoError {
                 kind: old_io::OtherIoError,
@@ -727,10 +727,10 @@ fn write_sized_vuint<W: Writer>(w: &mut W, n: uint, size: uint) -> EncodeResult
     }
 
     fn write_vuint<W: Writer>(w: &mut W, n: uint) -> EncodeResult {
-        if n < 0x7f_u { return write_sized_vuint(w, n, 1u); }
-        if n < 0x4000_u { return write_sized_vuint(w, n, 2u); }
-        if n < 0x200000_u { return write_sized_vuint(w, n, 3u); }
-        if n < 0x10000000_u { return write_sized_vuint(w, n, 4u); }
+        if n < 0x7f { return write_sized_vuint(w, n, 1); }
+        if n < 0x4000 { return write_sized_vuint(w, n, 2); }
+        if n < 0x200000 { return write_sized_vuint(w, n, 3); }
+        if n < 0x10000000 { return write_sized_vuint(w, n, 4); }
         Err(old_io::IoError {
             kind: old_io::OtherIoError,
             desc: "int too big",
@@ -772,7 +772,7 @@ pub fn end_tag(&mut self) -> EncodeResult {
             let cur_pos = try!(self.writer.tell());
             try!(self.writer.seek(last_size_pos as i64, old_io::SeekSet));
             let size = cur_pos as uint - last_size_pos - 4;
-            try!(write_sized_vuint(self.writer, size, 4u));
+            try!(write_sized_vuint(self.writer, size, 4));
             let r = try!(self.writer.seek(cur_pos as i64, old_io::SeekSet));
 
             debug!("End tag (size = {:?})", size);
@@ -794,19 +794,19 @@ pub fn wr_tagged_bytes(&mut self, tag_id: uint, b: &[u8]) -> EncodeResult {
         }
 
         pub fn wr_tagged_u64(&mut self, tag_id: uint, v: u64) -> EncodeResult {
-            u64_to_be_bytes(v, 8u, |v| {
+            u64_to_be_bytes(v, 8, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
 
         pub fn wr_tagged_u32(&mut self, tag_id: uint, v: u32)  -> EncodeResult{
-            u64_to_be_bytes(v as u64, 4u, |v| {
+            u64_to_be_bytes(v as u64, 4, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
 
         pub fn wr_tagged_u16(&mut self, tag_id: uint, v: u16) -> EncodeResult {
-            u64_to_be_bytes(v as u64, 2u, |v| {
+            u64_to_be_bytes(v as u64, 2, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
@@ -816,19 +816,19 @@ pub fn wr_tagged_u8(&mut self, tag_id: uint, v: u8) -> EncodeResult {
         }
 
         pub fn wr_tagged_i64(&mut self, tag_id: uint, v: i64) -> EncodeResult {
-            u64_to_be_bytes(v as u64, 8u, |v| {
+            u64_to_be_bytes(v as u64, 8, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
 
         pub fn wr_tagged_i32(&mut self, tag_id: uint, v: i32) -> EncodeResult {
-            u64_to_be_bytes(v as u64, 4u, |v| {
+            u64_to_be_bytes(v as u64, 4, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
 
         pub fn wr_tagged_i16(&mut self, tag_id: uint, v: i16) -> EncodeResult {
-            u64_to_be_bytes(v as u64, 2u, |v| {
+            u64_to_be_bytes(v as u64, 2, |v| {
                 self.wr_tagged_bytes(tag_id, v)
             })
         }
@@ -1190,7 +1190,7 @@ pub fn vuint_at_A_aligned(b: &mut Bencher) {
               _ => i as u8,
             }
         }).collect::<Vec<_>>();
-        let mut sum = 0u;
+        let mut sum = 0;
         b.iter(|| {
             let mut i = 0;
             while i < data.len() {
@@ -1208,7 +1208,7 @@ pub fn vuint_at_A_unaligned(b: &mut Bencher) {
               _ => i as u8
             }
         }).collect::<Vec<_>>();
-        let mut sum = 0u;
+        let mut sum = 0;
         b.iter(|| {
             let mut i = 1;
             while i < data.len() {
@@ -1227,7 +1227,7 @@ pub fn vuint_at_D_aligned(b: &mut Bencher) {
               _ => 0u8
             }
         }).collect::<Vec<_>>();
-        let mut sum = 0u;
+        let mut sum = 0;
         b.iter(|| {
             let mut i = 0;
             while i < data.len() {
@@ -1246,7 +1246,7 @@ pub fn vuint_at_D_unaligned(b: &mut Bencher) {
               _ => 0u8
             }
         }).collect::<Vec<_>>();
-        let mut sum = 0u;
+        let mut sum = 0;
         b.iter(|| {
             let mut i = 1;
             while i < data.len() {
index 2f6efbc85a2647f1e6f588d4171a564f394a1696..4b9064aaa05f9ecc8e6970457ed6062a00361b96 100644 (file)
@@ -8,8 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-pub const BOX_FIELD_DROP_GLUE: uint = 1u;
-pub const BOX_FIELD_BODY: uint = 4u;
+pub const BOX_FIELD_DROP_GLUE: uint = 1;
+pub const BOX_FIELD_BODY: uint = 4;
 
 /// The first half of a fat pointer.
 /// - For a closure, this is the code address.
@@ -21,4 +21,4 @@
 /// - For a closure, this is the address of the environment.
 /// - For an object or trait instance, this is the address of the vtable.
 /// - For a slice, this is the length.
-pub const FAT_PTR_EXTRA: uint = 1u;
+pub const FAT_PTR_EXTRA: uint = 1;
index c15b4114aa7b896cc19ffceacb2e37b462f59d37..693c75cbbcc5d2d35a74e69bbae2c49f59295cdf 100644 (file)
@@ -40,7 +40,7 @@ fn read_u32_be(input: &[u8]) -> u32 {
 /// Read a vector of bytes into a vector of u32s. The values are read in big-endian format.
 fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
     assert!(dst.len() * 4 == input.len());
-    let mut pos = 0u;
+    let mut pos = 0;
     for chunk in input.chunks(4) {
         dst[pos] = read_u32_be(chunk);
         pos += 1;
@@ -366,7 +366,7 @@ macro_rules! sha2_round {
 
         // Putting the message schedule inside the same loop as the round calculations allows for
         // the compiler to generate better code.
-        for t in range_step(0u, 48, 8) {
+        for t in range_step(0, 48, 8) {
             schedule_round!(t + 16);
             schedule_round!(t + 17);
             schedule_round!(t + 18);
@@ -386,7 +386,7 @@ macro_rules! sha2_round {
             sha2_round!(b, c, d, e, f, g, h, a, K32, t + 7);
         }
 
-        for t in range_step(48u, 64, 8) {
+        for t in range_step(48, 64, 8) {
             sha2_round!(a, b, c, d, e, f, g, h, K32, t);
             sha2_round!(h, a, b, c, d, e, f, g, K32, t + 1);
             sha2_round!(g, h, a, b, c, d, e, f, K32, t + 2);
@@ -569,8 +569,8 @@ fn test_hash<D: Digest>(sh: &mut D, tests: &[Test]) {
             sh.reset();
             let len = t.input.len();
             let mut left = len;
-            while left > 0u {
-                let take = (left + 1u) / 2u;
+            while left > 0 {
+                let take = (left + 1) / 2;
                 sh.input_str(&t.input[len - left..take + len - left]);
                 left = left - take;
             }
index a14f4775ec135be769035af2485329b12f4efabf..2823b2e9d74c3a30cc032938702bf50d2207fe92 100644 (file)
@@ -103,7 +103,7 @@ pub fn calculate(metadata: &Vec<String>, krate: &ast::Crate) -> Svh {
 
         let hash = state.finish();
         return Svh {
-            hash: range_step(0u, 64u, 4u).map(|i| hex(hash >> i)).collect()
+            hash: range_step(0, 64, 4).map(|i| hex(hash >> i)).collect()
         };
 
         fn hex(b: u64) -> char {
index 4b3833b687c5b53e176fe511c949a67382357409..bffee9d49334da43c3bedcb1d7743a7e66523f1b 100644 (file)
@@ -306,7 +306,7 @@ pub fn search(target: &str) -> Result<Target, String> {
         use std::env;
         use std::ffi::OsString;
         use std::old_io::File;
-        use std::path::Path;
+        use std::old_path::Path;
         use serialize::json;
 
         fn load_file(path: &Path) -> Result<Target, String> {
index d71e85e6a55c60a918c210e4cbe483d1bbe7c743..4fe037d852f49c715adf497772a746db53f146dd 100644 (file)
@@ -126,7 +126,7 @@ fn run_compiler(args: &[String]) {
     let odir = matches.opt_str("out-dir").map(|o| Path::new(o));
     let ofile = matches.opt_str("o").map(|o| Path::new(o));
     let (input, input_file_path) = match matches.free.len() {
-        0u => {
+        0 => {
             if sopts.describe_lints {
                 let mut ls = lint::LintStore::new();
                 ls.register_builtin(None);
@@ -139,7 +139,7 @@ fn run_compiler(args: &[String]) {
             }
             early_error("no input filename given");
         }
-        1u => {
+        1 => {
             let ifile = &matches.free[0][];
             if ifile == "-" {
                 let contents = old_io::stdin().read_to_end().unwrap();
index bd7ad51de37247ee77956eca4e91e248d38f90a6..ea7e59560cda9bb75dd22f7a2f607af10a03c6cb 100644 (file)
@@ -399,7 +399,7 @@ fn to_one_node_id(self, user_option: &str, sess: &Session, map: &ast_map::Map) -
         };
 
         let mut saw_node = ast::DUMMY_NODE_ID;
-        let mut seen = 0u;
+        let mut seen = 0;
         for node in self.all_matching_node_ids(map) {
             saw_node = node;
             seen += 1;
index a5fb57eadc41d0901d6d4f77043c8292b5ee9f39..d87039cbaefc18b4e3fabb0f8ee304ca57389f00 100644 (file)
@@ -997,7 +997,7 @@ fn new(session: &'a Session,
     /// Resolves all imports for the crate. This method performs the fixed-
     /// point iteration.
     fn resolve_imports(&mut self) {
-        let mut i = 0u;
+        let mut i = 0;
         let mut prev_unresolved_imports = 0;
         loop {
             debug!("(resolving imports) iteration {}, {} imports left",
index 66bb299273d9f86aa7aa4861f7468f3eddf783b0..0ced4066f625b7150238385cdc832b92b5ea159f 100644 (file)
@@ -1590,7 +1590,7 @@ fn compile_unit_metadata(cx: &CrateContext) -> DIDescriptor {
                     Some(ref p) if p.is_relative() => {
                         // prepend "./" if necessary
                         let dotdot = b"..";
-                        let prefix: &[u8] = &[dotdot[0], ::std::path::SEP_BYTE];
+                        let prefix: &[u8] = &[dotdot[0], ::std::old_path::SEP_BYTE];
                         let mut path_bytes = p.as_vec().to_vec();
 
                         if &path_bytes[..2] != prefix &&
index bed43a5c838823e36f062f1faeab10063ab48344..689d0c231b5b746b9d4bddf8c8e792c59e1d1d02 100644 (file)
@@ -194,7 +194,8 @@ fn apply_adjustments<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                 // a different region or mutability, but we don't care here. It might
                 // also be just in case we need to unsize. But if there are no nested
                 // adjustments then it should be a no-op).
-                Some(ty::AutoPtr(_, _, None)) if adj.autoderefs == 1 => {
+                Some(ty::AutoPtr(_, _, None)) |
+                Some(ty::AutoUnsafe(_, None)) if adj.autoderefs == 1 => {
                     match datum.ty.sty {
                         // Don't skip a conversion from Box<T> to &T, etc.
                         ty::ty_rptr(..) => {
index c326116cbd5449b3fbbf8709212af0a69039d67b..1cfb019395870fa63ec47d6b6125f52dfc270764 100644 (file)
@@ -347,9 +347,9 @@ fn instantiate_method_substs(&mut self,
         let num_supplied_types = supplied_method_types.len();
         let num_method_types = pick.method_ty.generics.types.len(subst::FnSpace);
         let method_types = {
-            if num_supplied_types == 0u {
+            if num_supplied_types == 0 {
                 self.fcx.infcx().next_ty_vars(num_method_types)
-            } else if num_method_types == 0u {
+            } else if num_method_types == 0 {
                 span_err!(self.tcx().sess, self.span, E0035,
                     "does not take type parameters");
                 self.fcx.infcx().next_ty_vars(num_method_types)
index bd5060c940e5025505e5ec8d4fe9c0700f211c88..c22d2a9bb416fe01a4e5537a29f22efb0dc00128 100644 (file)
@@ -36,6 +36,11 @@ pub fn report_error<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                               callee_expr: &ast::Expr,
                               error: MethodError)
 {
+    // avoid suggestions when we don't know what's going on.
+    if ty::type_is_error(rcvr_ty) {
+        return
+    }
+
     match error {
         MethodError::NoMatch(static_sources, out_of_scope_traits) => {
             let cx = fcx.tcx();
@@ -127,7 +132,7 @@ fn report_candidates(fcx: &FnCtxt,
 
                     span_note!(fcx.sess(), method_span,
                                "candidate #{} is defined in an impl{} for the type `{}`",
-                               idx + 1u,
+                               idx + 1,
                                insertion,
                                impl_ty.user_string(fcx.tcx()));
                 }
@@ -136,7 +141,7 @@ fn report_candidates(fcx: &FnCtxt,
                     let method_span = fcx.tcx().map.def_id_span(method.def_id, span);
                     span_note!(fcx.sess(), method_span,
                                "candidate #{} is defined in the trait `{}`",
-                               idx + 1u,
+                               idx + 1,
                                ty::item_path_str(fcx.tcx(), trait_did));
                 }
             }
@@ -149,7 +154,7 @@ fn report_candidates(fcx: &FnCtxt,
 
 fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
                                       span: Span,
-                                      _rcvr_ty: Ty<'tcx>,
+                                      rcvr_ty: Ty<'tcx>,
                                       method_name: ast::Name,
                                       valid_out_of_scope_traits: Vec<ast::DefId>)
 {
@@ -179,9 +184,22 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         return
     }
 
-    // there's no implemented traits, so lets suggest some traits to implement
+    let type_is_local = type_derefs_to_local(fcx, span, rcvr_ty);
+
+    // there's no implemented traits, so lets suggest some traits to
+    // implement, by finding ones that have the method name, and are
+    // legal to implement.
     let mut candidates = all_traits(fcx.ccx)
-        .filter(|info| trait_method(tcx, info.def_id, method_name).is_some())
+        .filter(|info| {
+            // we approximate the coherence rules to only suggest
+            // traits that are legal to implement by requiring that
+            // either the type or trait is local. Multidispatch means
+            // this isn't perfect (that is, there are cases when
+            // implementing a trait would be legal but is rejected
+            // here).
+            (type_is_local || ast_util::is_local(info.def_id))
+                && trait_method(tcx, info.def_id, method_name).is_some()
+        })
         .collect::<Vec<_>>();
 
     if candidates.len() > 0 {
@@ -189,6 +207,9 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
         candidates.sort_by(|a, b| a.cmp(b).reverse());
         candidates.dedup();
 
+        // FIXME #21673 this help message could be tuned to the case
+        // of a type parameter: suggest adding a trait bound rather
+        // than implementing.
         let msg = format!(
             "methods from traits can only be called if the trait is implemented and in scope; \
              the following {traits_define} a method `{name}`, \
@@ -208,6 +229,39 @@ fn suggest_traits_to_import<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
     }
 }
 
+/// Checks whether there is a local type somewhere in the chain of
+/// autoderefs of `rcvr_ty`.
+fn type_derefs_to_local<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
+                                  span: Span,
+                                  rcvr_ty: Ty<'tcx>) -> bool {
+    check::autoderef(fcx, span, rcvr_ty, None,
+                     check::UnresolvedTypeAction::Ignore, check::NoPreference,
+                     |&: ty, _| {
+        let is_local = match ty.sty {
+            ty::ty_enum(did, _) | ty::ty_struct(did, _) => ast_util::is_local(did),
+
+            ty::ty_trait(ref tr) => ast_util::is_local(tr.principal_def_id()),
+
+            ty::ty_param(_) => true,
+
+            // the user cannot implement traits for unboxed closures, so
+            // there's no point suggesting anything at all, local or not.
+            ty::ty_closure(..) => return Some(false),
+
+            // everything else (primitive types etc.) is effectively
+            // non-local (there are "edge" cases, e.g. (LocalType,), but
+            // the noise from these sort of types is usually just really
+            // annoying, rather than any sort of help).
+            _ => false
+        };
+        if is_local {
+            Some(true)
+        } else {
+            None
+        }
+    }).2.unwrap_or(false)
+}
+
 #[derive(Copy)]
 pub struct TraitInfo {
     pub def_id: ast::DefId,
index 70e5d44ca672541b6aa87478390d0a964a21b6f8..07b67d543a87e4f21243c9ca9b17a55bf0b6aeb0 100644 (file)
@@ -5193,7 +5193,7 @@ pub fn check_bounds_are_used<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>,
            tps.len(), ppaux::ty_to_string(ccx.tcx, ty));
 
     // make a vector of booleans initially false, set to true when used
-    if tps.len() == 0u { return; }
+    if tps.len() == 0 { return; }
     let mut tps_used: Vec<_> = repeat(false).take(tps.len()).collect();
 
     ty::walk_ty(ty, |t| {
@@ -5259,13 +5259,13 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
         let (n_tps, inputs, output) = match name.get() {
             "breakpoint" => (0, Vec::new(), ty::mk_nil(tcx)),
             "size_of" |
-            "pref_align_of" | "min_align_of" => (1u, Vec::new(), ccx.tcx.types.uint),
-            "init" => (1u, Vec::new(), param(ccx, 0)),
-            "uninit" => (1u, Vec::new(), param(ccx, 0)),
-            "forget" => (1u, vec!( param(ccx, 0) ), ty::mk_nil(tcx)),
+            "pref_align_of" | "min_align_of" => (1, Vec::new(), ccx.tcx.types.uint),
+            "init" => (1, Vec::new(), param(ccx, 0)),
+            "uninit" => (1, Vec::new(), param(ccx, 0)),
+            "forget" => (1, vec!( param(ccx, 0) ), ty::mk_nil(tcx)),
             "transmute" => (2, vec!( param(ccx, 0) ), param(ccx, 1)),
             "move_val_init" => {
-                (1u,
+                (1,
                  vec!(
                     ty::mk_mut_rptr(tcx,
                                     tcx.mk_region(ty::ReLateBound(ty::DebruijnIndex::new(1),
@@ -5275,8 +5275,8 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                   ),
                ty::mk_nil(tcx))
             }
-            "needs_drop" => (1u, Vec::new(), ccx.tcx.types.bool),
-            "owns_managed" => (1u, Vec::new(), ccx.tcx.types.bool),
+            "needs_drop" => (1, Vec::new(), ccx.tcx.types.bool),
+            "owns_managed" => (1, Vec::new(), ccx.tcx.types.bool),
 
             "get_tydesc" => {
               let tydesc_ty = match ty::get_tydesc_ty(ccx.tcx) {
@@ -5287,9 +5287,9 @@ fn param<'a, 'tcx>(ccx: &CrateCtxt<'a, 'tcx>, n: u32) -> Ty<'tcx> {
                   ty: tydesc_ty,
                   mutbl: ast::MutImmutable
               });
-              (1u, Vec::new(), td_ptr)
+              (1, Vec::new(), td_ptr)
             }
-            "type_id" => (1u, Vec::new(), ccx.tcx.types.u64),
+            "type_id" => (1, Vec::new(), ccx.tcx.types.u64),
             "offset" => {
               (1,
                vec!(
index 94414d842c9dfd0daee79c3cfd8dfcb2a46d681d..d5baff3a0c4a37a0ba1cad683c2d2200576d0ae4 100644 (file)
@@ -921,7 +921,7 @@ fn constrain_autoderefs<'a, 'tcx>(rcx: &mut Rcx<'a, 'tcx>,
            derefd_ty.repr(rcx.tcx()));
 
     let r_deref_expr = ty::ReScope(CodeExtent::from_node_id(deref_expr.id));
-    for i in 0u..derefs {
+    for i in 0..derefs {
         let method_call = MethodCall::autoderef(deref_expr.id, i);
         debug!("constrain_autoderefs: method_call={:?} (of {:?} total)", method_call, derefs);
 
index 07679480bfb39ef6f6f2702070d99df4c98cdf09..57eaf042aa02edc676697cb3173d92d881dd0209 100644 (file)
@@ -49,7 +49,7 @@
 use std::rc::Rc;
 use std::u32;
 use std::str::Str as StrTrait; // Conflicts with Str variant
-use std::path::Path as FsPath; // Conflicts with Path struct
+use std::old_path::Path as FsPath; // Conflicts with Path struct
 
 use core::DocContext;
 use doctree;
index d61d5b68462610ec82307d7625715505befa4b91..be7abfe6aca3b7a8038fdac57c4590877c1684b6 100644 (file)
@@ -36,7 +36,7 @@ impl<T:Decodable> Decodable for DList<T> {
     fn decode<D: Decoder>(d: &mut D) -> Result<DList<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut list = DList::new();
-            for i in 0u..len {
+            for i in 0..len {
                 list.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
             }
             Ok(list)
@@ -59,7 +59,7 @@ impl<T:Decodable> Decodable for RingBuf<T> {
     fn decode<D: Decoder>(d: &mut D) -> Result<RingBuf<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut deque: RingBuf<T> = RingBuf::new();
-            for i in 0u..len {
+            for i in 0..len {
                 deque.push_back(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
             }
             Ok(deque)
@@ -91,7 +91,7 @@ impl<
     fn decode<D: Decoder>(d: &mut D) -> Result<BTreeMap<K, V>, D::Error> {
         d.read_map(|d, len| {
             let mut map = BTreeMap::new();
-            for i in 0u..len {
+            for i in 0..len {
                 let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                 let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                 map.insert(key, val);
@@ -122,7 +122,7 @@ impl<
     fn decode<D: Decoder>(d: &mut D) -> Result<BTreeSet<T>, D::Error> {
         d.read_seq(|d, len| {
             let mut set = BTreeSet::new();
-            for i in 0u..len {
+            for i in 0..len {
                 set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
             }
             Ok(set)
@@ -186,7 +186,7 @@ fn decode<D: Decoder>(d: &mut D) -> Result<HashMap<K, V, S>, D::Error> {
         d.read_map(|d, len| {
             let state = Default::default();
             let mut map = HashMap::with_capacity_and_hash_state(len, state);
-            for i in 0u..len {
+            for i in 0..len {
                 let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                 let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                 map.insert(key, val);
@@ -222,7 +222,7 @@ fn decode<D: Decoder>(d: &mut D) -> Result<HashSet<T, S>, D::Error> {
         d.read_seq(|d, len| {
             let state = Default::default();
             let mut set = HashSet::with_capacity_and_hash_state(len, state);
-            for i in 0u..len {
+            for i in 0..len {
                 set.insert(try!(d.read_seq_elt(i, |d| Decodable::decode(d))));
             }
             Ok(set)
@@ -246,7 +246,7 @@ impl<V: Decodable> Decodable for VecMap<V> {
     fn decode<D: Decoder>(d: &mut D) -> Result<VecMap<V>, D::Error> {
         d.read_map(|d, len| {
             let mut map = VecMap::new();
-            for i in 0u..len {
+            for i in 0..len {
                 let key = try!(d.read_map_elt_key(i, |d| Decodable::decode(d)));
                 let val = try!(d.read_map_elt_val(i, |d| Decodable::decode(d)));
                 map.insert(key, val);
index a34ae1087dbbe3ccb5ec599cc014a8abf3aa3115..a3cc2d6b935d9fab31d9bea4d38968ea822132e1 100644 (file)
@@ -185,14 +185,14 @@ pub fn test_from_hex_ignores_whitespace() {
 
     #[test]
     pub fn test_to_hex_all_bytes() {
-        for i in 0u..256 {
+        for i in 0..256 {
             assert_eq!([i as u8].to_hex(), format!("{:02x}", i as uint));
         }
     }
 
     #[test]
     pub fn test_from_hex_all_bytes() {
-        for i in 0u..256 {
+        for i in 0..256 {
             let ii: &[u8] = &[i as u8];
             assert_eq!(format!("{:02x}", i as uint).from_hex()
                                                    .unwrap(),
index 3bc9e699035da3b2f70eef1f2f2bb23aa87a69b4..4f62cca3c68c285fe1c70ff190c8cfe5cba1c6a5 100644 (file)
@@ -457,8 +457,8 @@ fn spaces(wr: &mut fmt::Writer, mut n: uint) -> EncodeResult {
 fn fmt_number_or_null(v: f64) -> string::String {
     match v.classify() {
         Fp::Nan | Fp::Infinite => string::String::from_str("null"),
-        _ if v.fract() != 0f64 => f64::to_str_digits(v, 6u),
-        _ => f64::to_str_digits(v, 6u) + ".0",
+        _ if v.fract() != 0f64 => f64::to_str_digits(v, 6),
+        _ => f64::to_str_digits(v, 6) + ".0",
     }
 }
 
@@ -1474,10 +1474,10 @@ fn bump(&mut self) {
         self.ch = self.rdr.next();
 
         if self.ch_is('\n') {
-            self.line += 1u;
-            self.col = 1u;
+            self.line += 1;
+            self.col = 1;
         } else {
-            self.col += 1u;
+            self.col += 1;
         }
     }
 
@@ -1614,7 +1614,7 @@ fn parse_decimal(&mut self, mut res: f64) -> Result<f64, ParserError> {
     fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
         self.bump();
 
-        let mut exp = 0u;
+        let mut exp = 0;
         let mut neg_exp = false;
 
         if self.ch_is('+') {
@@ -1652,7 +1652,7 @@ fn parse_exponent(&mut self, mut res: f64) -> Result<f64, ParserError> {
     }
 
     fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
-        let mut i = 0u;
+        let mut i = 0;
         let mut n = 0u16;
         while i < 4 && !self.eof() {
             self.bump();
@@ -1667,7 +1667,7 @@ fn decode_hex_escape(&mut self) -> Result<u16, ParserError> {
                 _ => return self.error(InvalidEscape)
             };
 
-            i += 1u;
+            i += 1;
         }
 
         // Error out if we didn't parse 4 digits.
@@ -2638,7 +2638,7 @@ fn test_decode_option_none() {
     fn test_decode_option_some() {
         let s = "{ \"opt\": 10 }";
         let obj: OptionData = super::decode(s).unwrap();
-        assert_eq!(obj, OptionData { opt: Some(10u) });
+        assert_eq!(obj, OptionData { opt: Some(10) });
     }
 
     #[test]
@@ -3092,10 +3092,10 @@ fn test_decode_array() {
     #[test]
     fn test_decode_tuple() {
         let t: (uint, uint, uint) = super::decode("[1, 2, 3]").unwrap();
-        assert_eq!(t, (1u, 2, 3));
+        assert_eq!(t, (1, 2, 3));
 
         let t: (uint, string::String) = super::decode("[1, \"two\"]").unwrap();
-        assert_eq!(t, (1u, "two".to_string()));
+        assert_eq!(t, (1, "two".to_string()));
     }
 
     #[test]
@@ -3228,7 +3228,7 @@ fn test_decode_map() {
     #[test]
     fn test_multiline_errors() {
         assert_eq!(from_str("{\n  \"foo\":\n \"bar\""),
-            Err(SyntaxError(EOFWhileParsingObject, 3u, 8u)));
+            Err(SyntaxError(EOFWhileParsingObject, 3, 8)));
     }
 
     #[derive(RustcDecodable)]
@@ -3512,7 +3512,7 @@ fn indents(source: &str) -> uint {
         }
 
         // Test up to 4 spaces of indents (more?)
-        for i in 0..4u {
+        for i in 0..4 {
             let mut writer = Vec::new();
             write!(&mut writer, "{}",
                    super::as_pretty_json(&json).indent(i)).unwrap();
@@ -3924,22 +3924,22 @@ fn test_to_json() {
         assert_eq!(false.to_json(), Boolean(false));
         assert_eq!("abc".to_json(), String("abc".to_string()));
         assert_eq!("abc".to_string().to_json(), String("abc".to_string()));
-        assert_eq!((1u, 2u).to_json(), array2);
-        assert_eq!((1u, 2u, 3u).to_json(), array3);
-        assert_eq!([1u, 2].to_json(), array2);
-        assert_eq!((&[1u, 2, 3]).to_json(), array3);
-        assert_eq!((vec![1u, 2]).to_json(), array2);
-        assert_eq!(vec!(1u, 2, 3).to_json(), array3);
+        assert_eq!((1us, 2us).to_json(), array2);
+        assert_eq!((1us, 2us, 3us).to_json(), array3);
+        assert_eq!([1us, 2us].to_json(), array2);
+        assert_eq!((&[1us, 2us, 3us]).to_json(), array3);
+        assert_eq!((vec![1us, 2us]).to_json(), array2);
+        assert_eq!(vec!(1us, 2us, 3us).to_json(), array3);
         let mut tree_map = BTreeMap::new();
-        tree_map.insert("a".to_string(), 1u);
+        tree_map.insert("a".to_string(), 1us);
         tree_map.insert("b".to_string(), 2);
         assert_eq!(tree_map.to_json(), object);
         let mut hash_map = HashMap::new();
-        hash_map.insert("a".to_string(), 1u);
+        hash_map.insert("a".to_string(), 1us);
         hash_map.insert("b".to_string(), 2);
         assert_eq!(hash_map.to_json(), object);
         assert_eq!(Some(15).to_json(), I64(15));
-        assert_eq!(Some(15u).to_json(), U64(15));
+        assert_eq!(Some(15us).to_json(), U64(15));
         assert_eq!(None::<int>.to_json(), Null);
     }
 
index f963d0ce813ee790eb360dfa38aed139b634a093..517907bcf58e347c3e94b7f876e66026a7aef97d 100644 (file)
@@ -14,7 +14,7 @@
 Core encoding and decoding interfaces.
 */
 
-use std::path;
+use std::old_path;
 use std::rc::Rc;
 use std::cell::{Cell, RefCell};
 use std::sync::Arc;
@@ -498,7 +498,7 @@ macro_rules! peel {
 
 /// Evaluates to the number of identifiers passed to it, for example: `count_idents!(a, b, c) == 3
 macro_rules! count_idents {
-    () => { 0u };
+    () => { 0 };
     ($_i:ident, $($rest:ident,)*) => { 1 + count_idents!($($rest,)*) }
 }
 
@@ -538,29 +538,29 @@ fn encode<S: Encoder>(&self, s: &mut S) -> Result<(), S::Error> {
 
 tuple! { T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, }
 
-impl Encodable for path::posix::Path {
+impl Encodable for old_path::posix::Path {
     fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
         self.as_vec().encode(e)
     }
 }
 
-impl Decodable for path::posix::Path {
-    fn decode<D: Decoder>(d: &mut D) -> Result<path::posix::Path, D::Error> {
+impl Decodable for old_path::posix::Path {
+    fn decode<D: Decoder>(d: &mut D) -> Result<old_path::posix::Path, D::Error> {
         let bytes: Vec<u8> = try!(Decodable::decode(d));
-        Ok(path::posix::Path::new(bytes))
+        Ok(old_path::posix::Path::new(bytes))
     }
 }
 
-impl Encodable for path::windows::Path {
+impl Encodable for old_path::windows::Path {
     fn encode<S: Encoder>(&self, e: &mut S) -> Result<(), S::Error> {
         self.as_vec().encode(e)
     }
 }
 
-impl Decodable for path::windows::Path {
-    fn decode<D: Decoder>(d: &mut D) -> Result<path::windows::Path, D::Error> {
+impl Decodable for old_path::windows::Path {
+    fn decode<D: Decoder>(d: &mut D) -> Result<old_path::windows::Path, D::Error> {
         let bytes: Vec<u8> = try!(Decodable::decode(d));
-        Ok(path::windows::Path::new(bytes))
+        Ok(old_path::windows::Path::new(bytes))
     }
 }
 
index 7b3cc434f0ca3e2201951d7f86f887a1578921e8..205eeb75b5b790c0c2ca0b97eae817f195034b53 100644 (file)
@@ -46,6 +46,7 @@
 use super::state::HashState;
 
 const INITIAL_LOG2_CAP: uint = 5;
+#[unstable(feature = "std_misc")]
 pub const INITIAL_CAPACITY: uint = 1 << INITIAL_LOG2_CAP; // 2^5
 
 /// The default behavior of HashMap implements a load factor of 90.9%.
@@ -1622,6 +1623,8 @@ fn default() -> RandomState {
 /// typically declare an ability to explicitly hash into this particular type,
 /// but rather in a `H: hash::Writer` type parameter.
 #[allow(missing_copy_implementations)]
+#[unstable(feature = "std_misc",
+           reason = "hashing an hash maps may be altered")]
 pub struct Hasher { inner: SipHasher }
 
 impl hash::Writer for Hasher {
index ffbc958f179f5adfcccbdb9fd04d0060ab974455..79e01304fb8c0807a9bf5face1810a69f6a24861 100644 (file)
@@ -24,6 +24,7 @@
 /// algorithm can implement the `Default` trait and create hash maps with the
 /// `DefaultState` structure. This state is 0-sized and will simply delegate
 /// to `Default` when asked to create a hasher.
+#[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
 pub trait HashState {
     type Hasher: hash::Hasher;
 
@@ -35,6 +36,7 @@ pub trait HashState {
 /// default trait.
 ///
 /// This struct has is 0-sized and does not need construction.
+#[unstable(feature = "std_misc", reason = "hasher stuff is unclear")]
 pub struct DefaultState<H>;
 
 impl<H: Default + hash::Hasher> HashState for DefaultState<H> {
index 5070f8c547ab0663501b84ce25d29b291c84c561..559a68542efc890492144a2ec5289b739e059b68 100644 (file)
@@ -57,7 +57,7 @@ pub fn current_dir() -> IoResult<Path> {
 ///
 /// ```rust
 /// use std::env;
-/// use std::path::Path;
+/// use std::old_path::Path;
 ///
 /// let root = Path::new("/");
 /// assert!(env::set_current_dir(&root).is_ok());
index 76f925a23f17412e3cd4bac2a6a707ccadc9caa3..07a4f17796c4994f14638ac3258ee15a0da40b4e 100644 (file)
@@ -24,6 +24,7 @@
 mod c_str;
 mod os_str;
 
+// FIXME (#21670): these should be defined in the os_str module
 /// Freely convertible to an `&OsStr` slice.
 pub trait AsOsStr {
     /// Convert to an `&OsStr` slice.
index b8d770e6ad694e12734ac08d4c606b77ebdd0001..4d7292b6eb417469e4aea7a03002ca0063a10fe2 100644 (file)
@@ -41,7 +41,7 @@
 use ops;
 use cmp;
 use hash::{Hash, Hasher, Writer};
-use path::{Path, GenericPath};
+use old_path::{Path, GenericPath};
 
 use sys::os_str::{Buf, Slice};
 use sys_common::{AsInner, IntoInner, FromInner};
index 9efb6fa4247aa832e6586488e39a26dfdd1fce9e..a46cea7a44325ea60a451f64f2fe52b5079504bb 100644 (file)
 pub mod os;
 pub mod env;
 pub mod path;
+pub mod old_path;
 pub mod rand;
 pub mod time;
 
index abf215988bb4b859982967ee3dda5ceeb3294d65..88ca6667d55deba1e56b8446824b6a9f73c48ddc 100644 (file)
@@ -61,8 +61,8 @@
 use iter::{Iterator, Extend};
 use option::Option;
 use option::Option::{Some, None};
-use path::{Path, GenericPath};
-use path;
+use old_path::{Path, GenericPath};
+use old_path;
 use result::Result::{Err, Ok};
 use slice::SliceExt;
 use string::String;
@@ -782,7 +782,7 @@ pub trait PathExtensions {
     fn is_dir(&self) -> bool;
 }
 
-impl PathExtensions for path::Path {
+impl PathExtensions for old_path::Path {
     fn stat(&self) -> IoResult<FileStat> { stat(self) }
     fn lstat(&self) -> IoResult<FileStat> { lstat(self) }
     fn exists(&self) -> bool {
index 0da7670c5b49cf2a2eda037c8557a45824a27f0f..8c4a10a55d489d86865f8ca661754fefc97d56b5 100644 (file)
@@ -23,7 +23,7 @@
 use prelude::v1::*;
 
 use ffi::CString;
-use path::BytesContainer;
+use old_path::BytesContainer;
 use old_io::{Listener, Acceptor, IoResult, TimedOut, standard_error};
 use sys::pipe::UnixAcceptor as UnixAcceptorImp;
 use sys::pipe::UnixListener as UnixListenerImp;
index 61a07bc8208eda35ffc5b3a96b6e329943e621d9..27af957e18e18614c591e47fd2911a9672cdd8f2 100644 (file)
@@ -25,7 +25,7 @@
 use old_io;
 use libc;
 use os;
-use path::BytesContainer;
+use old_path::BytesContainer;
 use sync::mpsc::{channel, Receiver};
 use sys::fs::FileDesc;
 use sys::process::Process as ProcessImp;
index 83a42549424d698dabee5242ff2075df1c04ceb0..a227116dfae997b4c3818f888fba4abf3a30e8bb 100644 (file)
@@ -17,7 +17,7 @@
 use ops::Drop;
 use option::Option::{None, Some};
 use option::Option;
-use path::{Path, GenericPath};
+use old_path::{Path, GenericPath};
 use rand::{Rng, thread_rng};
 use result::Result::{Ok, Err};
 use str::StrExt;
diff --git a/src/libstd/old_path/mod.rs b/src/libstd/old_path/mod.rs
new file mode 100644 (file)
index 0000000..0d80258
--- /dev/null
@@ -0,0 +1,923 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Cross-platform path support
+//!
+//! This module implements support for two flavors of paths. `PosixPath` represents a path on any
+//! unix-like system, whereas `WindowsPath` represents a path on Windows. This module also exposes
+//! a typedef `Path` which is equal to the appropriate platform-specific path variant.
+//!
+//! Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which contains the set of
+//! methods that behave the same for both paths. They each also implement some methods that could
+//! not be expressed in `GenericPath`, yet behave identically for both path flavors, such as
+//! `.components()`.
+//!
+//! The three main design goals of this module are 1) to avoid unnecessary allocation, 2) to behave
+//! the same regardless of which flavor of path is being used, and 3) to support paths that cannot
+//! be represented in UTF-8 (as Linux has 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.
+//!
+//! 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 `.pop()` (and other
+//! setters). The resulting Path can either be passed to another API that expects a path, or can be
+//! turned into a `&[u8]` with `.as_vec()` or a `Option<&str>` with `.as_str()`. Similarly,
+//! attributes of the path can be queried with methods such as `.filename()`. There are also
+//! methods that return a new path instead of modifying the receiver, such as `.join()` or
+//! `.dir_path()`.
+//!
+//! Paths are always kept in normalized form. This means that creating the path
+//! `Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt to mutate the path
+//! will always leave it in normalized form.
+//!
+//! When rendering a path to some form of output, there is a method `.display()` which is
+//! compatible with the `format!()` parameter `{}`. This will render the path as a string,
+//! replacing all non-utf8 sequences with the Replacement Character (U+FFFD). As such it is not
+//! suitable for passing to any API that actually operates on the path; it is only intended for
+//! display.
+//!
+//! ## Example
+//!
+//! ```rust
+//! use std::old_io::fs::PathExtensions;
+//!
+//! let mut path = Path::new("/tmp/path");
+//! println!("path: {}", path.display());
+//! path.set_filename("foo");
+//! path.push("bar");
+//! println!("new path: {}", path.display());
+//! println!("path exists: {}", path.exists());
+//! ```
+
+#![unstable(feature = "path")]
+
+use core::marker::Sized;
+use ffi::CString;
+use clone::Clone;
+use fmt;
+use iter::IteratorExt;
+use option::Option;
+use option::Option::{None, Some};
+use str;
+use str::StrExt;
+use string::{String, CowString};
+use slice::SliceExt;
+use vec::Vec;
+
+/// Typedef for POSIX file paths.
+/// See `posix::Path` for more info.
+pub use self::posix::Path as PosixPath;
+
+/// Typedef for Windows file paths.
+/// See `windows::Path` for more info.
+pub use self::windows::Path as WindowsPath;
+
+/// Typedef for the platform-native path type
+#[cfg(unix)]
+pub use self::posix::Path as Path;
+/// Typedef for the platform-native path type
+#[cfg(windows)]
+pub use self::windows::Path as Path;
+
+/// Typedef for the platform-native component iterator
+#[cfg(unix)]
+pub use self::posix::Components as Components;
+/// Typedef for the platform-native component iterator
+#[cfg(windows)]
+pub use self::windows::Components as Components;
+
+/// Typedef for the platform-native str component iterator
+#[cfg(unix)]
+pub use self::posix::StrComponents as StrComponents;
+/// Typedef for the platform-native str component iterator
+#[cfg(windows)]
+pub use self::windows::StrComponents as StrComponents;
+
+/// Alias for the platform-native separator character.
+#[cfg(unix)]
+pub use self::posix::SEP as SEP;
+/// Alias for the platform-native separator character.
+#[cfg(windows)]
+pub use self::windows::SEP as SEP;
+
+/// Alias for the platform-native separator byte.
+#[cfg(unix)]
+pub use self::posix::SEP_BYTE as SEP_BYTE;
+/// Alias for the platform-native separator byte.
+#[cfg(windows)]
+pub use self::windows::SEP_BYTE as SEP_BYTE;
+
+/// Typedef for the platform-native separator char func
+#[cfg(unix)]
+pub use self::posix::is_sep as is_sep;
+/// Typedef for the platform-native separator char func
+#[cfg(windows)]
+pub use self::windows::is_sep as is_sep;
+/// Typedef for the platform-native separator byte func
+#[cfg(unix)]
+pub use self::posix::is_sep_byte as is_sep_byte;
+/// Typedef for the platform-native separator byte func
+#[cfg(windows)]
+pub use self::windows::is_sep_byte as is_sep_byte;
+
+pub mod posix;
+pub mod windows;
+
+/// A trait that represents the generic operations available on paths
+pub trait GenericPath: Clone + GenericPathUnsafe {
+    /// Creates a new Path from a byte vector or string.
+    /// The resulting Path will always be normalized.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let path = Path::new("foo/bar");
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the path contains a NUL.
+    ///
+    /// See individual Path impls for additional restrictions.
+    #[inline]
+    fn new<T: BytesContainer>(path: T) -> Self {
+        assert!(!contains_nul(&path));
+        unsafe { GenericPathUnsafe::new_unchecked(path) }
+    }
+
+    /// Creates a new Path from a byte vector or string, if possible.
+    /// The resulting Path will always be normalized.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let x: &[u8] = b"foo\0";
+    /// assert!(Path::new_opt(x).is_none());
+    /// # }
+    /// ```
+    #[inline]
+    fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
+        if contains_nul(&path) {
+            None
+        } else {
+            Some(unsafe { GenericPathUnsafe::new_unchecked(path) })
+        }
+    }
+
+    /// Returns the path as a string, if possible.
+    /// If the path is not representable in utf-8, this returns None.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("/abc/def");
+    /// assert_eq!(p.as_str(), Some("/abc/def"));
+    /// # }
+    /// ```
+    #[inline]
+    fn as_str<'a>(&'a self) -> Option<&'a str> {
+        str::from_utf8(self.as_vec()).ok()
+    }
+
+    /// Returns the path as a byte vector
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def");
+    /// assert_eq!(p.as_vec(), b"abc/def");
+    /// # }
+    /// ```
+    fn as_vec<'a>(&'a self) -> &'a [u8];
+
+    /// Converts the Path into an owned byte vector
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def");
+    /// assert_eq!(p.into_vec(), b"abc/def".to_vec());
+    /// // attempting to use p now results in "error: use of moved value"
+    /// # }
+    /// ```
+    fn into_vec(self) -> Vec<u8>;
+
+    /// Returns an object that implements `Show` for printing paths
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def");
+    /// println!("{}", p.display()); // prints "abc/def"
+    /// # }
+    /// ```
+    fn display<'a>(&'a self) -> Display<'a, Self> {
+        Display{ path: self, filename: false }
+    }
+
+    /// Returns an object that implements `Show` for printing filenames
+    ///
+    /// If there is no filename, nothing will be printed.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def");
+    /// println!("{}", p.filename_display()); // prints "def"
+    /// # }
+    /// ```
+    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).
+    /// If `self` has no directory component, returns ['.'].
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def/ghi");
+    /// assert_eq!(p.dirname(), b"abc/def");
+    /// # }
+    /// ```
+    fn dirname<'a>(&'a self) -> &'a [u8];
+
+    /// Returns the directory component of `self`, as a string, if possible.
+    /// See `dirname` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def/ghi");
+    /// assert_eq!(p.dirname_str(), Some("abc/def"));
+    /// # }
+    /// ```
+    #[inline]
+    fn dirname_str<'a>(&'a self) -> Option<&'a str> {
+        str::from_utf8(self.dirname()).ok()
+    }
+
+    /// Returns the file component of `self`, as a byte vector.
+    /// If `self` represents the root of the file hierarchy, returns None.
+    /// If `self` is "." or "..", returns None.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def/ghi");
+    /// assert_eq!(p.filename(), Some(b"ghi"));
+    /// # }
+    /// ```
+    fn filename<'a>(&'a self) -> Option<&'a [u8]>;
+
+    /// Returns the file component of `self`, as a string, if possible.
+    /// See `filename` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def/ghi");
+    /// assert_eq!(p.filename_str(), Some("ghi"));
+    /// # }
+    /// ```
+    #[inline]
+    fn filename_str<'a>(&'a self) -> Option<&'a str> {
+        self.filename().and_then(|s| str::from_utf8(s).ok())
+    }
+
+    /// Returns the stem of the filename of `self`, as a byte vector.
+    /// The stem is the portion of the filename just before the last '.'.
+    /// If there is no '.', the entire filename is returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("/abc/def.txt");
+    /// assert_eq!(p.filestem(), Some(b"def"));
+    /// # }
+    /// ```
+    fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
+        match self.filename() {
+            None => None,
+            Some(name) => Some({
+                let dot = b'.';
+                match name.rposition_elem(&dot) {
+                    None | Some(0) => name,
+                    Some(1) if name == b".." => name,
+                    Some(pos) => &name[..pos]
+                }
+            })
+        }
+    }
+
+    /// Returns the stem of the filename of `self`, as a string, if possible.
+    /// See `filestem` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("/abc/def.txt");
+    /// assert_eq!(p.filestem_str(), Some("def"));
+    /// # }
+    /// ```
+    #[inline]
+    fn filestem_str<'a>(&'a self) -> Option<&'a str> {
+        self.filestem().and_then(|s| str::from_utf8(s).ok())
+    }
+
+    /// Returns the extension of the filename of `self`, as an optional byte vector.
+    /// The extension is the portion of the filename just after the last '.'.
+    /// If there is no extension, None is returned.
+    /// If the filename ends in '.', the empty vector is returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def.txt");
+    /// assert_eq!(p.extension(), Some(b"txt"));
+    /// # }
+    /// ```
+    fn extension<'a>(&'a self) -> Option<&'a [u8]> {
+        match self.filename() {
+            None => None,
+            Some(name) => {
+                let dot = b'.';
+                match name.rposition_elem(&dot) {
+                    None | Some(0) => None,
+                    Some(1) if name == b".." => None,
+                    Some(pos) => Some(&name[pos+1..])
+                }
+            }
+        }
+    }
+
+    /// Returns the extension of the filename of `self`, as a string, if possible.
+    /// See `extension` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def.txt");
+    /// assert_eq!(p.extension_str(), Some("txt"));
+    /// # }
+    /// ```
+    #[inline]
+    fn extension_str<'a>(&'a self) -> Option<&'a str> {
+        self.extension().and_then(|s| str::from_utf8(s).ok())
+    }
+
+    /// Replaces the filename portion of the path with the given byte vector or string.
+    /// If the replacement name is [], this is equivalent to popping the path.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("abc/def.txt");
+    /// p.set_filename("foo.dat");
+    /// assert!(p == Path::new("abc/foo.dat"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the filename contains a NUL.
+    #[inline]
+    fn set_filename<T: BytesContainer>(&mut self, filename: T) {
+        assert!(!contains_nul(&filename));
+        unsafe { self.set_filename_unchecked(filename) }
+    }
+
+    /// Replaces the extension with the given byte vector or string.
+    /// If there is no extension in `self`, this adds one.
+    /// If the argument is [] or "", this removes the extension.
+    /// If `self` has no filename, this is a no-op.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("abc/def.txt");
+    /// p.set_extension("csv");
+    /// assert_eq!(p, Path::new("abc/def.csv"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the extension contains a NUL.
+    fn set_extension<T: BytesContainer>(&mut self, extension: T) {
+        assert!(!contains_nul(&extension));
+
+        let val = self.filename().and_then(|name| {
+            let dot = b'.';
+            let extlen = extension.container_as_bytes().len();
+            match (name.rposition_elem(&dot), extlen) {
+                (None, 0) | (Some(0), 0) => None,
+                (Some(idx), 0) => Some(name[..idx].to_vec()),
+                (idx, extlen) => {
+                    let idx = match idx {
+                        None | Some(0) => name.len(),
+                        Some(val) => val
+                    };
+
+                    let mut v;
+                    v = Vec::with_capacity(idx + extlen + 1);
+                    v.push_all(&name[..idx]);
+                    v.push(dot);
+                    v.push_all(extension.container_as_bytes());
+                    Some(v)
+                }
+            }
+        });
+
+        match val {
+            None => (),
+            Some(v) => unsafe { self.set_filename_unchecked(v) }
+        }
+    }
+
+    /// Returns a new Path constructed by replacing the filename with the given
+    /// byte vector or string.
+    /// See `set_filename` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("abc/def.txt");
+    /// assert_eq!(p.with_filename("foo.dat"), Path::new("abc/foo.dat"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the filename contains a NUL.
+    #[inline]
+    fn with_filename<T: BytesContainer>(&self, filename: T) -> Self {
+        let mut p = self.clone();
+        p.set_filename(filename);
+        p
+    }
+
+    /// Returns a new Path constructed by setting the extension to the given
+    /// byte vector or string.
+    /// See `set_extension` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("abc/def.txt");
+    /// assert_eq!(p.with_extension("csv"), Path::new("abc/def.csv"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the extension contains a NUL.
+    #[inline]
+    fn with_extension<T: BytesContainer>(&self, extension: T) -> Self {
+        let mut p = self.clone();
+        p.set_extension(extension);
+        p
+    }
+
+    /// Returns the directory component of `self`, as a Path.
+    /// If `self` represents the root of the filesystem hierarchy, returns `self`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def/ghi");
+    /// assert_eq!(p.dir_path(), Path::new("abc/def"));
+    /// # }
+    /// ```
+    fn dir_path(&self) -> Self {
+        // self.dirname() returns a NUL-free vector
+        unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) }
+    }
+
+    /// Returns a Path that represents the filesystem root that `self` is rooted in.
+    ///
+    /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// assert_eq!(Path::new("abc/def").root_path(), None);
+    /// assert_eq!(Path::new("/abc/def").root_path(), Some(Path::new("/")));
+    /// # }
+    /// ```
+    fn root_path(&self) -> Option<Self>;
+
+    /// Pushes a path (as a byte vector or string) onto `self`.
+    /// If the argument represents an absolute path, it replaces `self`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("foo/bar");
+    /// p.push("baz.txt");
+    /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the path contains a NUL.
+    #[inline]
+    fn push<T: BytesContainer>(&mut self, path: T) {
+        assert!(!contains_nul(&path));
+        unsafe { self.push_unchecked(path) }
+    }
+
+    /// Pushes multiple paths (as byte vectors or strings) onto `self`.
+    /// See `push` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("foo");
+    /// p.push_many(&["bar", "baz.txt"]);
+    /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
+    /// # }
+    /// ```
+    #[inline]
+    fn push_many<T: BytesContainer>(&mut self, paths: &[T]) {
+        let t: Option<&T> = None;
+        if BytesContainer::is_str(t) {
+            for p in paths {
+                self.push(p.container_as_str().unwrap())
+            }
+        } else {
+            for p in paths {
+                self.push(p.container_as_bytes())
+            }
+        }
+    }
+
+    /// Removes the last path component from the receiver.
+    /// Returns `true` if the receiver was modified, or `false` if it already
+    /// represented the root of the file hierarchy.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let mut p = Path::new("foo/bar/baz.txt");
+    /// p.pop();
+    /// assert_eq!(p, Path::new("foo/bar"));
+    /// # }
+    /// ```
+    fn pop(&mut self) -> bool;
+
+    /// Returns a new Path constructed by joining `self` with the given path
+    /// (as a byte vector or string).
+    /// If the given path is absolute, the new Path will represent just that.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("/foo");
+    /// assert_eq!(p.join("bar.txt"), Path::new("/foo/bar.txt"));
+    /// # }
+    /// ```
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the path contains a NUL.
+    #[inline]
+    fn join<T: BytesContainer>(&self, path: T) -> Self {
+        let mut p = self.clone();
+        p.push(path);
+        p
+    }
+
+    /// Returns a new Path constructed by joining `self` with the given paths
+    /// (as byte vectors or strings).
+    /// See `join` for details.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("foo");
+    /// let fbbq = Path::new("foo/bar/baz/quux.txt");
+    /// assert_eq!(p.join_many(&["bar", "baz", "quux.txt"]), fbbq);
+    /// # }
+    /// ```
+    #[inline]
+    fn join_many<T: BytesContainer>(&self, paths: &[T]) -> Self {
+        let mut p = self.clone();
+        p.push_many(paths);
+        p
+    }
+
+    /// Returns whether `self` represents an absolute path.
+    /// An absolute path is defined as one that, when joined to another path, will
+    /// yield back the same absolute path.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("/abc/def");
+    /// assert!(p.is_absolute());
+    /// # }
+    /// ```
+    fn is_absolute(&self) -> bool;
+
+    /// Returns whether `self` represents a relative path.
+    /// Typically this is the inverse of `is_absolute`.
+    /// But for Windows paths, it also means the path is not volume-relative or
+    /// relative to the current working directory.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("abc/def");
+    /// assert!(p.is_relative());
+    /// # }
+    /// ```
+    fn is_relative(&self) -> bool {
+        !self.is_absolute()
+    }
+
+    /// Returns whether `self` is equal to, or is an ancestor of, the given path.
+    /// If both paths are relative, they are compared as though they are relative
+    /// to the same parent path.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("foo/bar/baz/quux.txt");
+    /// let fb = Path::new("foo/bar");
+    /// let bq = Path::new("baz/quux.txt");
+    /// assert!(fb.is_ancestor_of(&p));
+    /// # }
+    /// ```
+    fn is_ancestor_of(&self, other: &Self) -> bool;
+
+    /// Returns the Path that, were it joined to `base`, would yield `self`.
+    /// If no such path exists, None is returned.
+    /// If `self` is absolute and `base` is relative, or on Windows if both
+    /// paths refer to separate drives, an absolute path is returned.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("foo/bar/baz/quux.txt");
+    /// let fb = Path::new("foo/bar");
+    /// let bq = Path::new("baz/quux.txt");
+    /// assert_eq!(p.path_relative_from(&fb), Some(bq));
+    /// # }
+    /// ```
+    fn path_relative_from(&self, base: &Self) -> Option<Self>;
+
+    /// Returns whether the relative path `child` is a suffix of `self`.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// # foo();
+    /// # #[cfg(windows)] fn foo() {}
+    /// # #[cfg(unix)] fn foo() {
+    /// let p = Path::new("foo/bar/baz/quux.txt");
+    /// let bq = Path::new("baz/quux.txt");
+    /// assert!(p.ends_with_path(&bq));
+    /// # }
+    /// ```
+    fn ends_with_path(&self, child: &Self) -> bool;
+}
+
+/// A trait that represents something bytes-like (e.g. a &[u8] or a &str)
+pub trait BytesContainer {
+    /// Returns a &[u8] representing the receiver
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8];
+    /// Returns the receiver interpreted as a utf-8 string, if possible
+    #[inline]
+    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
+        str::from_utf8(self.container_as_bytes()).ok()
+    }
+    /// 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 }
+}
+
+/// A trait that represents the unsafe operations on GenericPaths
+pub trait GenericPathUnsafe {
+    /// Creates a new Path without checking for null bytes.
+    /// The resulting Path will always be normalized.
+    unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Self;
+
+    /// Replaces the filename portion of the path without checking for null
+    /// bytes.
+    /// See `set_filename` for details.
+    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T);
+
+    /// Pushes a path onto `self` without checking for null bytes.
+    /// See `push` for details.
+    unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
+}
+
+/// Helper struct for printing paths with format!()
+pub struct Display<'a, P:'a> {
+    path: &'a P,
+    filename: bool
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: GenericPath> fmt::Debug for Display<'a, P> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.as_cow(), f)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, P: GenericPath> fmt::Display for Display<'a, P> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.as_cow().fmt(f)
+    }
+}
+
+impl<'a, P: GenericPath> Display<'a, P> {
+    /// Returns the path as a possibly-owned string.
+    ///
+    /// If the path is not UTF-8, invalid sequences will be replaced with the
+    /// Unicode replacement char. This involves allocation.
+    #[inline]
+    pub fn as_cow(&self) -> CowString<'a> {
+        String::from_utf8_lossy(if self.filename {
+            match self.path.filename() {
+                None => {
+                    let result: &[u8] = &[];
+                    result
+                }
+                Some(v) => v
+            }
+        } else {
+            self.path.as_vec()
+        })
+    }
+}
+
+impl BytesContainer for str {
+    #[inline]
+    fn container_as_bytes(&self) -> &[u8] {
+        self.as_bytes()
+    }
+    #[inline]
+    fn container_as_str(&self) -> Option<&str> {
+        Some(self)
+    }
+    #[inline]
+    fn is_str(_: Option<&str>) -> bool { true }
+}
+
+impl BytesContainer for String {
+    #[inline]
+    fn container_as_bytes(&self) -> &[u8] {
+        self.as_bytes()
+    }
+    #[inline]
+    fn container_as_str(&self) -> Option<&str> {
+        Some(&self[])
+    }
+    #[inline]
+    fn is_str(_: Option<&String>) -> bool { true }
+}
+
+impl BytesContainer for [u8] {
+    #[inline]
+    fn container_as_bytes(&self) -> &[u8] {
+        self
+    }
+}
+
+impl BytesContainer for Vec<u8> {
+    #[inline]
+    fn container_as_bytes(&self) -> &[u8] {
+        &self[]
+    }
+}
+
+impl BytesContainer for CString {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_bytes()
+    }
+}
+
+impl<'a, T: ?Sized + BytesContainer> BytesContainer for &'a T {
+    #[inline]
+    fn container_as_bytes(&self) -> &[u8] {
+        (**self).container_as_bytes()
+    }
+    #[inline]
+    fn container_as_str(&self) -> Option<&str> {
+        (**self).container_as_str()
+    }
+    #[inline]
+    fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) }
+}
+
+#[inline(always)]
+fn contains_nul<T: BytesContainer>(v: &T) -> bool {
+    v.container_as_bytes().iter().any(|&x| x == 0)
+}
diff --git a/src/libstd/old_path/posix.rs b/src/libstd/old_path/posix.rs
new file mode 100644 (file)
index 0000000..8bcdd89
--- /dev/null
@@ -0,0 +1,1348 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! POSIX file path handling
+
+use clone::Clone;
+use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
+use fmt;
+use hash;
+use old_io::Writer;
+use iter::{AdditiveIterator, Extend};
+use iter::{Iterator, IteratorExt, Map};
+use marker::Sized;
+use option::Option::{self, Some, None};
+use result::Result::{self, Ok, Err};
+use slice::{AsSlice, Split, SliceExt, SliceConcatExt};
+use str::{self, FromStr, StrExt};
+use vec::Vec;
+
+use super::{BytesContainer, GenericPath, GenericPathUnsafe};
+
+/// Iterator that yields successive components of a Path as &[u8]
+pub type Components<'a> = Split<'a, u8, fn(&u8) -> bool>;
+
+/// Iterator that yields successive components of a Path as Option<&str>
+pub type StrComponents<'a> =
+    Map<Components<'a>, fn(&[u8]) -> Option<&str>>;
+
+/// Represents a POSIX file path
+#[derive(Clone)]
+pub struct Path {
+    repr: Vec<u8>, // assumed to never be empty or contain NULs
+    sepidx: Option<uint> // index of the final separator in repr
+}
+
+/// The standard path separator character
+pub const SEP: char = '/';
+
+/// The standard path separator byte
+pub const SEP_BYTE: u8 = SEP as u8;
+
+/// Returns whether the given byte is a path separator
+#[inline]
+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
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.display(), f)
+    }
+}
+
+impl PartialEq for Path {
+    #[inline]
+    fn eq(&self, other: &Path) -> bool {
+        self.repr == other.repr
+    }
+}
+
+impl Eq for Path {}
+
+impl PartialOrd for Path {
+    fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Path {
+    fn cmp(&self, other: &Path) -> Ordering {
+        self.repr.cmp(&other.repr)
+    }
+}
+
+impl FromStr for Path {
+    type Err = ParsePathError;
+    fn from_str(s: &str) -> Result<Path, ParsePathError> {
+        match Path::new_opt(s) {
+            Some(p) => Ok(p),
+            None => Err(ParsePathError),
+        }
+    }
+}
+
+/// Valuelue indicating that a path could not be parsed from a string.
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct ParsePathError;
+
+impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
+    #[inline]
+    fn hash(&self, state: &mut S) {
+        self.repr.hash(state)
+    }
+}
+
+impl BytesContainer for 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_BYTE);
+        Path{ repr: path, sepidx: idx }
+    }
+
+    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
+        let filename = filename.container_as_bytes();
+        match self.sepidx {
+            None if b".." == self.repr => {
+                let mut v = Vec::with_capacity(3 + filename.len());
+                v.push_all(dot_dot_static);
+                v.push(SEP_BYTE);
+                v.push_all(filename);
+                // FIXME: this is slow
+                self.repr = Path::normalize(v.as_slice());
+            }
+            None => {
+                self.repr = Path::normalize(filename);
+            }
+            Some(idx) if &self.repr[idx+1..] == b".." => {
+                let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len());
+                v.push_all(self.repr.as_slice());
+                v.push(SEP_BYTE);
+                v.push_all(filename);
+                // FIXME: this is slow
+                self.repr = Path::normalize(v.as_slice());
+            }
+            Some(idx) => {
+                let mut v = Vec::with_capacity(idx + 1 + filename.len());
+                v.push_all(&self.repr[..idx+1]);
+                v.push_all(filename);
+                // FIXME: this is slow
+                self.repr = Path::normalize(v.as_slice());
+            }
+        }
+        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_BYTE {
+                self.repr = Path::normalize(path);
+            }  else {
+                let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1);
+                v.push_all(self.repr.as_slice());
+                v.push(SEP_BYTE);
+                v.push_all(path);
+                // FIXME: this is slow
+                self.repr = Path::normalize(v.as_slice());
+            }
+            self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
+        }
+    }
+}
+
+impl GenericPath for Path {
+    #[inline]
+    fn as_vec<'a>(&'a self) -> &'a [u8] {
+        self.repr.as_slice()
+    }
+
+    fn into_vec(self) -> Vec<u8> {
+        self.repr
+    }
+
+    fn dirname<'a>(&'a self) -> &'a [u8] {
+        match self.sepidx {
+            None if b".." == self.repr => self.repr.as_slice(),
+            None => dot_static,
+            Some(0) => &self.repr[..1],
+            Some(idx) if &self.repr[idx+1..] == b".." => self.repr.as_slice(),
+            Some(idx) => &self.repr[..idx]
+        }
+    }
+
+    fn filename<'a>(&'a self) -> Option<&'a [u8]> {
+        match self.sepidx {
+            None if b"." == self.repr ||
+                b".." == self.repr => None,
+            None => Some(self.repr.as_slice()),
+            Some(idx) if &self.repr[idx+1..] == b".." => None,
+            Some(0) if self.repr[1..].is_empty() => None,
+            Some(idx) => Some(&self.repr[idx+1..])
+        }
+    }
+
+    fn pop(&mut self) -> bool {
+        match self.sepidx {
+            None if b"." == self.repr => false,
+            None => {
+                self.repr = vec![b'.'];
+                self.sepidx = None;
+                true
+            }
+            Some(0) if b"/" == self.repr => false,
+            Some(idx) => {
+                if idx == 0 {
+                    self.repr.truncate(idx+1);
+                } else {
+                    self.repr.truncate(idx);
+                }
+                self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
+                true
+            }
+        }
+    }
+
+    fn root_path(&self) -> Option<Path> {
+        if self.is_absolute() {
+            Some(Path::new("/"))
+        } else {
+            None
+        }
+    }
+
+    #[inline]
+    fn is_absolute(&self) -> bool {
+        self.repr[0] == SEP_BYTE
+    }
+
+    fn is_ancestor_of(&self, other: &Path) -> bool {
+        if self.is_absolute() != other.is_absolute() {
+            false
+        } else {
+            let mut ita = self.components();
+            let mut itb = other.components();
+            if b"." == self.repr {
+                return match itb.next() {
+                    None => true,
+                    Some(b) => b != b".."
+                };
+            }
+            loop {
+                match (ita.next(), itb.next()) {
+                    (None, _) => break,
+                    (Some(a), Some(b)) if a == b => { continue },
+                    (Some(a), _) if a == b".." => {
+                        // if ita contains only .. components, it's an ancestor
+                        return ita.all(|x| x == b"..");
+                    }
+                    _ => return false
+                }
+            }
+            true
+        }
+    }
+
+    fn path_relative_from(&self, base: &Path) -> Option<Path> {
+        if self.is_absolute() != base.is_absolute() {
+            if self.is_absolute() {
+                Some(self.clone())
+            } else {
+                None
+            }
+        } else {
+            let mut ita = self.components();
+            let mut itb = base.components();
+            let mut comps = vec![];
+            loop {
+                match (ita.next(), itb.next()) {
+                    (None, None) => break,
+                    (Some(a), None) => {
+                        comps.push(a);
+                        comps.extend(ita.by_ref());
+                        break;
+                    }
+                    (None, _) => comps.push(dot_dot_static),
+                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
+                    (Some(a), Some(b)) if b == b"." => comps.push(a),
+                    (Some(_), Some(b)) if b == b".." => return None,
+                    (Some(a), Some(_)) => {
+                        comps.push(dot_dot_static);
+                        for _ in itb {
+                            comps.push(dot_dot_static);
+                        }
+                        comps.push(a);
+                        comps.extend(ita.by_ref());
+                        break;
+                    }
+                }
+            }
+            Some(Path::new(comps.connect(&SEP_BYTE)))
+        }
+    }
+
+    fn ends_with_path(&self, child: &Path) -> bool {
+        if !child.is_relative() { return false; }
+        let mut selfit = self.components().rev();
+        let mut childit = child.components().rev();
+        loop {
+            match (selfit.next(), childit.next()) {
+                (Some(a), Some(b)) => if a != b { return false; },
+                (Some(_), None) => break,
+                (None, Some(_)) => return false,
+                (None, None) => break
+            }
+        }
+        true
+    }
+}
+
+impl Path {
+    /// Returns a new Path from a byte vector or string
+    ///
+    /// # Panics
+    ///
+    /// Panics the task if the vector contains a NUL.
+    #[inline]
+    pub fn new<T: BytesContainer>(path: T) -> Path {
+        GenericPath::new(path)
+    }
+
+    /// Returns a new Path from a byte vector or string, if possible
+    #[inline]
+    pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
+        GenericPath::new_opt(path)
+    }
+
+    /// Returns a normalized byte vector representation of a path, by removing all empty
+    /// components, and unnecessary . and .. components.
+    fn normalize<V: ?Sized + AsSlice<u8>>(v: &V) -> Vec<u8> {
+        // borrowck is being very picky
+        let val = {
+            let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
+            let v_ = if is_abs { &v.as_slice()[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(vec![SEP_BYTE])
+                    } else {
+                        let n = if is_abs { comps.len() } else { comps.len() - 1} +
+                                comps.iter().map(|v| v.len()).sum();
+                        let mut v = Vec::with_capacity(n);
+                        let mut it = comps.into_iter();
+                        if !is_abs {
+                            match it.next() {
+                                None => (),
+                                Some(comp) => v.push_all(comp)
+                            }
+                        }
+                        for comp in it {
+                            v.push(SEP_BYTE);
+                            v.push_all(comp);
+                        }
+                        Some(v)
+                    }
+                }
+            }
+        };
+        match val {
+            None => v.as_slice().to_vec(),
+            Some(val) => val
+        }
+    }
+
+    /// Returns an iterator that yields each component of the path in turn.
+    /// Does not distinguish between absolute and relative paths, e.g.
+    /// /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 components<'a>(&'a self) -> Components<'a> {
+        let v = if self.repr[0] == SEP_BYTE {
+            &self.repr[1..]
+        } else { self.repr.as_slice() };
+        let is_sep_byte: fn(&u8) -> bool = is_sep_byte; // coerce to fn ptr
+        let mut ret = v.split(is_sep_byte);
+        if v.is_empty() {
+            // consume the empty "" component
+            ret.next();
+        }
+        ret
+    }
+
+    /// Returns an iterator that yields each component of the path as Option<&str>.
+    /// See components() for details.
+    pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
+        fn from_utf8(s: &[u8]) -> Option<&str> {
+            str::from_utf8(s).ok()
+        }
+        let f: fn(&[u8]) -> Option<&str> = from_utf8; // coerce to fn ptr
+        self.components().map(f)
+    }
+}
+
+// None result means the byte vector didn't need normalizing
+fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<Vec<&'a [u8]>> {
+    if is_abs && v.is_empty() {
+        return None;
+    }
+    let mut comps: Vec<&'a [u8]> = vec![];
+    let mut n_up = 0u;
+    let mut changed = false;
+    for comp in v.split(is_sep_byte) {
+        if comp.is_empty() { changed = true }
+        else if comp == b"." { changed = true }
+        else if comp == b".." {
+            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().unwrap(); changed = true }
+        } else { comps.push(comp) }
+    }
+    if changed {
+        if comps.is_empty() && !is_abs {
+            if v == b"." {
+                return None;
+            }
+            comps.push(dot_static);
+        }
+        Some(comps)
+    } else {
+        None
+    }
+}
+
+#[allow(non_upper_case_globals)]
+static dot_static: &'static [u8] = b".";
+#[allow(non_upper_case_globals)]
+static dot_dot_static: &'static [u8] = b"..";
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use clone::Clone;
+    use iter::IteratorExt;
+    use option::Option::{self, Some, None};
+    use old_path::GenericPath;
+    use slice::{AsSlice, SliceExt};
+    use str::{self, Str, StrExt};
+    use string::ToString;
+    use vec::Vec;
+
+    macro_rules! t {
+        (s: $path:expr, $exp:expr) => (
+            {
+                let path = $path;
+                assert_eq!(path.as_str(), Some($exp));
+            }
+        );
+        (v: $path:expr, $exp:expr) => (
+            {
+                let path = $path;
+                assert_eq!(path.as_vec(), $exp);
+            }
+        )
+    }
+
+    #[test]
+    fn test_paths() {
+        let empty: &[u8] = &[];
+        t!(v: Path::new(empty), b".");
+        t!(v: Path::new(b"/"), b"/");
+        t!(v: Path::new(b"a/b/c"), b"a/b/c");
+        t!(v: Path::new(b"a/b/c\xFF"), b"a/b/c\xFF");
+        t!(v: Path::new(b"\xFF/../foo\x80"), b"foo\x80");
+        let p = Path::new(b"a/b/c\xFF");
+        assert!(p.as_str().is_none());
+
+        t!(s: Path::new(""), ".");
+        t!(s: Path::new("/"), "/");
+        t!(s: Path::new("hi"), "hi");
+        t!(s: Path::new("hi/"), "hi");
+        t!(s: Path::new("/lib"), "/lib");
+        t!(s: Path::new("/lib/"), "/lib");
+        t!(s: Path::new("hi/there"), "hi/there");
+        t!(s: Path::new("hi/there.txt"), "hi/there.txt");
+
+        t!(s: Path::new("hi/there/"), "hi/there");
+        t!(s: Path::new("hi/../there"), "there");
+        t!(s: Path::new("../hi/there"), "../hi/there");
+        t!(s: Path::new("/../hi/there"), "/hi/there");
+        t!(s: Path::new("foo/.."), ".");
+        t!(s: Path::new("/foo/.."), "/");
+        t!(s: Path::new("/foo/../.."), "/");
+        t!(s: Path::new("/foo/../../bar"), "/bar");
+        t!(s: Path::new("/./hi/./there/."), "/hi/there");
+        t!(s: Path::new("/./hi/./there/./.."), "/hi");
+        t!(s: Path::new("foo/../.."), "..");
+        t!(s: Path::new("foo/../../.."), "../..");
+        t!(s: Path::new("foo/../../bar"), "../bar");
+
+        assert_eq!(Path::new(b"foo/bar").into_vec(), b"foo/bar");
+        assert_eq!(Path::new(b"/foo/../../bar").into_vec(),
+                   b"/bar");
+
+        let p = Path::new(b"foo/bar\x80");
+        assert!(p.as_str().is_none());
+    }
+
+    #[test]
+    fn test_opt_paths() {
+        assert!(Path::new_opt(b"foo/bar\0").is_none());
+        t!(v: Path::new_opt(b"foo/bar").unwrap(), b"foo/bar");
+        assert!(Path::new_opt("foo/bar\0").is_none());
+        t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar");
+    }
+
+    #[test]
+    fn test_null_byte() {
+        use thread::Thread;
+        let result = Thread::scoped(move|| {
+            Path::new(b"foo/bar\0")
+        }).join();
+        assert!(result.is_err());
+
+        let result = Thread::scoped(move|| {
+            Path::new("test").set_filename(b"f\0o")
+        }).join();
+        assert!(result.is_err());
+
+        let result = Thread::scoped(move|| {
+            Path::new("test").push(b"f\0o");
+        }).join();
+        assert!(result.is_err());
+    }
+
+    #[test]
+    fn test_display_str() {
+        macro_rules! t {
+            ($path:expr, $disp:ident, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    assert_eq!(path.$disp().to_string(), $exp);
+                }
+            )
+        }
+        t!("foo", display, "foo");
+        t!(b"foo\x80", display, "foo\u{FFFD}");
+        t!(b"foo\xFFbar", display, "foo\u{FFFD}bar");
+        t!(b"foo\xFF/bar", filename_display, "bar");
+        t!(b"foo/\xFFbar", filename_display, "\u{FFFD}bar");
+        t!(b"/", filename_display, "");
+
+        macro_rules! t {
+            ($path:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let mo = path.display().as_cow();
+                    assert_eq!(mo.as_slice(), $exp);
+                }
+            );
+            ($path:expr, $exp:expr, filename) => (
+                {
+                    let path = Path::new($path);
+                    let mo = path.filename_display().as_cow();
+                    assert_eq!(mo.as_slice(), $exp);
+                }
+            )
+        }
+
+        t!("foo", "foo");
+        t!(b"foo\x80", "foo\u{FFFD}");
+        t!(b"foo\xFFbar", "foo\u{FFFD}bar");
+        t!(b"foo\xFF/bar", "bar", filename);
+        t!(b"foo/\xFFbar", "\u{FFFD}bar", filename);
+        t!(b"/", "", filename);
+    }
+
+    #[test]
+    fn test_display() {
+        macro_rules! t {
+            ($path:expr, $exp:expr, $expf:expr) => (
+                {
+                    let path = Path::new($path);
+                    let f = format!("{}", path.display());
+                    assert_eq!(f, $exp);
+                    let f = format!("{}", path.filename_display());
+                    assert_eq!(f, $expf);
+                }
+            )
+        }
+
+        t!(b"foo", "foo", "foo");
+        t!(b"foo/bar", "foo/bar", "bar");
+        t!(b"/", "/", "");
+        t!(b"foo\xFF", "foo\u{FFFD}", "foo\u{FFFD}");
+        t!(b"foo\xFF/bar", "foo\u{FFFD}/bar", "bar");
+        t!(b"foo/\xFFbar", "foo/\u{FFFD}bar", "\u{FFFD}bar");
+        t!(b"\xFFfoo/bar\xFF", "\u{FFFD}foo/bar\u{FFFD}", "bar\u{FFFD}");
+    }
+
+    #[test]
+    fn test_components() {
+        macro_rules! t {
+            (s: $path:expr, $op:ident, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    assert_eq!(path.$op(), ($exp).as_bytes());
+                }
+            );
+            (s: $path:expr, $op:ident, $exp:expr, opt) => (
+                {
+                    let path = Path::new($path);
+                    let left = path.$op().map(|x| str::from_utf8(x).unwrap());
+                    assert_eq!(left, $exp);
+                }
+            );
+            (v: $path:expr, $op:ident, $exp:expr) => (
+                {
+                    let arg = $path;
+                    let path = Path::new(arg);
+                    assert_eq!(path.$op(), $exp);
+                }
+            );
+        }
+
+        t!(v: b"a/b/c", filename, Some(b"c"));
+        t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF"));
+        t!(v: b"a/b\xFF/c", filename, Some(b"c"));
+        t!(s: "a/b/c", filename, Some("c"), opt);
+        t!(s: "/a/b/c", filename, Some("c"), opt);
+        t!(s: "a", filename, Some("a"), opt);
+        t!(s: "/a", filename, Some("a"), opt);
+        t!(s: ".", filename, None, opt);
+        t!(s: "/", filename, None, opt);
+        t!(s: "..", filename, None, opt);
+        t!(s: "../..", filename, None, opt);
+
+        t!(v: b"a/b/c", dirname, b"a/b");
+        t!(v: b"a/b/c\xFF", dirname, b"a/b");
+        t!(v: b"a/b\xFF/c", dirname, b"a/b\xFF");
+        t!(s: "a/b/c", dirname, "a/b");
+        t!(s: "/a/b/c", dirname, "/a/b");
+        t!(s: "a", dirname, ".");
+        t!(s: "/a", dirname, "/");
+        t!(s: ".", dirname, ".");
+        t!(s: "/", dirname, "/");
+        t!(s: "..", dirname, "..");
+        t!(s: "../..", dirname, "../..");
+
+        t!(v: b"hi/there.txt", filestem, Some(b"there"));
+        t!(v: b"hi/there\x80.txt", filestem, Some(b"there\x80"));
+        t!(v: b"hi/there.t\x80xt", filestem, Some(b"there"));
+        t!(s: "hi/there.txt", filestem, Some("there"), opt);
+        t!(s: "hi/there", filestem, Some("there"), opt);
+        t!(s: "there.txt", filestem, Some("there"), opt);
+        t!(s: "there", filestem, Some("there"), opt);
+        t!(s: ".", filestem, None, opt);
+        t!(s: "/", filestem, None, opt);
+        t!(s: "foo/.bar", filestem, Some(".bar"), opt);
+        t!(s: ".bar", filestem, Some(".bar"), opt);
+        t!(s: "..bar", filestem, Some("."), opt);
+        t!(s: "hi/there..txt", filestem, Some("there."), opt);
+        t!(s: "..", filestem, None, opt);
+        t!(s: "../..", filestem, None, opt);
+
+        t!(v: b"hi/there.txt", extension, Some(b"txt"));
+        t!(v: b"hi/there\x80.txt", extension, Some(b"txt"));
+        t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt"));
+        t!(v: b"hi/there", extension, None);
+        t!(v: b"hi/there\x80", extension, None);
+        t!(s: "hi/there.txt", extension, Some("txt"), opt);
+        t!(s: "hi/there", extension, None, opt);
+        t!(s: "there.txt", extension, Some("txt"), opt);
+        t!(s: "there", extension, None, opt);
+        t!(s: ".", extension, None, opt);
+        t!(s: "/", extension, None, opt);
+        t!(s: "foo/.bar", extension, None, opt);
+        t!(s: ".bar", extension, None, opt);
+        t!(s: "..bar", extension, Some("bar"), opt);
+        t!(s: "hi/there..txt", extension, Some("txt"), opt);
+        t!(s: "..", extension, None, opt);
+        t!(s: "../..", extension, None, opt);
+    }
+
+    #[test]
+    fn test_push() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr) => (
+                {
+                    let path = $path;
+                    let join = $join;
+                    let mut p1 = Path::new(path);
+                    let p2 = p1.clone();
+                    p1.push(join);
+                    assert_eq!(p1, p2.join(join));
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "..");
+        t!(s: "/a/b/c", "d");
+        t!(s: "a/b", "c/d");
+        t!(s: "a/b", "/c/d");
+    }
+
+    #[test]
+    fn test_push_path() {
+        macro_rules! t {
+            (s: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    let push = Path::new($push);
+                    p.push(&push);
+                    assert_eq!(p.as_str(), Some($exp));
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "d", "a/b/c/d");
+        t!(s: "/a/b/c", "d", "/a/b/c/d");
+        t!(s: "a/b", "c/d", "a/b/c/d");
+        t!(s: "a/b", "/c/d", "/c/d");
+        t!(s: "a/b", ".", "a/b");
+        t!(s: "a/b", "../c", "a/c");
+    }
+
+    #[test]
+    fn test_push_many() {
+        macro_rules! t {
+            (s: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    p.push_many(&$push);
+                    assert_eq!(p.as_str(), Some($exp));
+                }
+            );
+            (v: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    p.push_many(&$push);
+                    assert_eq!(p.as_vec(), $exp);
+                }
+            )
+        }
+
+        t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
+        t!(s: "a/b/c", ["d", "/e"], "/e");
+        t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
+        t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e");
+        t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e");
+        t!(v: b"a/b/c", [b"d", b"/e", b"f"], b"/e/f");
+        t!(v: b"a/b/c", [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e");
+    }
+
+    #[test]
+    fn test_pop() {
+        macro_rules! t {
+            (s: $path:expr, $left:expr, $right:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    let result = p.pop();
+                    assert_eq!(p.as_str(), Some($left));
+                    assert_eq!(result, $right);
+                }
+            );
+            (b: $path:expr, $left:expr, $right:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    let result = p.pop();
+                    assert_eq!(p.as_vec(), $left);
+                    assert_eq!(result, $right);
+                }
+            )
+        }
+
+        t!(b: b"a/b/c", b"a/b", true);
+        t!(b: b"a", b".", true);
+        t!(b: b".", b".", false);
+        t!(b: b"/a", b"/", true);
+        t!(b: b"/", b"/", false);
+        t!(b: b"a/b/c\x80", b"a/b", true);
+        t!(b: b"a/b\x80/c", b"a/b\x80", true);
+        t!(b: b"\xFF", b".", true);
+        t!(b: b"/\xFF", b"/", true);
+        t!(s: "a/b/c", "a/b", true);
+        t!(s: "a", ".", true);
+        t!(s: ".", ".", false);
+        t!(s: "/a", "/", true);
+        t!(s: "/", "/", false);
+    }
+
+    #[test]
+    fn test_root_path() {
+        assert_eq!(Path::new(b"a/b/c").root_path(), None);
+        assert_eq!(Path::new(b"/a/b/c").root_path(), Some(Path::new("/")));
+    }
+
+    #[test]
+    fn test_join() {
+        t!(v: Path::new(b"a/b/c").join(b".."), b"a/b");
+        t!(v: Path::new(b"/a/b/c").join(b"d"), b"/a/b/c/d");
+        t!(v: Path::new(b"a/\x80/c").join(b"\xFF"), b"a/\x80/c/\xFF");
+        t!(s: Path::new("a/b/c").join(".."), "a/b");
+        t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d");
+        t!(s: Path::new("a/b").join("c/d"), "a/b/c/d");
+        t!(s: Path::new("a/b").join("/c/d"), "/c/d");
+        t!(s: Path::new(".").join("a/b"), "a/b");
+        t!(s: Path::new("/").join("a/b"), "/a/b");
+    }
+
+    #[test]
+    fn test_join_path() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let join = Path::new($join);
+                    let res = path.join(&join);
+                    assert_eq!(res.as_str(), Some($exp));
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "..", "a/b");
+        t!(s: "/a/b/c", "d", "/a/b/c/d");
+        t!(s: "a/b", "c/d", "a/b/c/d");
+        t!(s: "a/b", "/c/d", "/c/d");
+        t!(s: ".", "a/b", "a/b");
+        t!(s: "/", "a/b", "/a/b");
+    }
+
+    #[test]
+    fn test_join_many() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let res = path.join_many(&$join);
+                    assert_eq!(res.as_str(), Some($exp));
+                }
+            );
+            (v: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let res = path.join_many(&$join);
+                    assert_eq!(res.as_vec(), $exp);
+                }
+            )
+        }
+
+        t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
+        t!(s: "a/b/c", ["..", "d"], "a/b/d");
+        t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
+        t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e");
+        t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e");
+        t!(v: b"a/b/c", [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e");
+    }
+
+    #[test]
+    fn test_with_helpers() {
+        let empty: &[u8] = &[];
+
+        t!(v: Path::new(b"a/b/c").with_filename(b"d"), b"a/b/d");
+        t!(v: Path::new(b"a/b/c\xFF").with_filename(b"\x80"), b"a/b/\x80");
+        t!(v: Path::new(b"/\xFF/foo").with_filename(b"\xCD"),
+              b"/\xFF/\xCD");
+        t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d");
+        t!(s: Path::new(".").with_filename("foo"), "foo");
+        t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d");
+        t!(s: Path::new("/").with_filename("foo"), "/foo");
+        t!(s: Path::new("/a").with_filename("foo"), "/foo");
+        t!(s: Path::new("foo").with_filename("bar"), "bar");
+        t!(s: Path::new("/").with_filename("foo/"), "/foo");
+        t!(s: Path::new("/a").with_filename("foo/"), "/foo");
+        t!(s: Path::new("a/b/c").with_filename(""), "a/b");
+        t!(s: Path::new("a/b/c").with_filename("."), "a/b");
+        t!(s: Path::new("a/b/c").with_filename(".."), "a");
+        t!(s: Path::new("/a").with_filename(""), "/");
+        t!(s: Path::new("foo").with_filename(""), ".");
+        t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e");
+        t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d");
+        t!(s: Path::new("..").with_filename("foo"), "../foo");
+        t!(s: Path::new("../..").with_filename("foo"), "../../foo");
+        t!(s: Path::new("..").with_filename(""), "..");
+        t!(s: Path::new("../..").with_filename(""), "../..");
+
+        t!(v: Path::new(b"hi/there\x80.txt").with_extension(b"exe"),
+              b"hi/there\x80.exe");
+        t!(v: Path::new(b"hi/there.txt\x80").with_extension(b"\xFF"),
+              b"hi/there.\xFF");
+        t!(v: Path::new(b"hi/there\x80").with_extension(b"\xFF"),
+              b"hi/there\x80.\xFF");
+        t!(v: Path::new(b"hi/there.\xFF").with_extension(empty), b"hi/there");
+        t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe");
+        t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there");
+        t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there..");
+        t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there...");
+        t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt");
+        t!(s: Path::new("hi/there").with_extension("."), "hi/there..");
+        t!(s: Path::new("hi/there").with_extension(".."), "hi/there...");
+        t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt");
+        t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt");
+        t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo");
+        t!(s: Path::new("/").with_extension("txt"), "/");
+        t!(s: Path::new("/").with_extension("."), "/");
+        t!(s: Path::new("/").with_extension(".."), "/");
+        t!(s: Path::new(".").with_extension("txt"), ".");
+    }
+
+    #[test]
+    fn test_setters() {
+        macro_rules! t {
+            (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
+                {
+                    let path = $path;
+                    let arg = $arg;
+                    let mut p1 = Path::new(path);
+                    p1.$set(arg);
+                    let p2 = Path::new(path);
+                    assert_eq!(p1, p2.$with(arg));
+                }
+            );
+            (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
+                {
+                    let path = $path;
+                    let arg = $arg;
+                    let mut p1 = Path::new(path);
+                    p1.$set(arg);
+                    let p2 = Path::new(path);
+                    assert_eq!(p1, p2.$with(arg));
+                }
+            )
+        }
+
+        t!(v: b"a/b/c", set_filename, with_filename, b"d");
+        t!(v: b"/", set_filename, with_filename, b"foo");
+        t!(v: b"\x80", set_filename, with_filename, b"\xFF");
+        t!(s: "a/b/c", set_filename, with_filename, "d");
+        t!(s: "/", set_filename, with_filename, "foo");
+        t!(s: ".", set_filename, with_filename, "foo");
+        t!(s: "a/b", set_filename, with_filename, "");
+        t!(s: "a", set_filename, with_filename, "");
+
+        t!(v: b"hi/there.txt", set_extension, with_extension, b"exe");
+        t!(v: b"hi/there.t\x80xt", set_extension, with_extension, b"exe\xFF");
+        t!(s: "hi/there.txt", set_extension, with_extension, "exe");
+        t!(s: "hi/there.", set_extension, with_extension, "txt");
+        t!(s: "hi/there", set_extension, with_extension, "txt");
+        t!(s: "hi/there.txt", set_extension, with_extension, "");
+        t!(s: "hi/there", set_extension, with_extension, "");
+        t!(s: ".", set_extension, with_extension, "txt");
+    }
+
+    #[test]
+    fn test_getters() {
+        macro_rules! t {
+            (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
+                {
+                    let path = $path;
+                    assert_eq!(path.filename_str(), $filename);
+                    assert_eq!(path.dirname_str(), $dirname);
+                    assert_eq!(path.filestem_str(), $filestem);
+                    assert_eq!(path.extension_str(), $ext);
+               }
+            );
+            (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
+                {
+                    let path = $path;
+                    assert_eq!(path.filename(), $filename);
+                    assert_eq!(path.dirname(), $dirname);
+                    assert_eq!(path.filestem(), $filestem);
+                    assert_eq!(path.extension(), $ext);
+                }
+            )
+        }
+
+        t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None);
+        t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
+        t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi",
+              Some(b"there"), Some(b"\xFF"));
+        t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None);
+        t!(s: Path::new("."), None, Some("."), None, None);
+        t!(s: Path::new("/"), None, Some("/"), None, None);
+        t!(s: Path::new(".."), None, Some(".."), None, None);
+        t!(s: Path::new("../.."), None, Some("../.."), None, None);
+        t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
+              Some("there"), Some("txt"));
+        t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
+        t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
+              Some("there"), Some(""));
+        t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
+        t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
+              Some("."), Some("there"));
+        t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None);
+        t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt"));
+        t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None);
+        t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None);
+    }
+
+    #[test]
+    fn test_dir_path() {
+        t!(v: Path::new(b"hi/there\x80").dir_path(), b"hi");
+        t!(v: Path::new(b"hi\xFF/there").dir_path(), b"hi\xFF");
+        t!(s: Path::new("hi/there").dir_path(), "hi");
+        t!(s: Path::new("hi").dir_path(), ".");
+        t!(s: Path::new("/hi").dir_path(), "/");
+        t!(s: Path::new("/").dir_path(), "/");
+        t!(s: Path::new("..").dir_path(), "..");
+        t!(s: Path::new("../..").dir_path(), "../..");
+    }
+
+    #[test]
+    fn test_is_absolute() {
+        macro_rules! t {
+            (s: $path:expr, $abs:expr, $rel:expr) => (
+                {
+                    let path = Path::new($path);
+                    assert_eq!(path.is_absolute(), $abs);
+                    assert_eq!(path.is_relative(), $rel);
+                }
+            )
+        }
+        t!(s: "a/b/c", false, true);
+        t!(s: "/a/b/c", true, false);
+        t!(s: "a", false, true);
+        t!(s: "/a", true, false);
+        t!(s: ".", false, true);
+        t!(s: "/", true, false);
+        t!(s: "..", false, true);
+        t!(s: "../..", false, true);
+    }
+
+    #[test]
+    fn test_is_ancestor_of() {
+        macro_rules! t {
+            (s: $path:expr, $dest:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let dest = Path::new($dest);
+                    assert_eq!(path.is_ancestor_of(&dest), $exp);
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "a/b/c/d", true);
+        t!(s: "a/b/c", "a/b/c", true);
+        t!(s: "a/b/c", "a/b", false);
+        t!(s: "/a/b/c", "/a/b/c", true);
+        t!(s: "/a/b", "/a/b/c", true);
+        t!(s: "/a/b/c/d", "/a/b/c", false);
+        t!(s: "/a/b", "a/b/c", false);
+        t!(s: "a/b", "/a/b/c", false);
+        t!(s: "a/b/c", "a/b/d", false);
+        t!(s: "../a/b/c", "a/b/c", false);
+        t!(s: "a/b/c", "../a/b/c", false);
+        t!(s: "a/b/c", "a/b/cd", false);
+        t!(s: "a/b/cd", "a/b/c", false);
+        t!(s: "../a/b", "../a/b/c", true);
+        t!(s: ".", "a/b", true);
+        t!(s: ".", ".", true);
+        t!(s: "/", "/", true);
+        t!(s: "/", "/a/b", true);
+        t!(s: "..", "a/b", true);
+        t!(s: "../..", "a/b", true);
+    }
+
+    #[test]
+    fn test_ends_with_path() {
+        macro_rules! t {
+            (s: $path:expr, $child:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let child = Path::new($child);
+                    assert_eq!(path.ends_with_path(&child), $exp);
+                }
+            );
+            (v: $path:expr, $child:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let child = Path::new($child);
+                    assert_eq!(path.ends_with_path(&child), $exp);
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "c", true);
+        t!(s: "a/b/c", "d", false);
+        t!(s: "foo/bar/quux", "bar", false);
+        t!(s: "foo/bar/quux", "barquux", false);
+        t!(s: "a/b/c", "b/c", true);
+        t!(s: "a/b/c", "a/b/c", true);
+        t!(s: "a/b/c", "foo/a/b/c", false);
+        t!(s: "/a/b/c", "a/b/c", true);
+        t!(s: "/a/b/c", "/a/b/c", false); // child must be relative
+        t!(s: "/a/b/c", "foo/a/b/c", false);
+        t!(s: "a/b/c", "", false);
+        t!(s: "", "", true);
+        t!(s: "/a/b/c", "d/e/f", false);
+        t!(s: "a/b/c", "a/b", false);
+        t!(s: "a/b/c", "b", false);
+        t!(v: b"a/b/c", b"b/c", true);
+        t!(v: b"a/b/\xFF", b"\xFF", true);
+        t!(v: b"a/b/\xFF", b"b/\xFF", true);
+    }
+
+    #[test]
+    fn test_path_relative_from() {
+        macro_rules! t {
+            (s: $path:expr, $other:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let other = Path::new($other);
+                    let res = path.path_relative_from(&other);
+                    assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
+                }
+            )
+        }
+
+        t!(s: "a/b/c", "a/b", Some("c"));
+        t!(s: "a/b/c", "a/b/d", Some("../c"));
+        t!(s: "a/b/c", "a/b/c/d", Some(".."));
+        t!(s: "a/b/c", "a/b/c", Some("."));
+        t!(s: "a/b/c", "a/b/c/d/e", Some("../.."));
+        t!(s: "a/b/c", "a/d/e", Some("../../b/c"));
+        t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c"));
+        t!(s: "a/b/c", "/a/b/c", None);
+        t!(s: "/a/b/c", "a/b/c", Some("/a/b/c"));
+        t!(s: "/a/b/c", "/a/b/c/d", Some(".."));
+        t!(s: "/a/b/c", "/a/b", Some("c"));
+        t!(s: "/a/b/c", "/a/b/c/d/e", Some("../.."));
+        t!(s: "/a/b/c", "/a/d/e", Some("../../b/c"));
+        t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c"));
+        t!(s: "hi/there.txt", "hi/there", Some("../there.txt"));
+        t!(s: ".", "a", Some(".."));
+        t!(s: ".", "a/b", Some("../.."));
+        t!(s: ".", ".", Some("."));
+        t!(s: "a", ".", Some("a"));
+        t!(s: "a/b", ".", Some("a/b"));
+        t!(s: "..", ".", Some(".."));
+        t!(s: "a/b/c", "a/b/c", Some("."));
+        t!(s: "/a/b/c", "/a/b/c", Some("."));
+        t!(s: "/", "/", Some("."));
+        t!(s: "/", ".", Some("/"));
+        t!(s: "../../a", "b", Some("../../../a"));
+        t!(s: "a", "../../b", None);
+        t!(s: "../../a", "../../b", Some("../a"));
+        t!(s: "../../a", "../../a/b", Some(".."));
+        t!(s: "../../a/b", "../../a", Some("b"));
+    }
+
+    #[test]
+    fn test_components_iter() {
+        macro_rules! t {
+            (s: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let comps = path.components().collect::<Vec<&[u8]>>();
+                    let exp: &[&str] = &$exp;
+                    let exps = exp.iter().map(|x| x.as_bytes()).collect::<Vec<&[u8]>>();
+                    assert_eq!(comps, exps);
+                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
+                    let exps = exps.into_iter().rev().collect::<Vec<&[u8]>>();
+                    assert_eq!(comps, exps);
+                }
+            );
+            (b: $arg:expr, [$($exp:expr),*]) => (
+                {
+                    let path = Path::new($arg);
+                    let comps = path.components().collect::<Vec<&[u8]>>();
+                    let exp: &[&[u8]] = &[$($exp),*];
+                    assert_eq!(comps, exp);
+                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
+                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
+                    assert_eq!(comps, exp)
+                }
+            )
+        }
+
+        t!(b: b"a/b/c", [b"a", b"b", b"c"]);
+        t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]);
+        t!(b: b"../../foo\xCDbar", [b"..", b"..", b"foo\xCDbar"]);
+        t!(s: "a/b/c", ["a", "b", "c"]);
+        t!(s: "a/b/d", ["a", "b", "d"]);
+        t!(s: "a/b/cd", ["a", "b", "cd"]);
+        t!(s: "/a/b/c", ["a", "b", "c"]);
+        t!(s: "a", ["a"]);
+        t!(s: "/a", ["a"]);
+        t!(s: "/", []);
+        t!(s: ".", ["."]);
+        t!(s: "..", [".."]);
+        t!(s: "../..", ["..", ".."]);
+        t!(s: "../../foo", ["..", "..", "foo"]);
+    }
+
+    #[test]
+    fn test_str_components() {
+        macro_rules! t {
+            (b: $arg:expr, $exp:expr) => (
+                {
+                    let path = Path::new($arg);
+                    let comps = path.str_components().collect::<Vec<Option<&str>>>();
+                    let exp: &[Option<&str>] = &$exp;
+                    assert_eq!(comps, exp);
+                    let comps = path.str_components().rev().collect::<Vec<Option<&str>>>();
+                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<Option<&str>>>();
+                    assert_eq!(comps, exp);
+                }
+            )
+        }
+
+        t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]);
+        t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]);
+        t!(b: b"../../foo\xCDbar", [Some(".."), Some(".."), None]);
+        // str_components is a wrapper around components, so no need to do
+        // the full set of tests
+    }
+}
+
+#[cfg(test)]
+mod bench {
+    extern crate test;
+    use self::test::Bencher;
+    use super::*;
+    use prelude::v1::{Clone, GenericPath};
+
+    #[bench]
+    fn join_home_dir(b: &mut Bencher) {
+        let posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.join("home");
+        });
+    }
+
+    #[bench]
+    fn join_abs_path_home_dir(b: &mut Bencher) {
+        let posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.join("/home");
+        });
+    }
+
+    #[bench]
+    fn join_many_home_dir(b: &mut Bencher) {
+        let posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.join_many(&["home"]);
+        });
+    }
+
+    #[bench]
+    fn join_many_abs_path_home_dir(b: &mut Bencher) {
+        let posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.join_many(&["/home"]);
+        });
+    }
+
+    #[bench]
+    fn push_home_dir(b: &mut Bencher) {
+        let mut posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.push("home");
+        });
+    }
+
+    #[bench]
+    fn push_abs_path_home_dir(b: &mut Bencher) {
+        let mut posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.push("/home");
+        });
+    }
+
+    #[bench]
+    fn push_many_home_dir(b: &mut Bencher) {
+        let mut posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.push_many(&["home"]);
+        });
+    }
+
+    #[bench]
+    fn push_many_abs_path_home_dir(b: &mut Bencher) {
+        let mut posix_path = Path::new("/");
+        b.iter(|| {
+            posix_path.push_many(&["/home"]);
+        });
+    }
+
+    #[bench]
+    fn ends_with_path_home_dir(b: &mut Bencher) {
+        let posix_home_path = Path::new("/home");
+        b.iter(|| {
+            posix_home_path.ends_with_path(&Path::new("home"));
+        });
+    }
+
+    #[bench]
+    fn ends_with_path_missmatch_jome_home(b: &mut Bencher) {
+        let posix_home_path = Path::new("/home");
+        b.iter(|| {
+            posix_home_path.ends_with_path(&Path::new("jome"));
+        });
+    }
+
+    #[bench]
+    fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) {
+        let path = Path::new("/home/1/2/3/4/5/6/7/8/9");
+        let mut sub = path.clone();
+        sub.pop();
+        b.iter(|| {
+            path.is_ancestor_of(&sub);
+        });
+    }
+
+    #[bench]
+    fn path_relative_from_forward(b: &mut Bencher) {
+        let path = Path::new("/a/b/c");
+        let mut other = path.clone();
+        other.pop();
+        b.iter(|| {
+            path.path_relative_from(&other);
+        });
+    }
+
+    #[bench]
+    fn path_relative_from_same_level(b: &mut Bencher) {
+        let path = Path::new("/a/b/c");
+        let mut other = path.clone();
+        other.pop();
+        other.push("d");
+        b.iter(|| {
+            path.path_relative_from(&other);
+        });
+    }
+
+    #[bench]
+    fn path_relative_from_backward(b: &mut Bencher) {
+        let path = Path::new("/a/b");
+        let mut other = path.clone();
+        other.push("c");
+        b.iter(|| {
+            path.path_relative_from(&other);
+        });
+    }
+}
diff --git a/src/libstd/old_path/windows.rs b/src/libstd/old_path/windows.rs
new file mode 100644 (file)
index 0000000..2e25403
--- /dev/null
@@ -0,0 +1,2329 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+//
+// ignore-lexer-test FIXME #15883
+
+//! Windows file path handling
+
+use self::PathPrefix::*;
+
+use ascii::AsciiExt;
+use char::CharExt;
+use clone::Clone;
+use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
+use fmt;
+use hash;
+use old_io::Writer;
+use iter::{AdditiveIterator, Extend};
+use iter::{Iterator, IteratorExt, Map, repeat};
+use mem;
+use option::Option::{self, Some, None};
+use result::Result::{self, Ok, Err};
+use slice::{SliceExt, SliceConcatExt};
+use str::{SplitTerminator, FromStr, StrExt};
+use string::{String, ToString};
+use vec::Vec;
+
+use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe};
+
+/// Iterator that yields successive components of a Path as &str
+///
+/// Each component is yielded as Option<&str> for compatibility with PosixPath, but
+/// every component in WindowsPath is guaranteed to be Some.
+pub type StrComponents<'a> =
+    Map<SplitTerminator<'a, char>, fn(&'a str) -> Option<&'a str>>;
+
+/// Iterator that yields successive components of a Path as &[u8]
+pub type Components<'a> =
+    Map<StrComponents<'a>, fn(Option<&str>) -> &[u8]>;
+
+/// Represents a Windows path
+// Notes for Windows path impl:
+// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs
+// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information
+// about windows paths.
+// That same page puts a bunch of restrictions on allowed characters in a path.
+// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here
+// as `∃P | P.join("\foo.txt") != "\foo.txt"`.
+// `C:` is interesting, that means "the current directory on drive C".
+// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be
+// ignored for now, though, and only added in a hypothetical .to_pwstr() function.
+// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the
+// processing of "." and ".." components and / as a separator.
+// Experimentally, \\?\foo is not the same thing as \foo.
+// Also, \\foo is not valid either (certainly not equivalent to \foo).
+// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent
+// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be
+// best to just ignore that and normalize it to C:\foo\bar.
+//
+// Based on all this, I think the right approach is to do the following:
+// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible
+// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure).
+// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly.
+// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing
+//   server\share.
+// * If \\?\, parse disk from following component, if present. Don't error for missing disk.
+// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled
+//   here, they probably aren't, but I'm not going to worry about that.
+// * Else if starts with \\, treat following two components as server\share. Don't error for missing
+//   server\share.
+// * Otherwise, attempt to parse drive from start of path.
+//
+// The only error condition imposed here is valid utf-8. All other invalid paths are simply
+// preserved by the data structure; let the Windows API error out on them.
+#[derive(Clone)]
+pub struct Path {
+    repr: String, // assumed to never be empty
+    prefix: Option<PathPrefix>,
+    sepidx: Option<uint> // index of the final separator in the non-prefix portion of repr
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Path {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.display(), f)
+    }
+}
+
+impl PartialEq for Path {
+    #[inline]
+    fn eq(&self, other: &Path) -> bool {
+        self.repr == other.repr
+    }
+}
+
+impl Eq for Path {}
+
+impl PartialOrd for Path {
+    fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
+        Some(self.cmp(other))
+    }
+}
+
+impl Ord for Path {
+    fn cmp(&self, other: &Path) -> Ordering {
+        self.repr.cmp(&other.repr)
+    }
+}
+
+impl FromStr for Path {
+    type Err = ParsePathError;
+    fn from_str(s: &str) -> Result<Path, ParsePathError> {
+        match Path::new_opt(s) {
+            Some(p) => Ok(p),
+            None => Err(ParsePathError),
+        }
+    }
+}
+
+/// Value indicating that a path could not be parsed from a string.
+#[derive(Debug, Clone, PartialEq, Copy)]
+pub struct ParsePathError;
+
+impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
+    #[cfg(not(test))]
+    #[inline]
+    fn hash(&self, state: &mut S) {
+        self.repr.hash(state)
+    }
+
+    #[cfg(test)]
+    #[inline]
+    fn hash(&self, _: &mut S) {
+        // No-op because the `hash` implementation will be wrong.
+    }
+}
+
+impl BytesContainer for Path {
+    #[inline]
+    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
+        self.as_vec()
+    }
+    #[inline]
+    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
+        self.as_str()
+    }
+    #[inline]
+    fn is_str(_: Option<&Path>) -> bool { true }
+}
+
+impl GenericPathUnsafe for Path {
+    /// See `GenericPathUnsafe::from_vec_unchecked`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if not valid UTF-8.
+    #[inline]
+    unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
+        let (prefix, path) = Path::normalize_(path.container_as_str().unwrap());
+        assert!(!path.is_empty());
+        let mut ret = Path{ repr: path, prefix: prefix, sepidx: None };
+        ret.update_sepidx();
+        ret
+    }
+
+    /// See `GenericPathUnsafe::set_filename_unchecked`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if not valid UTF-8.
+    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
+        let filename = filename.container_as_str().unwrap();
+        match self.sepidx_or_prefix_len() {
+            None if ".." == self.repr => {
+                let mut s = String::with_capacity(3 + filename.len());
+                s.push_str("..");
+                s.push(SEP);
+                s.push_str(filename);
+                self.update_normalized(&s[]);
+            }
+            None => {
+                self.update_normalized(filename);
+            }
+            Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => {
+                let mut s = String::with_capacity(end + 1 + filename.len());
+                s.push_str(&self.repr[..end]);
+                s.push(SEP);
+                s.push_str(filename);
+                self.update_normalized(&s[]);
+            }
+            Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => {
+                let mut s = String::with_capacity(idxb + filename.len());
+                s.push_str(&self.repr[..idxb]);
+                s.push_str(filename);
+                self.update_normalized(&s[]);
+            }
+            Some((idxb,_,_)) => {
+                let mut s = String::with_capacity(idxb + 1 + filename.len());
+                s.push_str(&self.repr[..idxb]);
+                s.push(SEP);
+                s.push_str(filename);
+                self.update_normalized(&s[]);
+            }
+        }
+    }
+
+    /// See `GenericPathUnsafe::push_unchecked`.
+    ///
+    /// Concatenating two Windows Paths is rather complicated.
+    /// For the most part, it will behave as expected, except in the case of
+    /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no
+    /// concept of per-volume cwds like Windows does, we can't behave exactly
+    /// like Windows will. Instead, if the receiver is an absolute path on
+    /// the same volume as the new path, it will be treated as the cwd that
+    /// the new path is relative to. Otherwise, the new path will be treated
+    /// as if it were absolute and will replace the receiver outright.
+    unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
+        let path = path.container_as_str().unwrap();
+        fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool {
+            // assume prefix is Some(DiskPrefix)
+            let rest = &path[prefix_len(prefix)..];
+            !rest.is_empty() && rest.as_bytes()[0].is_ascii() && is_sep(rest.as_bytes()[0] as char)
+        }
+        fn shares_volume(me: &Path, path: &str) -> bool {
+            // path is assumed to have a prefix of Some(DiskPrefix)
+            let repr = &me.repr[];
+            match me.prefix {
+                Some(DiskPrefix) => {
+                    repr.as_bytes()[0] == path.as_bytes()[0].to_ascii_uppercase()
+                }
+                Some(VerbatimDiskPrefix) => {
+                    repr.as_bytes()[4] == path.as_bytes()[0].to_ascii_uppercase()
+                }
+                _ => false
+            }
+        }
+        fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
+            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>) {
+            let newpath = Path::normalize__(path, prefix);
+            me.repr = match newpath {
+                Some(p) => p,
+                None => String::from_str(path)
+            };
+            me.prefix = prefix;
+            me.update_sepidx();
+        }
+        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 is_verbatim(me) { Path::normalize__(path, None) }
+                        else { None };
+            let pathlen = path_.as_ref().map_or(path.len(), |p| p.len());
+            let mut s = String::with_capacity(me.repr.len() + 1 + pathlen);
+            s.push_str(&me.repr[]);
+            let plen = me.prefix_len();
+            // if me is "C:" we don't want to add a path separator
+            match me.prefix {
+                Some(DiskPrefix) if me.repr.len() == plen => (),
+                _ if !(me.repr.len() > plen && me.repr.as_bytes()[me.repr.len()-1] == SEP_BYTE) => {
+                    s.push(SEP);
+                }
+                _ => ()
+            }
+            match path_ {
+                None => s.push_str(path),
+                Some(p) => s.push_str(&p[]),
+            };
+            me.update_normalized(&s[])
+        }
+
+        if !path.is_empty() {
+            let prefix = parse_prefix(path);
+            match prefix {
+                Some(DiskPrefix) if !is_vol_abs(path, prefix) && shares_volume(self, path) => {
+                    // cwd-relative path, self is on the same volume
+                    append_path(self, &path[prefix_len(prefix)..]);
+                }
+                Some(_) => {
+                    // absolute path, or cwd-relative and self is not same volume
+                    replace_path(self, path, prefix);
+                }
+                None if !path.is_empty() && is_sep_(self.prefix, path.as_bytes()[0]) => {
+                    // volume-relative path
+                    if self.prefix.is_some() {
+                        // truncate self down to the prefix, then append
+                        let n = self.prefix_len();
+                        self.repr.truncate(n);
+                        append_path(self, path);
+                    } else {
+                        // we have no prefix, so nothing to be relative to
+                        replace_path(self, path, prefix);
+                    }
+                }
+                None => {
+                    // relative path
+                    append_path(self, path);
+                }
+            }
+        }
+    }
+}
+
+impl GenericPath for Path {
+    #[inline]
+    fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
+        match path.container_as_str() {
+            None => None,
+            Some(ref s) => {
+                if contains_nul(s) {
+                    None
+                } else {
+                    Some(unsafe { GenericPathUnsafe::new_unchecked(*s) })
+                }
+            }
+        }
+    }
+
+    /// See `GenericPath::as_str` for info.
+    /// Always returns a `Some` value.
+    #[inline]
+    fn as_str<'a>(&'a self) -> Option<&'a str> {
+        Some(&self.repr[])
+    }
+
+    #[inline]
+    fn as_vec<'a>(&'a self) -> &'a [u8] {
+        self.repr.as_bytes()
+    }
+
+    #[inline]
+    fn into_vec(self) -> Vec<u8> {
+        self.repr.into_bytes()
+    }
+
+    #[inline]
+    fn dirname<'a>(&'a self) -> &'a [u8] {
+        self.dirname_str().unwrap().as_bytes()
+    }
+
+    /// See `GenericPath::dirname_str` for info.
+    /// Always returns a `Some` value.
+    fn dirname_str<'a>(&'a self) -> Option<&'a str> {
+        Some(match self.sepidx_or_prefix_len() {
+            None if ".." == self.repr => &self.repr[],
+            None => ".",
+            Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => {
+                &self.repr[]
+            }
+            Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => {
+                &self.repr[]
+            }
+            Some((0,idxa,_)) => &self.repr[..idxa],
+            Some((idxb,idxa,_)) => {
+                match self.prefix {
+                    Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => {
+                        &self.repr[..idxa]
+                    }
+                    _ => &self.repr[..idxb]
+                }
+            }
+        })
+    }
+
+    #[inline]
+    fn filename<'a>(&'a self) -> Option<&'a [u8]> {
+        self.filename_str().map(|x| x.as_bytes())
+    }
+
+    /// See `GenericPath::filename_str` for info.
+    /// Always returns a `Some` value if `filename` returns a `Some` value.
+    fn filename_str<'a>(&'a self) -> Option<&'a str> {
+        let repr = &self.repr[];
+        match self.sepidx_or_prefix_len() {
+            None if "." == repr || ".." == repr => None,
+            None => Some(repr),
+            Some((_,idxa,end)) if &repr[idxa..end] == ".." => None,
+            Some((_,idxa,end)) if idxa == end => None,
+            Some((_,idxa,end)) => Some(&repr[idxa..end])
+        }
+    }
+
+    /// See `GenericPath::filestem_str` for info.
+    /// Always returns a `Some` value if `filestem` returns a `Some` value.
+    #[inline]
+    fn filestem_str<'a>(&'a self) -> Option<&'a str> {
+        // filestem() returns a byte vector that's guaranteed valid UTF-8
+        self.filestem().map(|t| unsafe { mem::transmute(t) })
+    }
+
+    #[inline]
+    fn extension_str<'a>(&'a self) -> Option<&'a str> {
+        // extension() returns a byte vector that's guaranteed valid UTF-8
+        self.extension().map(|t| unsafe { mem::transmute(t) })
+    }
+
+    fn dir_path(&self) -> Path {
+        unsafe { GenericPathUnsafe::new_unchecked(self.dirname_str().unwrap()) }
+    }
+
+    #[inline]
+    fn pop(&mut self) -> bool {
+        match self.sepidx_or_prefix_len() {
+            None if "." == self.repr => false,
+            None => {
+                self.repr = String::from_str(".");
+                self.sepidx = None;
+                true
+            }
+            Some((idxb,idxa,end)) if idxb == idxa && idxb == end => false,
+            Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => false,
+            Some((idxb,idxa,_)) => {
+                let trunc = match self.prefix {
+                    Some(DiskPrefix) | Some(VerbatimDiskPrefix) | None => {
+                        let plen = self.prefix_len();
+                        if idxb == plen { idxa } else { idxb }
+                    }
+                    _ => idxb
+                };
+                self.repr.truncate(trunc);
+                self.update_sepidx();
+                true
+            }
+        }
+    }
+
+    fn root_path(&self) -> Option<Path> {
+        if self.prefix.is_some() {
+            Some(Path::new(match self.prefix {
+                Some(DiskPrefix) if self.is_absolute() => {
+                    &self.repr[..self.prefix_len()+1]
+                }
+                Some(VerbatimDiskPrefix) => {
+                    &self.repr[..self.prefix_len()+1]
+                }
+                _ => &self.repr[..self.prefix_len()]
+            }))
+        } else if is_vol_relative(self) {
+            Some(Path::new(&self.repr[..1]))
+        } else {
+            None
+        }
+    }
+
+    /// See `GenericPath::is_absolute` for info.
+    ///
+    /// A Windows Path is considered absolute only if it has a non-volume prefix,
+    /// or if it has a volume prefix and the path starts with '\'.
+    /// A path of `\foo` is not considered absolute because it's actually
+    /// relative to the "current volume". A separate method `Path::is_vol_relative`
+    /// is provided to indicate this case. Similarly a path of `C:foo` is not
+    /// considered absolute because it's relative to the cwd on volume C:. A
+    /// separate method `Path::is_cwd_relative` is provided to indicate this case.
+    #[inline]
+    fn is_absolute(&self) -> bool {
+        match self.prefix {
+            Some(DiskPrefix) => {
+                let rest = &self.repr[self.prefix_len()..];
+                rest.len() > 0 && rest.as_bytes()[0] == SEP_BYTE
+            }
+            Some(_) => true,
+            None => false
+        }
+    }
+
+    #[inline]
+    fn is_relative(&self) -> bool {
+        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() ||
+                  is_vol_relative(self) != is_vol_relative(other) {
+            false
+        } else {
+            let mut ita = self.str_components().map(|x|x.unwrap());
+            let mut itb = other.str_components().map(|x|x.unwrap());
+            if "." == self.repr {
+                return itb.next() != Some("..");
+            }
+            loop {
+                match (ita.next(), itb.next()) {
+                    (None, _) => break,
+                    (Some(a), Some(b)) if a == b => { continue },
+                    (Some(a), _) if a == ".." => {
+                        // if ita contains only .. components, it's an ancestor
+                        return ita.all(|x| x == "..");
+                    }
+                    _ => return false
+                }
+            }
+            true
+        }
+    }
+
+    fn path_relative_from(&self, base: &Path) -> Option<Path> {
+        fn comp_requires_verbatim(s: &str) -> bool {
+            s == "." || s == ".." || s.contains_char(SEP2)
+        }
+
+        if !self.equiv_prefix(base) {
+            // prefixes differ
+            if self.is_absolute() {
+                Some(self.clone())
+            } else if self.prefix == Some(DiskPrefix) && base.prefix == Some(DiskPrefix) {
+                // both drives, drive letters must differ or they'd be equiv
+                Some(self.clone())
+            } else {
+                None
+            }
+        } else if self.is_absolute() != base.is_absolute() {
+            if self.is_absolute() {
+                Some(self.clone())
+            } else {
+                None
+            }
+        } else if is_vol_relative(self) != is_vol_relative(base) {
+            if is_vol_relative(self) {
+                Some(self.clone())
+            } else {
+                None
+            }
+        } else {
+            let mut ita = self.str_components().map(|x|x.unwrap());
+            let mut itb = base.str_components().map(|x|x.unwrap());
+            let mut comps = vec![];
+
+            let a_verb = is_verbatim(self);
+            let b_verb = is_verbatim(base);
+            loop {
+                match (ita.next(), itb.next()) {
+                    (None, None) => break,
+                    (Some(a), None) if a_verb && comp_requires_verbatim(a) => {
+                        return Some(self.clone())
+                    }
+                    (Some(a), None) => {
+                        comps.push(a);
+                        if !a_verb {
+                            comps.extend(ita.by_ref());
+                            break;
+                        }
+                    }
+                    (None, _) => comps.push(".."),
+                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
+                    (Some(a), Some(b)) if !b_verb && b == "." => {
+                        if a_verb && comp_requires_verbatim(a) {
+                            return Some(self.clone())
+                        } else { comps.push(a) }
+                    }
+                    (Some(_), Some(b)) if !b_verb && b == ".." => return None,
+                    (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => {
+                        return Some(self.clone())
+                    }
+                    (Some(a), Some(_)) => {
+                        comps.push("..");
+                        for _ in itb.by_ref() {
+                            comps.push("..");
+                        }
+                        comps.push(a);
+                        if !a_verb {
+                            comps.extend(ita.by_ref());
+                            break;
+                        }
+                    }
+                }
+            }
+            Some(Path::new(comps.connect("\\")))
+        }
+    }
+
+    fn ends_with_path(&self, child: &Path) -> bool {
+        if !child.is_relative() { return false; }
+        let mut selfit = self.str_components().rev();
+        let mut childit = child.str_components().rev();
+        loop {
+            match (selfit.next(), childit.next()) {
+                (Some(a), Some(b)) => if a != b { return false; },
+                (Some(_), None) => break,
+                (None, Some(_)) => return false,
+                (None, None) => break
+            }
+        }
+        true
+    }
+}
+
+impl Path {
+    /// Returns a new `Path` from a `BytesContainer`.
+    ///
+    /// # Panics
+    ///
+    /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// println!("{}", Path::new(r"C:\some\path").display());
+    /// ```
+    #[inline]
+    pub fn new<T: BytesContainer>(path: T) -> Path {
+        GenericPath::new(path)
+    }
+
+    /// Returns a new `Some(Path)` from a `BytesContainer`.
+    ///
+    /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8.
+    ///
+    /// # Example
+    ///
+    /// ```
+    /// let path = Path::new_opt(r"C:\some\path");
+    ///
+    /// match path {
+    ///     Some(path) => println!("{}", path.display()),
+    ///     None       => println!("There was a problem with your path."),
+    /// }
+    /// ```
+    #[inline]
+    pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
+        GenericPath::new_opt(path)
+    }
+
+    /// Returns an iterator that yields each component of the path in turn as a Option<&str>.
+    /// Every component is guaranteed to be Some.
+    /// Does not yield the path prefix (including server/share components in UNC paths).
+    /// Does not distinguish between volume-relative and relative paths, e.g.
+    /// \a\b\c and a\b\c.
+    /// Does not distinguish between absolute and cwd-relative paths, e.g.
+    /// C:\foo and C:foo.
+    pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
+        let repr = &self.repr[];
+        let s = match self.prefix {
+            Some(_) => {
+                let plen = self.prefix_len();
+                if repr.len() > plen && repr.as_bytes()[plen] == SEP_BYTE {
+                    &repr[plen+1..]
+                } else { &repr[plen..] }
+            }
+            None if repr.as_bytes()[0] == SEP_BYTE => &repr[1..],
+            None => repr
+        };
+        let some: fn(&'a str) -> Option<&'a str> = Some; // coerce to fn ptr
+        let ret = s.split_terminator(SEP).map(some);
+        ret
+    }
+
+    /// Returns an iterator that yields each component of the path in turn as a &[u8].
+    /// See str_components() for details.
+    pub fn components<'a>(&'a self) -> Components<'a> {
+        fn convert<'a>(x: Option<&'a str>) -> &'a [u8] {
+            #![inline]
+            x.unwrap().as_bytes()
+        }
+        let convert: for<'b> fn(Option<&'b str>) -> &'b [u8] = convert; // coerce to fn ptr
+        self.str_components().map(convert)
+    }
+
+    fn equiv_prefix(&self, other: &Path) -> bool {
+        let s_repr = &self.repr[];
+        let o_repr = &other.repr[];
+        match (self.prefix, other.prefix) {
+            (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
+                self.is_absolute() &&
+                    s_repr.as_bytes()[0].to_ascii_lowercase() ==
+                        o_repr.as_bytes()[4].to_ascii_lowercase()
+            }
+            (Some(VerbatimDiskPrefix), Some(DiskPrefix)) => {
+                other.is_absolute() &&
+                    s_repr.as_bytes()[4].to_ascii_lowercase() ==
+                        o_repr.as_bytes()[0].to_ascii_lowercase()
+            }
+            (Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => {
+                s_repr.as_bytes()[4].to_ascii_lowercase() ==
+                    o_repr.as_bytes()[4].to_ascii_lowercase()
+            }
+            (Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => {
+                &s_repr[2..self.prefix_len()] == &o_repr[8..other.prefix_len()]
+            }
+            (Some(VerbatimUNCPrefix(_,_)), Some(UNCPrefix(_,_))) => {
+                &s_repr[8..self.prefix_len()] == &o_repr[2..other.prefix_len()]
+            }
+            (None, None) => true,
+            (a, b) if a == b => {
+                &s_repr[..self.prefix_len()] == &o_repr[..other.prefix_len()]
+            }
+            _ => false
+        }
+    }
+
+    fn normalize_(s: &str) -> (Option<PathPrefix>, String) {
+        // make borrowck happy
+        let (prefix, val) = {
+            let prefix = parse_prefix(s);
+            let path = Path::normalize__(s, prefix);
+            (prefix, path)
+        };
+        (prefix, match val {
+            None => s.to_string(),
+            Some(val) => val
+        })
+    }
+
+    fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
+        if prefix_is_verbatim(prefix) {
+            // don't do any normalization
+            match prefix {
+                Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => {
+                    // the server component has no trailing '\'
+                    let mut s = String::from_str(s);
+                    s.push(SEP);
+                    Some(s)
+                }
+                _ => None
+            }
+        } else {
+            let (is_abs, comps) = normalize_helper(s, prefix);
+            let mut comps = comps;
+            match (comps.is_some(),prefix) {
+                (false, Some(DiskPrefix)) => {
+                    if s.as_bytes()[0] >= b'a' && s.as_bytes()[0] <= b'z' {
+                        comps = Some(vec![]);
+                    }
+                }
+                (false, Some(VerbatimDiskPrefix)) => {
+                    if s.as_bytes()[4] >= b'a' && s.as_bytes()[0] <= b'z' {
+                        comps = Some(vec![]);
+                    }
+                }
+                _ => ()
+            }
+            match comps {
+                None => None,
+                Some(comps) => {
+                    if prefix.is_some() && comps.is_empty() {
+                        match prefix.unwrap() {
+                            DiskPrefix => {
+                                let len = prefix_len(prefix) + is_abs as uint;
+                                let mut s = String::from_str(&s[..len]);
+                                unsafe {
+                                    let v = s.as_mut_vec();
+                                    v[0] = (*v)[0].to_ascii_uppercase();
+                                }
+                                if is_abs {
+                                    // normalize C:/ to C:\
+                                    unsafe {
+                                        s.as_mut_vec()[2] = SEP_BYTE;
+                                    }
+                                }
+                                Some(s)
+                            }
+                            VerbatimDiskPrefix => {
+                                let len = prefix_len(prefix) + is_abs as uint;
+                                let mut s = String::from_str(&s[..len]);
+                                unsafe {
+                                    let v = s.as_mut_vec();
+                                    v[4] = (*v)[4].to_ascii_uppercase();
+                                }
+                                Some(s)
+                            }
+                            _ => {
+                                let plen = prefix_len(prefix);
+                                if s.len() > plen {
+                                    Some(String::from_str(&s[..plen]))
+                                } else { None }
+                            }
+                        }
+                    } else if is_abs && comps.is_empty() {
+                        Some(repeat(SEP).take(1).collect())
+                    } else {
+                        let prefix_ = &s[..prefix_len(prefix)];
+                        let n = prefix_.len() +
+                                if is_abs { comps.len() } else { comps.len() - 1} +
+                                comps.iter().map(|v| v.len()).sum();
+                        let mut s = String::with_capacity(n);
+                        match prefix {
+                            Some(DiskPrefix) => {
+                                s.push(prefix_.as_bytes()[0].to_ascii_uppercase() as char);
+                                s.push(':');
+                            }
+                            Some(VerbatimDiskPrefix) => {
+                                s.push_str(&prefix_[..4]);
+                                s.push(prefix_.as_bytes()[4].to_ascii_uppercase() as char);
+                                s.push_str(&prefix_[5..]);
+                            }
+                            Some(UNCPrefix(a,b)) => {
+                                s.push_str("\\\\");
+                                s.push_str(&prefix_[2..a+2]);
+                                s.push(SEP);
+                                s.push_str(&prefix_[3+a..3+a+b]);
+                            }
+                            Some(_) => s.push_str(prefix_),
+                            None => ()
+                        }
+                        let mut it = comps.into_iter();
+                        if !is_abs {
+                            match it.next() {
+                                None => (),
+                                Some(comp) => s.push_str(comp)
+                            }
+                        }
+                        for comp in it {
+                            s.push(SEP);
+                            s.push_str(comp);
+                        }
+                        Some(s)
+                    }
+                }
+            }
+        }
+    }
+
+    fn update_sepidx(&mut self) {
+        let s = if self.has_nonsemantic_trailing_slash() {
+                    &self.repr[..self.repr.len()-1]
+                } else { &self.repr[] };
+        let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) {
+            is_sep
+        } else {
+            is_sep_verbatim
+        };
+        let idx = s.rfind(sep_test);
+        let prefixlen = self.prefix_len();
+        self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
+    }
+
+    fn prefix_len(&self) -> uint {
+        prefix_len(self.prefix)
+    }
+
+    // Returns a tuple (before, after, end) where before is the index of the separator
+    // and after is the index just after the separator.
+    // end is the length of the string, normally, or the index of the final character if it is
+    // a non-semantic trailing separator in a verbatim string.
+    // If the prefix is considered the separator, before and after are the same.
+    fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> {
+        match self.sepidx {
+            None => match self.prefix_len() { 0 => None, x => Some((x,x,self.repr.len())) },
+            Some(x) => {
+                if self.has_nonsemantic_trailing_slash() {
+                    Some((x,x+1,self.repr.len()-1))
+                } else { Some((x,x+1,self.repr.len())) }
+            }
+        }
+    }
+
+    fn has_nonsemantic_trailing_slash(&self) -> bool {
+        is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
+            self.repr.as_bytes()[self.repr.len()-1] == SEP_BYTE
+    }
+
+    fn update_normalized(&mut self, s: &str) {
+        let (prefix, path) = Path::normalize_(s);
+        self.repr = path;
+        self.prefix = prefix;
+        self.update_sepidx();
+    }
+}
+
+/// 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.as_bytes()[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)
+}
+
+/// Returns the non-verbatim equivalent of the input path, if possible.
+/// If the input path is a device namespace path, None is returned.
+/// If the input path is not verbatim, it is returned as-is.
+/// If the input path is verbatim, but the same path can be expressed as
+/// non-verbatim, the non-verbatim version is returned.
+/// Otherwise, None is returned.
+pub fn make_non_verbatim(path: &Path) -> Option<Path> {
+    let repr = &path.repr[];
+    let new_path = match path.prefix {
+        Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None,
+        Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()),
+        Some(VerbatimDiskPrefix) => {
+            // \\?\D:\
+            Path::new(&repr[4..])
+        }
+        Some(VerbatimUNCPrefix(_,_)) => {
+            // \\?\UNC\server\share
+            Path::new(format!(r"\{}", &repr[7..]))
+        }
+    };
+    if new_path.prefix.is_none() {
+        // \\?\UNC\server is a VerbatimUNCPrefix
+        // but \\server is nothing
+        return None;
+    }
+    // now ensure normalization didn't change anything
+    if &repr[path.prefix_len()..] == &new_path.repr[new_path.prefix_len()..] {
+        Some(new_path)
+    } else {
+        None
+    }
+}
+
+/// The standard path separator character
+pub const SEP: char = '\\';
+/// The standard path separator byte
+pub const SEP_BYTE: u8 = SEP as u8;
+
+/// The alternative path separator character
+pub const SEP2: char = '/';
+/// The alternative path separator character
+pub const SEP2_BYTE: u8 = SEP2 as u8;
+
+/// 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_sep_byte(u: &u8) -> bool {
+    *u == SEP_BYTE || *u == SEP2_BYTE
+}
+
+/// 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 == SEP_BYTE
+}
+
+/// Prefix types for Path
+#[derive(Copy, PartialEq, Clone, Debug)]
+pub enum PathPrefix {
+    /// Prefix `\\?\`, uint is the length of the following component
+    VerbatimPrefix(uint),
+    /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components
+    VerbatimUNCPrefix(uint, uint),
+    /// Prefix `\\?\C:\` (for any alphabetic character)
+    VerbatimDiskPrefix,
+    /// Prefix `\\.\`, uint is the length of the following component
+    DeviceNSPrefix(uint),
+    /// UNC prefix `\\server\share`, uints are the lengths of the server/share
+    UNCPrefix(uint, uint),
+    /// Prefix `C:` for any alphabetic character
+    DiskPrefix
+}
+
+fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
+    if path.starts_with("\\\\") {
+        // \\
+        path = &path[2..];
+        if path.starts_with("?\\") {
+            // \\?\
+            path = &path[2..];
+            if path.starts_with("UNC\\") {
+                // \\?\UNC\server\share
+                path = &path[4..];
+                let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
+                    Some(x) => x,
+                    None => (path.len(), 0)
+                };
+                return Some(VerbatimUNCPrefix(idx_a, idx_b));
+            } else {
+                // \\?\path
+                let idx = path.find('\\');
+                if idx == Some(2) && path.as_bytes()[1] == b':' {
+                    let c = path.as_bytes()[0];
+                    if c.is_ascii() && (c as char).is_alphabetic() {
+                        // \\?\C:\ path
+                        return Some(VerbatimDiskPrefix);
+                    }
+                }
+                let idx = idx.unwrap_or(path.len());
+                return Some(VerbatimPrefix(idx));
+            }
+        } else if path.starts_with(".\\") {
+            // \\.\path
+            path = &path[2..];
+            let idx = path.find('\\').unwrap_or(path.len());
+            return Some(DeviceNSPrefix(idx));
+        }
+        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));
+            }
+            _ => ()
+        }
+    } else if path.len() > 1 && path.as_bytes()[1] == b':' {
+        // C:
+        let c = path.as_bytes()[0];
+        if c.is_ascii() && (c as char).is_alphabetic() {
+            return Some(DiskPrefix);
+        }
+    }
+    return None;
+
+    fn parse_two_comps(mut path: &str, f: fn(char) -> bool) -> Option<(uint, uint)> {
+        let idx_a = match path.find(f) {
+            None => return None,
+            Some(x) => x
+        };
+        path = &path[idx_a+1..];
+        let idx_b = path.find(f).unwrap_or(path.len());
+        Some((idx_a, idx_b))
+    }
+}
+
+// None result means the string didn't need normalizing
+fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
+    let f: fn(char) -> bool = 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[prefix_len(prefix)..];
+    let s_ = if is_abs { &s_[1..] } else { s_ };
+
+    if is_abs && s_.is_empty() {
+        return (is_abs, match prefix {
+            Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
+                                        else { Some(vec![]) }),
+            Some(_) => Some(vec![]), // need to trim the trailing separator
+        });
+    }
+    let mut comps: Vec<&'a str> = vec![];
+    let mut n_up = 0u;
+    let mut changed = false;
+    for comp in s_.split(f) {
+        if comp.is_empty() { changed = true }
+        else if comp == "." { changed = true }
+        else if comp == ".." {
+            let has_abs_prefix = match prefix {
+                Some(DiskPrefix) => false,
+                Some(_) => true,
+                None => false
+            };
+            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().unwrap(); changed = true }
+        } else { comps.push(comp) }
+    }
+    if !changed && !prefix_is_verbatim(prefix) {
+        changed = s.find(is_sep).is_some();
+    }
+    if changed {
+        if comps.is_empty() && !is_abs && prefix.is_none() {
+            if s == "." {
+                return (is_abs, None);
+            }
+            comps.push(".");
+        }
+        (is_abs, Some(comps))
+    } else {
+        (is_abs, None)
+    }
+}
+
+fn prefix_is_verbatim(p: Option<PathPrefix>) -> bool {
+    match p {
+        Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true,
+        Some(DeviceNSPrefix(_)) => true, // not really sure, but I think so
+        _ => false
+    }
+}
+
+fn prefix_len(p: Option<PathPrefix>) -> uint {
+    match p {
+        None => 0,
+        Some(VerbatimPrefix(x)) => 4 + x,
+        Some(VerbatimUNCPrefix(x,y)) => 8 + x + 1 + y,
+        Some(VerbatimDiskPrefix) => 6,
+        Some(UNCPrefix(x,y)) => 2 + x + 1 + y,
+        Some(DeviceNSPrefix(x)) => 4 + x,
+        Some(DiskPrefix) => 2
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::PathPrefix::*;
+    use super::parse_prefix;
+    use super::*;
+
+    use clone::Clone;
+    use iter::IteratorExt;
+    use option::Option::{self, Some, None};
+    use old_path::GenericPath;
+    use slice::{AsSlice, SliceExt};
+    use str::Str;
+    use string::ToString;
+    use vec::Vec;
+
+    macro_rules! t {
+        (s: $path:expr, $exp:expr) => (
+            {
+                let path = $path;
+                assert_eq!(path.as_str(), Some($exp));
+            }
+        );
+        (v: $path:expr, $exp:expr) => (
+            {
+                let path = $path;
+                assert_eq!(path.as_vec(), $exp);
+            }
+        )
+    }
+
+    #[test]
+    fn test_parse_prefix() {
+        macro_rules! t {
+            ($path:expr, $exp:expr) => (
+                {
+                    let path = $path;
+                    let exp = $exp;
+                    let res = parse_prefix(path);
+                    assert_eq!(res, exp);
+                }
+            )
+        }
+
+        t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
+        t!("\\\\", None);
+        t!("\\\\SERVER", None);
+        t!("\\\\SERVER\\", None);
+        t!("\\\\SERVER\\\\", None);
+        t!("\\\\SERVER\\\\foo", None);
+        t!("\\\\SERVER\\share", Some(UNCPrefix(6,5)));
+        t!("\\\\SERVER/share/foo", Some(UNCPrefix(6,5)));
+        t!("\\\\SERVER\\share/foo", Some(UNCPrefix(6,5)));
+        t!("//SERVER/share/foo", None);
+        t!("\\\\\\a\\b\\c", None);
+        t!("\\\\?\\a\\b\\c", Some(VerbatimPrefix(1)));
+        t!("\\\\?\\a/b/c", Some(VerbatimPrefix(5)));
+        t!("//?/a/b/c", None);
+        t!("\\\\.\\a\\b", Some(DeviceNSPrefix(1)));
+        t!("\\\\.\\a/b", Some(DeviceNSPrefix(3)));
+        t!("//./a/b", None);
+        t!("\\\\?\\UNC\\server\\share\\foo", Some(VerbatimUNCPrefix(6,5)));
+        t!("\\\\?\\UNC\\\\share\\foo", Some(VerbatimUNCPrefix(0,5)));
+        t!("\\\\?\\UNC\\", Some(VerbatimUNCPrefix(0,0)));
+        t!("\\\\?\\UNC\\server/share/foo", Some(VerbatimUNCPrefix(16,0)));
+        t!("\\\\?\\UNC\\server", Some(VerbatimUNCPrefix(6,0)));
+        t!("\\\\?\\UNC\\server\\", Some(VerbatimUNCPrefix(6,0)));
+        t!("\\\\?\\UNC/server/share", Some(VerbatimPrefix(16)));
+        t!("\\\\?\\UNC", Some(VerbatimPrefix(3)));
+        t!("\\\\?\\C:\\a\\b.txt", Some(VerbatimDiskPrefix));
+        t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
+        t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
+        t!("\\\\?\\C:a.txt", Some(VerbatimPrefix(7)));
+        t!("\\\\?\\C:a\\b.txt", Some(VerbatimPrefix(3)));
+        t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
+        t!("C:\\foo", Some(DiskPrefix));
+        t!("z:/foo", Some(DiskPrefix));
+        t!("d:", Some(DiskPrefix));
+        t!("ab:", None);
+        t!("ü:\\foo", None);
+        t!("3:\\foo", None);
+        t!(" :\\foo", None);
+        t!("::\\foo", None);
+        t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
+        t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
+        t!("\\\\?\\ab:\\", Some(VerbatimPrefix(3)));
+        t!("\\\\?\\C:\\a", Some(VerbatimDiskPrefix));
+        t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
+        t!("\\\\?\\C:\\a/b", Some(VerbatimDiskPrefix));
+    }
+
+    #[test]
+    fn test_paths() {
+        let empty: &[u8] = &[];
+        t!(v: Path::new(empty), b".");
+        t!(v: Path::new(b"\\"), b"\\");
+        t!(v: Path::new(b"a\\b\\c"), b"a\\b\\c");
+
+        t!(s: Path::new(""), ".");
+        t!(s: Path::new("\\"), "\\");
+        t!(s: Path::new("hi"), "hi");
+        t!(s: Path::new("hi\\"), "hi");
+        t!(s: Path::new("\\lib"), "\\lib");
+        t!(s: Path::new("\\lib\\"), "\\lib");
+        t!(s: Path::new("hi\\there"), "hi\\there");
+        t!(s: Path::new("hi\\there.txt"), "hi\\there.txt");
+        t!(s: Path::new("/"), "\\");
+        t!(s: Path::new("hi/"), "hi");
+        t!(s: Path::new("/lib"), "\\lib");
+        t!(s: Path::new("/lib/"), "\\lib");
+        t!(s: Path::new("hi/there"), "hi\\there");
+
+        t!(s: Path::new("hi\\there\\"), "hi\\there");
+        t!(s: Path::new("hi\\..\\there"), "there");
+        t!(s: Path::new("hi/../there"), "there");
+        t!(s: Path::new("..\\hi\\there"), "..\\hi\\there");
+        t!(s: Path::new("\\..\\hi\\there"), "\\hi\\there");
+        t!(s: Path::new("/../hi/there"), "\\hi\\there");
+        t!(s: Path::new("foo\\.."), ".");
+        t!(s: Path::new("\\foo\\.."), "\\");
+        t!(s: Path::new("\\foo\\..\\.."), "\\");
+        t!(s: Path::new("\\foo\\..\\..\\bar"), "\\bar");
+        t!(s: Path::new("\\.\\hi\\.\\there\\."), "\\hi\\there");
+        t!(s: Path::new("\\.\\hi\\.\\there\\.\\.."), "\\hi");
+        t!(s: Path::new("foo\\..\\.."), "..");
+        t!(s: Path::new("foo\\..\\..\\.."), "..\\..");
+        t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar");
+
+        assert_eq!(Path::new(b"foo\\bar").into_vec(), b"foo\\bar");
+        assert_eq!(Path::new(b"\\foo\\..\\..\\bar").into_vec(), b"\\bar");
+
+        t!(s: Path::new("\\\\a"), "\\a");
+        t!(s: Path::new("\\\\a\\"), "\\a");
+        t!(s: Path::new("\\\\a\\b"), "\\\\a\\b");
+        t!(s: Path::new("\\\\a\\b\\"), "\\\\a\\b");
+        t!(s: Path::new("\\\\a\\b/"), "\\\\a\\b");
+        t!(s: Path::new("\\\\\\b"), "\\b");
+        t!(s: Path::new("\\\\a\\\\b"), "\\a\\b");
+        t!(s: Path::new("\\\\a\\b\\c"), "\\\\a\\b\\c");
+        t!(s: Path::new("\\\\server\\share/path"), "\\\\server\\share\\path");
+        t!(s: Path::new("\\\\server/share/path"), "\\\\server\\share\\path");
+        t!(s: Path::new("C:a\\b.txt"), "C:a\\b.txt");
+        t!(s: Path::new("C:a/b.txt"), "C:a\\b.txt");
+        t!(s: Path::new("z:\\a\\b.txt"), "Z:\\a\\b.txt");
+        t!(s: Path::new("z:/a/b.txt"), "Z:\\a\\b.txt");
+        t!(s: Path::new("ab:/a/b.txt"), "ab:\\a\\b.txt");
+        t!(s: Path::new("C:\\"), "C:\\");
+        t!(s: Path::new("C:"), "C:");
+        t!(s: Path::new("q:"), "Q:");
+        t!(s: Path::new("C:/"), "C:\\");
+        t!(s: Path::new("C:\\foo\\.."), "C:\\");
+        t!(s: Path::new("C:foo\\.."), "C:");
+        t!(s: Path::new("C:\\a\\"), "C:\\a");
+        t!(s: Path::new("C:\\a/"), "C:\\a");
+        t!(s: Path::new("C:\\a\\b\\"), "C:\\a\\b");
+        t!(s: Path::new("C:\\a\\b/"), "C:\\a\\b");
+        t!(s: Path::new("C:a\\"), "C:a");
+        t!(s: Path::new("C:a/"), "C:a");
+        t!(s: Path::new("C:a\\b\\"), "C:a\\b");
+        t!(s: Path::new("C:a\\b/"), "C:a\\b");
+        t!(s: Path::new("\\\\?\\z:\\a\\b.txt"), "\\\\?\\z:\\a\\b.txt");
+        t!(s: Path::new("\\\\?\\C:/a/b.txt"), "\\\\?\\C:/a/b.txt");
+        t!(s: Path::new("\\\\?\\C:\\a/b.txt"), "\\\\?\\C:\\a/b.txt");
+        t!(s: Path::new("\\\\?\\test\\a\\b.txt"), "\\\\?\\test\\a\\b.txt");
+        t!(s: Path::new("\\\\?\\foo\\bar\\"), "\\\\?\\foo\\bar\\");
+        t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
+        t!(s: Path::new("\\\\.\\"), "\\\\.\\");
+        t!(s: Path::new("\\\\?\\UNC\\server\\share\\foo"), "\\\\?\\UNC\\server\\share\\foo");
+        t!(s: Path::new("\\\\?\\UNC\\server/share"), "\\\\?\\UNC\\server/share\\");
+        t!(s: Path::new("\\\\?\\UNC\\server"), "\\\\?\\UNC\\server\\");
+        t!(s: Path::new("\\\\?\\UNC\\"), "\\\\?\\UNC\\\\");
+        t!(s: Path::new("\\\\?\\UNC"), "\\\\?\\UNC");
+
+        // I'm not sure whether \\.\foo/bar should normalize to \\.\foo\bar
+        // as information is sparse and this isn't really googleable.
+        // I'm going to err on the side of not normalizing it, as this skips the filesystem
+        t!(s: Path::new("\\\\.\\foo/bar"), "\\\\.\\foo/bar");
+        t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
+    }
+
+    #[test]
+    fn test_opt_paths() {
+        assert!(Path::new_opt(b"foo\\bar\0") == None);
+        assert!(Path::new_opt(b"foo\\bar\x80") == None);
+        t!(v: Path::new_opt(b"foo\\bar").unwrap(), b"foo\\bar");
+        assert!(Path::new_opt("foo\\bar\0") == None);
+        t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar");
+    }
+
+    #[test]
+    fn test_null_byte() {
+        use thread::Thread;
+        let result = Thread::scoped(move|| {
+            Path::new(b"foo/bar\0")
+        }).join();
+        assert!(result.is_err());
+
+        let result = Thread::scoped(move|| {
+            Path::new("test").set_filename(b"f\0o")
+        }).join();
+        assert!(result.is_err());
+
+        let result = Thread::scoped(move || {
+            Path::new("test").push(b"f\0o");
+        }).join();
+        assert!(result.is_err());
+    }
+
+    #[test]
+    #[should_fail]
+    fn test_not_utf8_panics() {
+        Path::new(b"hello\x80.txt");
+    }
+
+    #[test]
+    fn test_display_str() {
+        let path = Path::new("foo");
+        assert_eq!(path.display().to_string(), "foo");
+        let path = Path::new(b"\\");
+        assert_eq!(path.filename_display().to_string(), "");
+
+        let path = Path::new("foo");
+        let mo = path.display().as_cow();
+        assert_eq!(mo.as_slice(), "foo");
+        let path = Path::new(b"\\");
+        let mo = path.filename_display().as_cow();
+        assert_eq!(mo.as_slice(), "");
+    }
+
+    #[test]
+    fn test_display() {
+        macro_rules! t {
+            ($path:expr, $exp:expr, $expf:expr) => (
+                {
+                    let path = Path::new($path);
+                    let f = format!("{}", path.display());
+                    assert_eq!(f, $exp);
+                    let f = format!("{}", path.filename_display());
+                    assert_eq!(f, $expf);
+                }
+            )
+        }
+
+        t!("foo", "foo", "foo");
+        t!("foo\\bar", "foo\\bar", "bar");
+        t!("\\", "\\", "");
+    }
+
+    #[test]
+    fn test_components() {
+        macro_rules! t {
+            (s: $path:expr, $op:ident, $exp:expr) => (
+                {
+                    let path = $path;
+                    let path = Path::new(path);
+                    assert_eq!(path.$op(), Some($exp));
+                }
+            );
+            (s: $path:expr, $op:ident, $exp:expr, opt) => (
+                {
+                    let path = $path;
+                    let path = Path::new(path);
+                    let left = path.$op();
+                    assert_eq!(left, $exp);
+                }
+            );
+            (v: $path:expr, $op:ident, $exp:expr) => (
+                {
+                    let path = $path;
+                    let path = Path::new(path);
+                    assert_eq!(path.$op(), $exp);
+                }
+            )
+        }
+
+        t!(v: b"a\\b\\c", filename, Some(b"c"));
+        t!(s: "a\\b\\c", filename_str, "c");
+        t!(s: "\\a\\b\\c", filename_str, "c");
+        t!(s: "a", filename_str, "a");
+        t!(s: "\\a", filename_str, "a");
+        t!(s: ".", filename_str, None, opt);
+        t!(s: "\\", filename_str, None, opt);
+        t!(s: "..", filename_str, None, opt);
+        t!(s: "..\\..", filename_str, None, opt);
+        t!(s: "c:\\foo.txt", filename_str, "foo.txt");
+        t!(s: "C:\\", filename_str, None, opt);
+        t!(s: "C:", filename_str, None, opt);
+        t!(s: "\\\\server\\share\\foo.txt", filename_str, "foo.txt");
+        t!(s: "\\\\server\\share", filename_str, None, opt);
+        t!(s: "\\\\server", filename_str, "server");
+        t!(s: "\\\\?\\bar\\foo.txt", filename_str, "foo.txt");
+        t!(s: "\\\\?\\bar", filename_str, None, opt);
+        t!(s: "\\\\?\\", filename_str, None, opt);
+        t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", filename_str, "foo.txt");
+        t!(s: "\\\\?\\UNC\\server", filename_str, None, opt);
+        t!(s: "\\\\?\\UNC\\", filename_str, None, opt);
+        t!(s: "\\\\?\\C:\\foo.txt", filename_str, "foo.txt");
+        t!(s: "\\\\?\\C:\\", filename_str, None, opt);
+        t!(s: "\\\\?\\C:", filename_str, None, opt);
+        t!(s: "\\\\?\\foo/bar", filename_str, None, opt);
+        t!(s: "\\\\?\\C:/foo", filename_str, None, opt);
+        t!(s: "\\\\.\\foo\\bar", filename_str, "bar");
+        t!(s: "\\\\.\\foo", filename_str, None, opt);
+        t!(s: "\\\\.\\foo/bar", filename_str, None, opt);
+        t!(s: "\\\\.\\foo\\bar/baz", filename_str, "bar/baz");
+        t!(s: "\\\\.\\", filename_str, None, opt);
+        t!(s: "\\\\?\\a\\b\\", filename_str, "b");
+
+        t!(v: b"a\\b\\c", dirname, b"a\\b");
+        t!(s: "a\\b\\c", dirname_str, "a\\b");
+        t!(s: "\\a\\b\\c", dirname_str, "\\a\\b");
+        t!(s: "a", dirname_str, ".");
+        t!(s: "\\a", dirname_str, "\\");
+        t!(s: ".", dirname_str, ".");
+        t!(s: "\\", dirname_str, "\\");
+        t!(s: "..", dirname_str, "..");
+        t!(s: "..\\..", dirname_str, "..\\..");
+        t!(s: "c:\\foo.txt", dirname_str, "C:\\");
+        t!(s: "C:\\", dirname_str, "C:\\");
+        t!(s: "C:", dirname_str, "C:");
+        t!(s: "C:foo.txt", dirname_str, "C:");
+        t!(s: "\\\\server\\share\\foo.txt", dirname_str, "\\\\server\\share");
+        t!(s: "\\\\server\\share", dirname_str, "\\\\server\\share");
+        t!(s: "\\\\server", dirname_str, "\\");
+        t!(s: "\\\\?\\bar\\foo.txt", dirname_str, "\\\\?\\bar");
+        t!(s: "\\\\?\\bar", dirname_str, "\\\\?\\bar");
+        t!(s: "\\\\?\\", dirname_str, "\\\\?\\");
+        t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", dirname_str, "\\\\?\\UNC\\server\\share");
+        t!(s: "\\\\?\\UNC\\server", dirname_str, "\\\\?\\UNC\\server\\");
+        t!(s: "\\\\?\\UNC\\", dirname_str, "\\\\?\\UNC\\\\");
+        t!(s: "\\\\?\\C:\\foo.txt", dirname_str, "\\\\?\\C:\\");
+        t!(s: "\\\\?\\C:\\", dirname_str, "\\\\?\\C:\\");
+        t!(s: "\\\\?\\C:", dirname_str, "\\\\?\\C:");
+        t!(s: "\\\\?\\C:/foo/bar", dirname_str, "\\\\?\\C:/foo/bar");
+        t!(s: "\\\\?\\foo/bar", dirname_str, "\\\\?\\foo/bar");
+        t!(s: "\\\\.\\foo\\bar", dirname_str, "\\\\.\\foo");
+        t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo");
+        t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a");
+
+        t!(v: b"hi\\there.txt", filestem, Some(b"there"));
+        t!(s: "hi\\there.txt", filestem_str, "there");
+        t!(s: "hi\\there", filestem_str, "there");
+        t!(s: "there.txt", filestem_str, "there");
+        t!(s: "there", filestem_str, "there");
+        t!(s: ".", filestem_str, None, opt);
+        t!(s: "\\", filestem_str, None, opt);
+        t!(s: "foo\\.bar", filestem_str, ".bar");
+        t!(s: ".bar", filestem_str, ".bar");
+        t!(s: "..bar", filestem_str, ".");
+        t!(s: "hi\\there..txt", filestem_str, "there.");
+        t!(s: "..", filestem_str, None, opt);
+        t!(s: "..\\..", filestem_str, None, opt);
+        // filestem is based on filename, so we don't need the full set of prefix tests
+
+        t!(v: b"hi\\there.txt", extension, Some(b"txt"));
+        t!(v: b"hi\\there", extension, None);
+        t!(s: "hi\\there.txt", extension_str, Some("txt"), opt);
+        t!(s: "hi\\there", extension_str, None, opt);
+        t!(s: "there.txt", extension_str, Some("txt"), opt);
+        t!(s: "there", extension_str, None, opt);
+        t!(s: ".", extension_str, None, opt);
+        t!(s: "\\", extension_str, None, opt);
+        t!(s: "foo\\.bar", extension_str, None, opt);
+        t!(s: ".bar", extension_str, None, opt);
+        t!(s: "..bar", extension_str, Some("bar"), opt);
+        t!(s: "hi\\there..txt", extension_str, Some("txt"), opt);
+        t!(s: "..", extension_str, None, opt);
+        t!(s: "..\\..", extension_str, None, opt);
+        // extension is based on filename, so we don't need the full set of prefix tests
+    }
+
+    #[test]
+    fn test_push() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr) => (
+                {
+                    let path = $path;
+                    let join = $join;
+                    let mut p1 = Path::new(path);
+                    let p2 = p1.clone();
+                    p1.push(join);
+                    assert_eq!(p1, p2.join(join));
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "..");
+        t!(s: "\\a\\b\\c", "d");
+        t!(s: "a\\b", "c\\d");
+        t!(s: "a\\b", "\\c\\d");
+        // this is just a sanity-check test. push and join share an implementation,
+        // so there's no need for the full set of prefix 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!(prefix(&p), Some(VerbatimPrefix(2)));
+        p.push("foo");
+        assert_eq!(prefix(&p), Some(VerbatimDiskPrefix));
+        assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
+
+        // and another with verbatim non-normalized paths
+        let mut p = Path::new("\\\\?\\C:\\a\\");
+        p.push("foo");
+        assert_eq!(p.as_str(), Some("\\\\?\\C:\\a\\foo"));
+    }
+
+    #[test]
+    fn test_push_path() {
+        macro_rules! t {
+            (s: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    let push = Path::new($push);
+                    p.push(&push);
+                    assert_eq!(p.as_str(), Some($exp));
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "d", "a\\b\\c\\d");
+        t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
+        t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
+        t!(s: "a\\b", "\\c\\d", "\\c\\d");
+        t!(s: "a\\b", ".", "a\\b");
+        t!(s: "a\\b", "..\\c", "a\\c");
+        t!(s: "a\\b", "C:a.txt", "C:a.txt");
+        t!(s: "a\\b", "..\\..\\..\\c", "..\\c");
+        t!(s: "a\\b", "C:\\a.txt", "C:\\a.txt");
+        t!(s: "C:\\a", "C:\\b.txt", "C:\\b.txt");
+        t!(s: "C:\\a\\b\\c", "C:d", "C:\\a\\b\\c\\d");
+        t!(s: "C:a\\b\\c", "C:d", "C:a\\b\\c\\d");
+        t!(s: "C:a\\b", "..\\..\\..\\c", "C:..\\c");
+        t!(s: "C:\\a\\b", "..\\..\\..\\c", "C:\\c");
+        t!(s: "C:", r"a\b\c", r"C:a\b\c");
+        t!(s: "C:", r"..\a", r"C:..\a");
+        t!(s: "\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
+        t!(s: "\\\\server\\share\\foo", "..\\..\\bar", "\\\\server\\share\\bar");
+        t!(s: "\\\\server\\share\\foo", "C:baz", "C:baz");
+        t!(s: "\\\\?\\C:\\a\\b", "C:c\\d", "\\\\?\\C:\\a\\b\\c\\d");
+        t!(s: "\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
+        t!(s: "\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
+        t!(s: "\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
+        t!(s: "\\\\?\\C:\\a\\b", "..\\..\\..\\c", "\\\\?\\C:\\a\\b\\..\\..\\..\\c");
+        t!(s: "\\\\?\\foo\\bar", "..\\..\\c", "\\\\?\\foo\\bar\\..\\..\\c");
+        t!(s: "\\\\?\\", "foo", "\\\\?\\\\foo");
+        t!(s: "\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
+        t!(s: "\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
+        t!(s: "\\\\?\\UNC\\server\\share", "C:a", "C:a");
+        t!(s: "\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\\\foo");
+        t!(s: "C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
+        t!(s: "\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
+        t!(s: "\\\\.\\foo\\bar", "C:a", "C:a");
+        // again, not sure about the following, but I'm assuming \\.\ should be verbatim
+        t!(s: "\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
+
+        t!(s: "\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
+    }
+
+    #[test]
+    fn test_push_many() {
+        macro_rules! t {
+            (s: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    p.push_many(&$push);
+                    assert_eq!(p.as_str(), Some($exp));
+                }
+            );
+            (v: $path:expr, $push:expr, $exp:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    p.push_many(&$push);
+                    assert_eq!(p.as_vec(), $exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
+        t!(s: "a\\b\\c", ["d", "\\e"], "\\e");
+        t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
+        t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e");
+        t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e");
+        t!(v: b"a\\b\\c", [b"d", b"\\e", b"f"], b"\\e\\f");
+        t!(v: b"a\\b\\c", [b"d".to_vec(), b"e".to_vec()],
+           b"a\\b\\c\\d\\e");
+    }
+
+    #[test]
+    fn test_pop() {
+        macro_rules! t {
+            (s: $path:expr, $left:expr, $right:expr) => (
+                {
+                    let pstr = $path;
+                    let mut p = Path::new(pstr);
+                    let result = p.pop();
+                    let left = $left;
+                    assert_eq!(p.as_str(), Some(left));
+                    assert_eq!(result, $right);
+                }
+            );
+            (b: $path:expr, $left:expr, $right:expr) => (
+                {
+                    let mut p = Path::new($path);
+                    let result = p.pop();
+                    assert_eq!(p.as_vec(), $left);
+                    assert_eq!(result, $right);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "a\\b", true);
+        t!(s: "a", ".", true);
+        t!(s: ".", ".", false);
+        t!(s: "\\a", "\\", true);
+        t!(s: "\\", "\\", false);
+        t!(b: b"a\\b\\c", b"a\\b", true);
+        t!(b: b"a", b".", true);
+        t!(b: b".", b".", false);
+        t!(b: b"\\a", b"\\", true);
+        t!(b: b"\\", b"\\", false);
+
+        t!(s: "C:\\a\\b", "C:\\a", true);
+        t!(s: "C:\\a", "C:\\", true);
+        t!(s: "C:\\", "C:\\", false);
+        t!(s: "C:a\\b", "C:a", true);
+        t!(s: "C:a", "C:", true);
+        t!(s: "C:", "C:", false);
+        t!(s: "\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
+        t!(s: "\\\\server\\share\\a", "\\\\server\\share", true);
+        t!(s: "\\\\server\\share", "\\\\server\\share", false);
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
+        t!(s: "\\\\?\\a\\b", "\\\\?\\a", true);
+        t!(s: "\\\\?\\a", "\\\\?\\a", false);
+        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\", true);
+        t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\", false);
+        t!(s: "\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
+        t!(s: "\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share", true);
+        t!(s: "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
+        t!(s: "\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
+        t!(s: "\\\\.\\a\\b", "\\\\.\\a", true);
+        t!(s: "\\\\.\\a", "\\\\.\\a", false);
+
+        t!(s: "\\\\?\\a\\b\\", "\\\\?\\a", true);
+    }
+
+    #[test]
+    fn test_root_path() {
+        assert_eq!(Path::new("a\\b\\c").root_path(),  None);
+        assert_eq!(Path::new("\\a\\b\\c").root_path(), Some(Path::new("\\")));
+        assert_eq!(Path::new("C:a").root_path(), Some(Path::new("C:")));
+        assert_eq!(Path::new("C:\\a").root_path(), Some(Path::new("C:\\")));
+        assert_eq!(Path::new("\\\\a\\b\\c").root_path(), Some(Path::new("\\\\a\\b")));
+        assert_eq!(Path::new("\\\\?\\a\\b").root_path(), Some(Path::new("\\\\?\\a")));
+        assert_eq!(Path::new("\\\\?\\C:\\a").root_path(), Some(Path::new("\\\\?\\C:\\")));
+        assert_eq!(Path::new("\\\\?\\UNC\\a\\b\\c").root_path(),
+                Some(Path::new("\\\\?\\UNC\\a\\b")));
+        assert_eq!(Path::new("\\\\.\\a\\b").root_path(), Some(Path::new("\\\\.\\a")));
+    }
+
+    #[test]
+    fn test_join() {
+        t!(s: Path::new("a\\b\\c").join(".."), "a\\b");
+        t!(s: Path::new("\\a\\b\\c").join("d"), "\\a\\b\\c\\d");
+        t!(s: Path::new("a\\b").join("c\\d"), "a\\b\\c\\d");
+        t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d");
+        t!(s: Path::new(".").join("a\\b"), "a\\b");
+        t!(s: Path::new("\\").join("a\\b"), "\\a\\b");
+        t!(v: Path::new(b"a\\b\\c").join(b".."), b"a\\b");
+        t!(v: Path::new(b"\\a\\b\\c").join(b"d"), b"\\a\\b\\c\\d");
+        // full join testing is covered under test_push_path, so no need for
+        // the full set of prefix tests
+    }
+
+    #[test]
+    fn test_join_path() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let join = Path::new($join);
+                    let res = path.join(&join);
+                    assert_eq!(res.as_str(), Some($exp));
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "..", "a\\b");
+        t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
+        t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
+        t!(s: "a\\b", "\\c\\d", "\\c\\d");
+        t!(s: ".", "a\\b", "a\\b");
+        t!(s: "\\", "a\\b", "\\a\\b");
+        // join is implemented using push, so there's no need for
+        // the full set of prefix tests
+    }
+
+    #[test]
+    fn test_join_many() {
+        macro_rules! t {
+            (s: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let res = path.join_many(&$join);
+                    assert_eq!(res.as_str(), Some($exp));
+                }
+            );
+            (v: $path:expr, $join:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let res = path.join_many(&$join);
+                    assert_eq!(res.as_vec(), $exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
+        t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
+        t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
+        t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e");
+        t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e");
+        t!(v: b"a\\b\\c", [b"d".to_vec(), b"e".to_vec()],
+           b"a\\b\\c\\d\\e");
+    }
+
+    #[test]
+    fn test_with_helpers() {
+        macro_rules! t {
+            (s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
+                {
+                    let pstr = $path;
+                    let path = Path::new(pstr);
+                    let arg = $arg;
+                    let res = path.$op(arg);
+                    let exp = Path::new($res);
+                    assert_eq!(res, exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
+        t!(s: ".", with_filename, "foo", "foo");
+        t!(s: "\\a\\b\\c", with_filename, "d", "\\a\\b\\d");
+        t!(s: "\\", with_filename, "foo", "\\foo");
+        t!(s: "\\a", with_filename, "foo", "\\foo");
+        t!(s: "foo", with_filename, "bar", "bar");
+        t!(s: "\\", with_filename, "foo\\", "\\foo");
+        t!(s: "\\a", with_filename, "foo\\", "\\foo");
+        t!(s: "a\\b\\c", with_filename, "", "a\\b");
+        t!(s: "a\\b\\c", with_filename, ".", "a\\b");
+        t!(s: "a\\b\\c", with_filename, "..", "a");
+        t!(s: "\\a", with_filename, "", "\\");
+        t!(s: "foo", with_filename, "", ".");
+        t!(s: "a\\b\\c", with_filename, "d\\e", "a\\b\\d\\e");
+        t!(s: "a\\b\\c", with_filename, "\\d", "a\\b\\d");
+        t!(s: "..", with_filename, "foo", "..\\foo");
+        t!(s: "..\\..", with_filename, "foo", "..\\..\\foo");
+        t!(s: "..", with_filename, "", "..");
+        t!(s: "..\\..", with_filename, "", "..\\..");
+        t!(s: "C:\\foo\\bar", with_filename, "baz", "C:\\foo\\baz");
+        t!(s: "C:\\foo", with_filename, "bar", "C:\\bar");
+        t!(s: "C:\\", with_filename, "foo", "C:\\foo");
+        t!(s: "C:foo\\bar", with_filename, "baz", "C:foo\\baz");
+        t!(s: "C:foo", with_filename, "bar", "C:bar");
+        t!(s: "C:", with_filename, "foo", "C:foo");
+        t!(s: "C:\\foo", with_filename, "", "C:\\");
+        t!(s: "C:foo", with_filename, "", "C:");
+        t!(s: "C:\\foo\\bar", with_filename, "..", "C:\\");
+        t!(s: "C:\\foo", with_filename, "..", "C:\\");
+        t!(s: "C:\\", with_filename, "..", "C:\\");
+        t!(s: "C:foo\\bar", with_filename, "..", "C:");
+        t!(s: "C:foo", with_filename, "..", "C:..");
+        t!(s: "C:", with_filename, "..", "C:..");
+        t!(s: "\\\\server\\share\\foo", with_filename, "bar", "\\\\server\\share\\bar");
+        t!(s: "\\\\server\\share", with_filename, "foo", "\\\\server\\share\\foo");
+        t!(s: "\\\\server\\share\\foo", with_filename, "", "\\\\server\\share");
+        t!(s: "\\\\server\\share", with_filename, "", "\\\\server\\share");
+        t!(s: "\\\\server\\share\\foo", with_filename, "..", "\\\\server\\share");
+        t!(s: "\\\\server\\share", with_filename, "..", "\\\\server\\share");
+        t!(s: "\\\\?\\C:\\foo\\bar", with_filename, "baz", "\\\\?\\C:\\foo\\baz");
+        t!(s: "\\\\?\\C:\\foo", with_filename, "bar", "\\\\?\\C:\\bar");
+        t!(s: "\\\\?\\C:\\", with_filename, "foo", "\\\\?\\C:\\foo");
+        t!(s: "\\\\?\\C:\\foo", with_filename, "..", "\\\\?\\C:\\..");
+        t!(s: "\\\\?\\foo\\bar", with_filename, "baz", "\\\\?\\foo\\baz");
+        t!(s: "\\\\?\\foo", with_filename, "bar", "\\\\?\\foo\\bar");
+        t!(s: "\\\\?\\", with_filename, "foo", "\\\\?\\\\foo");
+        t!(s: "\\\\?\\foo\\bar", with_filename, "..", "\\\\?\\foo\\..");
+        t!(s: "\\\\.\\foo\\bar", with_filename, "baz", "\\\\.\\foo\\baz");
+        t!(s: "\\\\.\\foo", with_filename, "bar", "\\\\.\\foo\\bar");
+        t!(s: "\\\\.\\foo\\bar", with_filename, "..", "\\\\.\\foo\\..");
+
+        t!(s: "hi\\there.txt", with_extension, "exe", "hi\\there.exe");
+        t!(s: "hi\\there.txt", with_extension, "", "hi\\there");
+        t!(s: "hi\\there.txt", with_extension, ".", "hi\\there..");
+        t!(s: "hi\\there.txt", with_extension, "..", "hi\\there...");
+        t!(s: "hi\\there", with_extension, "txt", "hi\\there.txt");
+        t!(s: "hi\\there", with_extension, ".", "hi\\there..");
+        t!(s: "hi\\there", with_extension, "..", "hi\\there...");
+        t!(s: "hi\\there.", with_extension, "txt", "hi\\there.txt");
+        t!(s: "hi\\.foo", with_extension, "txt", "hi\\.foo.txt");
+        t!(s: "hi\\there.txt", with_extension, ".foo", "hi\\there..foo");
+        t!(s: "\\", with_extension, "txt", "\\");
+        t!(s: "\\", with_extension, ".", "\\");
+        t!(s: "\\", with_extension, "..", "\\");
+        t!(s: ".", with_extension, "txt", ".");
+        // extension setter calls filename setter internally, no need for extended tests
+    }
+
+    #[test]
+    fn test_setters() {
+        macro_rules! t {
+            (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
+                {
+                    let path = $path;
+                    let arg = $arg;
+                    let mut p1 = Path::new(path);
+                    p1.$set(arg);
+                    let p2 = Path::new(path);
+                    assert_eq!(p1, p2.$with(arg));
+                }
+            );
+            (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
+                {
+                    let path = $path;
+                    let arg = $arg;
+                    let mut p1 = Path::new(path);
+                    p1.$set(arg);
+                    let p2 = Path::new(path);
+                    assert_eq!(p1, p2.$with(arg));
+                }
+            )
+        }
+
+        t!(v: b"a\\b\\c", set_filename, with_filename, b"d");
+        t!(v: b"\\", set_filename, with_filename, b"foo");
+        t!(s: "a\\b\\c", set_filename, with_filename, "d");
+        t!(s: "\\", set_filename, with_filename, "foo");
+        t!(s: ".", set_filename, with_filename, "foo");
+        t!(s: "a\\b", set_filename, with_filename, "");
+        t!(s: "a", set_filename, with_filename, "");
+
+        t!(v: b"hi\\there.txt", set_extension, with_extension, b"exe");
+        t!(s: "hi\\there.txt", set_extension, with_extension, "exe");
+        t!(s: "hi\\there.", set_extension, with_extension, "txt");
+        t!(s: "hi\\there", set_extension, with_extension, "txt");
+        t!(s: "hi\\there.txt", set_extension, with_extension, "");
+        t!(s: "hi\\there", set_extension, with_extension, "");
+        t!(s: ".", set_extension, with_extension, "txt");
+
+        // with_ helpers use the setter internally, so the tests for the with_ helpers
+        // will suffice. No need for the full set of prefix tests.
+    }
+
+    #[test]
+    fn test_getters() {
+        macro_rules! t {
+            (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
+                {
+                    let path = $path;
+                    assert_eq!(path.filename_str(), $filename);
+                    assert_eq!(path.dirname_str(), $dirname);
+                    assert_eq!(path.filestem_str(), $filestem);
+                    assert_eq!(path.extension_str(), $ext);
+                }
+            );
+            (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
+                {
+                    let path = $path;
+                    assert_eq!(path.filename(), $filename);
+                    assert_eq!(path.dirname(), $dirname);
+                    assert_eq!(path.filestem(), $filestem);
+                    assert_eq!(path.extension(), $ext);
+                }
+            )
+        }
+
+        t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None);
+        t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
+        t!(s: Path::new("."), None, Some("."), None, None);
+        t!(s: Path::new("\\"), None, Some("\\"), None, None);
+        t!(s: Path::new(".."), None, Some(".."), None, None);
+        t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None);
+        t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"),
+              Some("there"), Some("txt"));
+        t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None);
+        t!(s: Path::new("hi\\there."), Some("there."), Some("hi"),
+              Some("there"), Some(""));
+        t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None);
+        t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"),
+              Some("."), Some("there"));
+
+        // these are already tested in test_components, so no need for extended tests
+    }
+
+    #[test]
+    fn test_dir_path() {
+        t!(s: Path::new("hi\\there").dir_path(), "hi");
+        t!(s: Path::new("hi").dir_path(), ".");
+        t!(s: Path::new("\\hi").dir_path(), "\\");
+        t!(s: Path::new("\\").dir_path(), "\\");
+        t!(s: Path::new("..").dir_path(), "..");
+        t!(s: Path::new("..\\..").dir_path(), "..\\..");
+
+        // dir_path is just dirname interpreted as a path.
+        // No need for extended tests
+    }
+
+    #[test]
+    fn test_is_absolute() {
+        macro_rules! t {
+            ($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
+                {
+                    let path = Path::new($path);
+                    let (abs, vol, cwd, rel) = ($abs, $vol, $cwd, $rel);
+                    assert_eq!(path.is_absolute(), abs);
+                    assert_eq!(is_vol_relative(&path), vol);
+                    assert_eq!(is_cwd_relative(&path), cwd);
+                    assert_eq!(path.is_relative(), rel);
+                }
+            )
+        }
+        t!("a\\b\\c", false, false, false, true);
+        t!("\\a\\b\\c", false, true, false, false);
+        t!("a", false, false, false, true);
+        t!("\\a", false, true, false, false);
+        t!(".", false, false, false, true);
+        t!("\\", false, true, false, false);
+        t!("..", false, false, false, true);
+        t!("..\\..", false, false, false, true);
+        t!("C:a\\b.txt", false, false, true, false);
+        t!("C:\\a\\b.txt", true, false, false, false);
+        t!("\\\\server\\share\\a\\b.txt", true, false, false, false);
+        t!("\\\\?\\a\\b\\c.txt", true, false, false, false);
+        t!("\\\\?\\C:\\a\\b.txt", true, false, false, false);
+        t!("\\\\?\\C:a\\b.txt", true, false, false, false); // NB: not equivalent to C:a\b.txt
+        t!("\\\\?\\UNC\\server\\share\\a\\b.txt", true, false, false, false);
+        t!("\\\\.\\a\\b", true, false, false, false);
+    }
+
+    #[test]
+    fn test_is_ancestor_of() {
+        macro_rules! t {
+            (s: $path:expr, $dest:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let dest = Path::new($dest);
+                    let exp = $exp;
+                    let res = path.is_ancestor_of(&dest);
+                    assert_eq!(res, exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "a\\b\\c\\d", true);
+        t!(s: "a\\b\\c", "a\\b\\c", true);
+        t!(s: "a\\b\\c", "a\\b", false);
+        t!(s: "\\a\\b\\c", "\\a\\b\\c", true);
+        t!(s: "\\a\\b", "\\a\\b\\c", true);
+        t!(s: "\\a\\b\\c\\d", "\\a\\b\\c", false);
+        t!(s: "\\a\\b", "a\\b\\c", false);
+        t!(s: "a\\b", "\\a\\b\\c", false);
+        t!(s: "a\\b\\c", "a\\b\\d", false);
+        t!(s: "..\\a\\b\\c", "a\\b\\c", false);
+        t!(s: "a\\b\\c", "..\\a\\b\\c", false);
+        t!(s: "a\\b\\c", "a\\b\\cd", false);
+        t!(s: "a\\b\\cd", "a\\b\\c", false);
+        t!(s: "..\\a\\b", "..\\a\\b\\c", true);
+        t!(s: ".", "a\\b", true);
+        t!(s: ".", ".", true);
+        t!(s: "\\", "\\", true);
+        t!(s: "\\", "\\a\\b", true);
+        t!(s: "..", "a\\b", true);
+        t!(s: "..\\..", "a\\b", true);
+        t!(s: "foo\\bar", "foobar", false);
+        t!(s: "foobar", "foo\\bar", false);
+
+        t!(s: "foo", "C:foo", false);
+        t!(s: "C:foo", "foo", false);
+        t!(s: "C:foo", "C:foo\\bar", true);
+        t!(s: "C:foo\\bar", "C:foo", false);
+        t!(s: "C:\\foo", "C:\\foo\\bar", true);
+        t!(s: "C:", "C:", true);
+        t!(s: "C:", "C:\\", false);
+        t!(s: "C:\\", "C:", false);
+        t!(s: "C:\\", "C:\\", true);
+        t!(s: "C:\\foo\\bar", "C:\\foo", false);
+        t!(s: "C:foo\\bar", "C:foo", false);
+        t!(s: "C:\\foo", "\\foo", false);
+        t!(s: "\\foo", "C:\\foo", false);
+        t!(s: "\\\\server\\share\\foo", "\\\\server\\share\\foo\\bar", true);
+        t!(s: "\\\\server\\share", "\\\\server\\share\\foo", true);
+        t!(s: "\\\\server\\share\\foo", "\\\\server\\share", false);
+        t!(s: "C:\\foo", "\\\\server\\share\\foo", false);
+        t!(s: "\\\\server\\share\\foo", "C:\\foo", false);
+        t!(s: "\\\\?\\foo\\bar", "\\\\?\\foo\\bar\\baz", true);
+        t!(s: "\\\\?\\foo\\bar\\baz", "\\\\?\\foo\\bar", false);
+        t!(s: "\\\\?\\foo\\bar", "\\foo\\bar\\baz", false);
+        t!(s: "\\foo\\bar", "\\\\?\\foo\\bar\\baz", false);
+        t!(s: "\\\\?\\C:\\foo\\bar", "\\\\?\\C:\\foo\\bar\\baz", true);
+        t!(s: "\\\\?\\C:\\foo\\bar\\baz", "\\\\?\\C:\\foo\\bar", false);
+        t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\foo", true);
+        t!(s: "\\\\?\\C:", "\\\\?\\C:\\", false); // this is a weird one
+        t!(s: "\\\\?\\C:\\", "\\\\?\\C:", false);
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\c:\\a\\b", true);
+        t!(s: "\\\\?\\c:\\a", "\\\\?\\C:\\a\\b", true);
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a\\b", false);
+        t!(s: "\\\\?\\foo", "\\\\?\\foobar", false);
+        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", true);
+        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\", true);
+        t!(s: "\\\\?\\a\\b\\", "\\\\?\\a\\b", true);
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", false);
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b\\", false);
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c\\d", true);
+        t!(s: "\\\\?\\UNC\\a\\b\\c\\d", "\\\\?\\UNC\\a\\b\\c", false);
+        t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", true);
+        t!(s: "\\\\.\\foo\\bar", "\\\\.\\foo\\bar\\baz", true);
+        t!(s: "\\\\.\\foo\\bar\\baz", "\\\\.\\foo\\bar", false);
+        t!(s: "\\\\.\\foo", "\\\\.\\foo\\bar", true);
+        t!(s: "\\\\.\\foo", "\\\\.\\foobar", false);
+
+        t!(s: "\\a\\b", "\\\\?\\a\\b", false);
+        t!(s: "\\\\?\\a\\b", "\\a\\b", false);
+        t!(s: "\\a\\b", "\\\\?\\C:\\a\\b", false);
+        t!(s: "\\\\?\\C:\\a\\b", "\\a\\b", false);
+        t!(s: "Z:\\a\\b", "\\\\?\\z:\\a\\b", true);
+        t!(s: "C:\\a\\b", "\\\\?\\D:\\a\\b", false);
+        t!(s: "a\\b", "\\\\?\\a\\b", false);
+        t!(s: "\\\\?\\a\\b", "a\\b", false);
+        t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b", true);
+        t!(s: "\\\\?\\C:\\a\\b", "C:\\a\\b", true);
+        t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", false);
+        t!(s: "C:a\\b", "\\\\?\\C:a\\b", false);
+        t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", false);
+        t!(s: "\\\\?\\C:a\\b", "C:a\\b", false);
+        t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b\\", true);
+        t!(s: "\\\\?\\C:\\a\\b\\", "C:\\a\\b", true);
+        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c", true);
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b\\c", true);
+    }
+
+    #[test]
+    fn test_ends_with_path() {
+        macro_rules! t {
+            (s: $path:expr, $child:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let child = Path::new($child);
+                    assert_eq!(path.ends_with_path(&child), $exp);
+                }
+            );
+        }
+
+        t!(s: "a\\b\\c", "c", true);
+        t!(s: "a\\b\\c", "d", false);
+        t!(s: "foo\\bar\\quux", "bar", false);
+        t!(s: "foo\\bar\\quux", "barquux", false);
+        t!(s: "a\\b\\c", "b\\c", true);
+        t!(s: "a\\b\\c", "a\\b\\c", true);
+        t!(s: "a\\b\\c", "foo\\a\\b\\c", false);
+        t!(s: "\\a\\b\\c", "a\\b\\c", true);
+        t!(s: "\\a\\b\\c", "\\a\\b\\c", false); // child must be relative
+        t!(s: "\\a\\b\\c", "foo\\a\\b\\c", false);
+        t!(s: "a\\b\\c", "", false);
+        t!(s: "", "", true);
+        t!(s: "\\a\\b\\c", "d\\e\\f", false);
+        t!(s: "a\\b\\c", "a\\b", false);
+        t!(s: "a\\b\\c", "b", false);
+        t!(s: "C:\\a\\b", "b", true);
+        t!(s: "C:\\a\\b", "C:b", false);
+        t!(s: "C:\\a\\b", "C:a\\b", false);
+    }
+
+    #[test]
+    fn test_path_relative_from() {
+        macro_rules! t {
+            (s: $path:expr, $other:expr, $exp:expr) => (
+                {
+                    assert_eq!(Path::new($path).path_relative_from(&Path::new($other))
+                              .as_ref().and_then(|x| x.as_str()), $exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", "a\\b", Some("c"));
+        t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c"));
+        t!(s: "a\\b\\c", "a\\b\\c\\d", Some(".."));
+        t!(s: "a\\b\\c", "a\\b\\c", Some("."));
+        t!(s: "a\\b\\c", "a\\b\\c\\d\\e", Some("..\\.."));
+        t!(s: "a\\b\\c", "a\\d\\e", Some("..\\..\\b\\c"));
+        t!(s: "a\\b\\c", "d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
+        t!(s: "a\\b\\c", "\\a\\b\\c", None);
+        t!(s: "\\a\\b\\c", "a\\b\\c", Some("\\a\\b\\c"));
+        t!(s: "\\a\\b\\c", "\\a\\b\\c\\d", Some(".."));
+        t!(s: "\\a\\b\\c", "\\a\\b", Some("c"));
+        t!(s: "\\a\\b\\c", "\\a\\b\\c\\d\\e", Some("..\\.."));
+        t!(s: "\\a\\b\\c", "\\a\\d\\e", Some("..\\..\\b\\c"));
+        t!(s: "\\a\\b\\c", "\\d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
+        t!(s: "hi\\there.txt", "hi\\there", Some("..\\there.txt"));
+        t!(s: ".", "a", Some(".."));
+        t!(s: ".", "a\\b", Some("..\\.."));
+        t!(s: ".", ".", Some("."));
+        t!(s: "a", ".", Some("a"));
+        t!(s: "a\\b", ".", Some("a\\b"));
+        t!(s: "..", ".", Some(".."));
+        t!(s: "a\\b\\c", "a\\b\\c", Some("."));
+        t!(s: "\\a\\b\\c", "\\a\\b\\c", Some("."));
+        t!(s: "\\", "\\", Some("."));
+        t!(s: "\\", ".", Some("\\"));
+        t!(s: "..\\..\\a", "b", Some("..\\..\\..\\a"));
+        t!(s: "a", "..\\..\\b", None);
+        t!(s: "..\\..\\a", "..\\..\\b", Some("..\\a"));
+        t!(s: "..\\..\\a", "..\\..\\a\\b", Some(".."));
+        t!(s: "..\\..\\a\\b", "..\\..\\a", Some("b"));
+
+        t!(s: "C:a\\b\\c", "C:a\\b", Some("c"));
+        t!(s: "C:a\\b", "C:a\\b\\c", Some(".."));
+        t!(s: "C:" ,"C:a\\b", Some("..\\.."));
+        t!(s: "C:a\\b", "C:c\\d", Some("..\\..\\a\\b"));
+        t!(s: "C:a\\b", "D:c\\d", Some("C:a\\b"));
+        t!(s: "C:a\\b", "C:..\\c", None);
+        t!(s: "C:..\\a", "C:b\\c", Some("..\\..\\..\\a"));
+        t!(s: "C:\\a\\b\\c", "C:\\a\\b", Some("c"));
+        t!(s: "C:\\a\\b", "C:\\a\\b\\c", Some(".."));
+        t!(s: "C:\\", "C:\\a\\b", Some("..\\.."));
+        t!(s: "C:\\a\\b", "C:\\c\\d", Some("..\\..\\a\\b"));
+        t!(s: "C:\\a\\b", "C:a\\b", Some("C:\\a\\b"));
+        t!(s: "C:a\\b", "C:\\a\\b", None);
+        t!(s: "\\a\\b", "C:\\a\\b", None);
+        t!(s: "\\a\\b", "C:a\\b", None);
+        t!(s: "a\\b", "C:\\a\\b", None);
+        t!(s: "a\\b", "C:a\\b", None);
+
+        t!(s: "\\\\a\\b\\c", "\\\\a\\b", Some("c"));
+        t!(s: "\\\\a\\b", "\\\\a\\b\\c", Some(".."));
+        t!(s: "\\\\a\\b\\c\\e", "\\\\a\\b\\c\\d", Some("..\\e"));
+        t!(s: "\\\\a\\c\\d", "\\\\a\\b\\d", Some("\\\\a\\c\\d"));
+        t!(s: "\\\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\b\\c\\d"));
+        t!(s: "\\\\a\\b\\c", "\\d\\e", Some("\\\\a\\b\\c"));
+        t!(s: "\\d\\e", "\\\\a\\b\\c", None);
+        t!(s: "d\\e", "\\\\a\\b\\c", None);
+        t!(s: "C:\\a\\b\\c", "\\\\a\\b\\c", Some("C:\\a\\b\\c"));
+        t!(s: "C:\\c", "\\\\a\\b\\c", Some("C:\\c"));
+
+        t!(s: "\\\\?\\a\\b", "\\a\\b", Some("\\\\?\\a\\b"));
+        t!(s: "\\\\?\\a\\b", "a\\b", Some("\\\\?\\a\\b"));
+        t!(s: "\\\\?\\a\\b", "\\b", Some("\\\\?\\a\\b"));
+        t!(s: "\\\\?\\a\\b", "b", Some("\\\\?\\a\\b"));
+        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", Some(".."));
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", Some("c"));
+        t!(s: "\\\\?\\a\\b", "\\\\?\\c\\d", Some("\\\\?\\a\\b"));
+        t!(s: "\\\\?\\a", "\\\\?\\b", Some("\\\\?\\a"));
+
+        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\b", Some("..\\a"));
+        t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a", Some("\\\\?\\C:\\a"));
+        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\c:\\a", Some("b"));
+        t!(s: "\\\\?\\C:\\a\\b", "C:\\a", Some("b"));
+        t!(s: "\\\\?\\C:\\a", "C:\\a\\b", Some(".."));
+        t!(s: "C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
+        t!(s: "C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
+        t!(s: "\\\\?\\C:\\a", "D:\\a", Some("\\\\?\\C:\\a"));
+        t!(s: "\\\\?\\c:\\a\\b", "C:\\a", Some("b"));
+        t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", Some("\\\\?\\C:\\a\\b"));
+        t!(s: "\\\\?\\C:\\a\\.\\b", "C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
+        t!(s: "\\\\?\\C:\\a\\b/c", "C:\\a", Some("\\\\?\\C:\\a\\b/c"));
+        t!(s: "\\\\?\\C:\\a\\..\\b", "C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
+        t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", None);
+        t!(s: "\\\\?\\C:\\a\\.\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
+        t!(s: "\\\\?\\C:\\a\\b/c", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\b/c"));
+        t!(s: "\\\\?\\C:\\a\\..\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
+        t!(s: "\\\\?\\C:\\a\\b\\", "\\\\?\\C:\\a", Some("b"));
+        t!(s: "\\\\?\\C:\\.\\b", "\\\\?\\C:\\.", Some("b"));
+        t!(s: "C:\\b", "\\\\?\\C:\\.", Some("..\\b"));
+        t!(s: "\\\\?\\a\\.\\b\\c", "\\\\?\\a\\.\\b", Some("c"));
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\.\\d", Some("..\\..\\b\\c"));
+        t!(s: "\\\\?\\a\\..\\b", "\\\\?\\a\\..", Some("b"));
+        t!(s: "\\\\?\\a\\b\\..", "\\\\?\\a\\b", Some("\\\\?\\a\\b\\.."));
+        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\..\\b", Some("..\\..\\b\\c"));
+
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
+        t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", Some(".."));
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
+        t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\C:\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
+        t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
+        t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
+        t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b", Some("c"));
+        t!(s: "\\\\?\\UNC\\a\\b", "\\\\a\\b\\c", Some(".."));
+        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
+        t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
+        t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
+        t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
+        t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
+        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
+        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\a\\b\\c"));
+    }
+
+    #[test]
+    fn test_str_components() {
+        macro_rules! t {
+            (s: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let comps = path.str_components().map(|x|x.unwrap())
+                                .collect::<Vec<&str>>();
+                    let exp: &[&str] = &$exp;
+                    assert_eq!(comps, exp);
+                    let comps = path.str_components().rev().map(|x|x.unwrap())
+                                .collect::<Vec<&str>>();
+                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&str>>();
+                    assert_eq!(comps, exp);
+                }
+            );
+        }
+
+        t!(s: b"a\\b\\c", ["a", "b", "c"]);
+        t!(s: "a\\b\\c", ["a", "b", "c"]);
+        t!(s: "a\\b\\d", ["a", "b", "d"]);
+        t!(s: "a\\b\\cd", ["a", "b", "cd"]);
+        t!(s: "\\a\\b\\c", ["a", "b", "c"]);
+        t!(s: "a", ["a"]);
+        t!(s: "\\a", ["a"]);
+        t!(s: "\\", []);
+        t!(s: ".", ["."]);
+        t!(s: "..", [".."]);
+        t!(s: "..\\..", ["..", ".."]);
+        t!(s: "..\\..\\foo", ["..", "..", "foo"]);
+        t!(s: "C:foo\\bar", ["foo", "bar"]);
+        t!(s: "C:foo", ["foo"]);
+        t!(s: "C:", []);
+        t!(s: "C:\\foo\\bar", ["foo", "bar"]);
+        t!(s: "C:\\foo", ["foo"]);
+        t!(s: "C:\\", []);
+        t!(s: "\\\\server\\share\\foo\\bar", ["foo", "bar"]);
+        t!(s: "\\\\server\\share\\foo", ["foo"]);
+        t!(s: "\\\\server\\share", []);
+        t!(s: "\\\\?\\foo\\bar\\baz", ["bar", "baz"]);
+        t!(s: "\\\\?\\foo\\bar", ["bar"]);
+        t!(s: "\\\\?\\foo", []);
+        t!(s: "\\\\?\\", []);
+        t!(s: "\\\\?\\a\\b", ["b"]);
+        t!(s: "\\\\?\\a\\b\\", ["b"]);
+        t!(s: "\\\\?\\foo\\bar\\\\baz", ["bar", "", "baz"]);
+        t!(s: "\\\\?\\C:\\foo\\bar", ["foo", "bar"]);
+        t!(s: "\\\\?\\C:\\foo", ["foo"]);
+        t!(s: "\\\\?\\C:\\", []);
+        t!(s: "\\\\?\\C:\\foo\\", ["foo"]);
+        t!(s: "\\\\?\\UNC\\server\\share\\foo\\bar", ["foo", "bar"]);
+        t!(s: "\\\\?\\UNC\\server\\share\\foo", ["foo"]);
+        t!(s: "\\\\?\\UNC\\server\\share", []);
+        t!(s: "\\\\.\\foo\\bar\\baz", ["bar", "baz"]);
+        t!(s: "\\\\.\\foo\\bar", ["bar"]);
+        t!(s: "\\\\.\\foo", []);
+    }
+
+    #[test]
+    fn test_components_iter() {
+        macro_rules! t {
+            (s: $path:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let comps = path.components().collect::<Vec<&[u8]>>();
+                    let exp: &[&[u8]] = &$exp;
+                    assert_eq!(comps, exp);
+                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
+                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
+                    assert_eq!(comps, exp);
+                }
+            )
+        }
+
+        t!(s: "a\\b\\c", [b"a", b"b", b"c"]);
+        t!(s: ".", [b"."]);
+        // since this is really a wrapper around str_components, those tests suffice
+    }
+
+    #[test]
+    fn test_make_non_verbatim() {
+        macro_rules! t {
+            ($path:expr, $exp:expr) => (
+                {
+                    let path = Path::new($path);
+                    let exp: Option<&str> = $exp;
+                    let exp = exp.map(|s| Path::new(s));
+                    assert_eq!(make_non_verbatim(&path), exp);
+                }
+            )
+        }
+
+        t!(r"\a\b\c", Some(r"\a\b\c"));
+        t!(r"a\b\c", Some(r"a\b\c"));
+        t!(r"C:\a\b\c", Some(r"C:\a\b\c"));
+        t!(r"C:a\b\c", Some(r"C:a\b\c"));
+        t!(r"\\server\share\foo", Some(r"\\server\share\foo"));
+        t!(r"\\.\foo", None);
+        t!(r"\\?\foo", None);
+        t!(r"\\?\C:", None);
+        t!(r"\\?\C:foo", None);
+        t!(r"\\?\C:\", Some(r"C:\"));
+        t!(r"\\?\C:\foo", Some(r"C:\foo"));
+        t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz"));
+        t!(r"\\?\C:\foo\.\bar\baz", None);
+        t!(r"\\?\C:\foo\bar\..\baz", None);
+        t!(r"\\?\C:\foo\bar\..", None);
+        t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo"));
+        t!(r"\\?\UNC\server\share", Some(r"\\server\share"));
+        t!(r"\\?\UNC\server", None);
+        t!(r"\\?\UNC\server\", None);
+    }
+}
index d92f361af0bf24508fe18e9e4b11d5ed30aa5299..36122b16ea078115b9ae204b9dd0c88bd36fde5a 100644 (file)
@@ -48,7 +48,7 @@
 use ops::{Drop, FnOnce};
 use option::Option::{Some, None};
 use option::Option;
-use path::{Path, GenericPath, BytesContainer};
+use old_path::{Path, GenericPath, BytesContainer};
 use ptr::PtrExt;
 use ptr;
 use result::Result::{Err, Ok};
@@ -267,7 +267,7 @@ pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
 ///
 /// ```rust
 /// use std::os;
-/// use std::path::Path;
+/// use std::old_path::Path;
 ///
 /// let key = "PATH";
 /// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
@@ -470,7 +470,7 @@ fn lookup() -> Path {
 /// # Example
 /// ```rust
 /// use std::os;
-/// use std::path::Path;
+/// use std::old_path::Path;
 ///
 /// // Assume we're in a path like /home/someuser
 /// let rel_path = Path::new("..");
@@ -500,7 +500,7 @@ pub fn make_absolute(p: &Path) -> IoResult<Path> {
 /// # Example
 /// ```rust
 /// use std::os;
-/// use std::path::Path;
+/// use std::old_path::Path;
 ///
 /// let root = Path::new("/");
 /// assert!(os::change_dir(&root).is_ok());
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
new file mode 100755 (executable)
index 0000000..3fd45ea
--- /dev/null
@@ -0,0 +1,2567 @@
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Cross-platform path manipulation.
+//!
+//! This module provides two types, `PathBuf` and `Path` (akin to `String` and
+//! `str`), for working with paths abstractly. These types are thin wrappers
+//! around `OsString` and `OsStr` respectively, meaning that they work directly
+//! on strings according to the local platform's path syntax.
+//!
+//! ## Simple usage
+//!
+//! Path manipulation involves both parsing components from slices and building
+//! new owned paths.
+//!
+//! To parse a path, you can create a `Path` slice from a `str`
+//! slice and start asking questions:
+//!
+//! ```rust
+//! use std::path::Path;
+//!
+//! let path = Path::new("/tmp/foo/bar.txt");
+//! let file = path.file_name();
+//! let extension = path.extension();
+//! let parent_dir = path.parent();
+//! ```
+//!
+//! To build or modify paths, use `PathBuf`:
+//!
+//! ```rust
+//! use std::path::PathBuf;
+//!
+//! let mut path = PathBuf::new("c:\\");
+//! path.push("windows");
+//! path.push("system32");
+//! path.set_extension("dll");
+//! ```
+//!
+//! ## Path components and normalization
+//!
+//! The path APIs are built around the notion of "components", which roughly
+//! correspond to the substrings between path separators (`/` and, on Windows,
+//! `\`). The APIs for path parsing are largely specified in terms of the path's
+//! components, so it's important to clearly understand how those are determined.
+//!
+//! A path can always be reconstructed into an equivalent path by putting
+//! together its components via `push`. Syntactically, the paths may differ by
+//! the normalization described below.
+//!
+//! ### Component types
+//!
+//! Components come in several types:
+//!
+//! * Normal components are the default: standard references to files or
+//! directories. The path `a/b` has two normal components, `a` and `b`.
+//!
+//! * Current directory components represent the `.` character. For example,
+//! `a/.` has a normal component `a` and a current directory component.
+//!
+//! * The root directory component represents a separator that designates
+//!   starting from root. For example, `/a/b` has a root directory component
+//!   followed by normal components `a` and `b`.
+//!
+//! On Windows, two additional component types come into play:
+//!
+//! * Prefix components, of which there is a large variety. For example, `C:`
+//! and `\\server\share` are prefixes. The path `C:windows` has a prefix
+//! component `C:` and a normal component `windows`; the path `C:\windows` has a
+//! prefix component `C:`, a root directory component, and a normal component
+//! `windows`.
+//!
+//! * Empty components, a special case for so-called "verbatim" paths where very
+//! little normalization is allowed. For example, `\\?\C:\` has a "verbatim"
+//! prefix `\\?\C:`, a root component, and an empty component (as a way of
+//! representing the trailing `\`. Such a trailing `\` is in fact the only
+//! situation in which an empty component is produced.
+//!
+//! ### Normalization
+//!
+//! Aside from splitting on the separator(s), there is a small amount of
+//! "normalization":
+//!
+//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a`
+//!   and `b`.
+//!
+//! * Paths ending in a separator are treated as if they has a current directory
+//!   component at the end (or, in verbatim paths, an empty component).  For
+//!   example, while `a/b` has components `a` and `b`, the paths `a/b/` and
+//!   `a/b/.` both have components `a`, `b`, and `.` (current directory).  The
+//!   reason for this normalization is that `a/b` and `a/b/` are treated
+//!   differently in some contexts, but `a/b/` and `a/b/.` are always treated
+//!   the same.
+//!
+//! No other normalization takes place by default. In particular, `a/./b/` and
+//! `a/b` are treated distinctly in terms of components, as are `a/c` and
+//! `a/b/../c`. Further normalization is possible to build on top of the
+//! components APIs, and will be included in this library very soon.
+
+#![unstable(feature = "path")]
+
+use core::prelude::*;
+
+use borrow::BorrowFrom;
+use cmp;
+use iter;
+use mem;
+use ops::{self, Deref};
+use string::CowString;
+use vec::Vec;
+use fmt;
+
+use ffi::{OsStr, OsString, AsOsStr};
+
+use self::platform::{is_sep, is_verbatim_sep, MAIN_SEP_STR, parse_prefix, Prefix};
+
+////////////////////////////////////////////////////////////////////////////////
+// GENERAL NOTES
+////////////////////////////////////////////////////////////////////////////////
+//
+// Parsing in this module is done by directly transmuting OsStr to [u8] slices,
+// taking advantage of the fact that OsStr always encodes ASCII characters
+// as-is.  Eventually, this transmutation should be replaced by direct uses of
+// OsStr APIs for parsing, but it will take a while for those to become
+// available.
+
+////////////////////////////////////////////////////////////////////////////////
+// Platform-specific definitions
+////////////////////////////////////////////////////////////////////////////////
+
+// The following modules give the most basic tools for parsing paths on various
+// platforms. The bulk of the code is devoted to parsing prefixes on Windows.
+
+#[cfg(unix)]
+mod platform {
+    use core::prelude::*;
+    use ffi::OsStr;
+
+    #[inline]
+    pub fn is_sep(b: u8) -> bool {
+        b == b'/'
+    }
+
+    #[inline]
+    pub fn is_verbatim_sep(b: u8) -> bool {
+        b == b'/'
+    }
+
+    pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
+        None
+    }
+
+    #[derive(Copy, Clone, Show, Hash, PartialEq, Eq)]
+    pub struct Prefix<'a>;
+
+    impl<'a> Prefix<'a> {
+        #[inline]
+        pub fn len(&self) -> usize { 0 }
+        #[inline]
+        pub fn is_verbatim(&self) -> bool { false }
+        #[inline]
+        pub fn is_drive(&self) -> bool { false }
+        #[inline]
+        pub fn has_implicit_root(&self) -> bool { false }
+    }
+
+    pub const MAIN_SEP_STR: &'static str = "/";
+}
+
+#[cfg(windows)]
+mod platform {
+    use core::prelude::*;
+
+    use super::{Path, os_str_as_u8_slice, u8_slice_as_os_str};
+    use ffi::OsStr;
+    use ascii::*;
+
+    #[inline]
+    pub fn is_sep(b: u8) -> bool {
+        b == b'/' || b == b'\\'
+    }
+
+    #[inline]
+    pub fn is_verbatim_sep(b: u8) -> bool {
+        b == b'\\'
+    }
+
+    pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
+        use self::Prefix::*;
+        unsafe {
+            // The unsafety here stems from converting between &OsStr and &[u8]
+            // and back. This is safe to do because (1) we only look at ASCII
+            // contents of the encoding and (2) new &OsStr values are produced
+            // only from ASCII-bounded slices of existing &OsStr values.
+            let mut path = os_str_as_u8_slice(path);
+
+            if path.starts_with(br"\\") {
+                // \\
+                path = &path[2..];
+                if path.starts_with(br"?\") {
+                    // \\?\
+                    path = &path[2..];
+                    if path.starts_with(br"UNC\") {
+                        // \\?\UNC\server\share
+                        path = &path[4..];
+                        let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
+                            Some((server, share)) => (u8_slice_as_os_str(server),
+                                                      u8_slice_as_os_str(share)),
+                            None => (u8_slice_as_os_str(path),
+                                     u8_slice_as_os_str(&[])),
+                        };
+                        return Some(VerbatimUNC(server, share));
+                    } else {
+                        // \\?\path
+                        let idx = path.position_elem(&b'\\');
+                        if idx == Some(2) && path[1] == b':' {
+                            let c = path[0];
+                            if c.is_ascii() && (c as char).is_alphabetic() {
+                                // \\?\C:\ path
+                                let slice = u8_slice_as_os_str(&path[0..1]);
+                                return Some(VerbatimDisk(slice));
+                            }
+                        }
+                        let slice = &path[.. idx.unwrap_or(path.len())];
+                        return Some(Verbatim(u8_slice_as_os_str(slice)));
+                    }
+                } else if path.starts_with(b".\\") {
+                    // \\.\path
+                    path = &path[2..];
+                    let slice = &path[.. path.position_elem(&b'\\').unwrap_or(path.len())];
+                    return Some(DeviceNS(u8_slice_as_os_str(slice)));
+                }
+                match parse_two_comps(path, is_sep) {
+                    Some((server, share)) if server.len() > 0 && share.len() > 0 => {
+                        // \\server\share
+                        return Some(UNC(u8_slice_as_os_str(server),
+                                        u8_slice_as_os_str(share)));
+                    }
+                    _ => ()
+                }
+            } else if path.len() > 1 && path[1] == b':' {
+                // C:
+                let c = path[0];
+                if c.is_ascii() && (c as char).is_alphabetic() {
+                    return Some(Disk(u8_slice_as_os_str(&path[0..1])));
+                }
+            }
+            return None;
+        }
+
+        fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
+            let first = match path.iter().position(|x| f(*x)) {
+                None => return None,
+                Some(x) => &path[.. x]
+            };
+            path = &path[(first.len()+1)..];
+            let idx = path.iter().position(|x| f(*x));
+            let second = &path[.. idx.unwrap_or(path.len())];
+            Some((first, second))
+        }
+    }
+
+    /// Windows path prefixes.
+    ///
+    /// Windows uses a variety of path styles, including references to drive
+    /// volumes (like `C:`), network shared (like `\\server\share`) and
+    /// others. In addition, some path prefixes are "verbatim", in which case
+    /// `/` is *not* treated as a separator and essentially no normalization is
+    /// performed.
+    #[derive(Copy, Clone, Debug, Hash, Eq)]
+    pub enum Prefix<'a> {
+        /// Prefix `\\?\`, together with the given component immediately following it.
+        Verbatim(&'a OsStr),
+
+        /// Prefix `\\?\UNC\`, with the "server" and "share" components following it.
+        VerbatimUNC(&'a OsStr, &'a OsStr),
+
+        /// Prefix like `\\?\C:\`, for the given drive letter
+        VerbatimDisk(&'a OsStr),
+
+        /// Prefix `\\.\`, together with the given component immediately following it.
+        DeviceNS(&'a OsStr),
+
+        /// Prefix `\\server\share`, with the given "server" and "share" components.
+        UNC(&'a OsStr, &'a OsStr),
+
+        /// Prefix `C:` for the given disk drive.
+        Disk(&'a OsStr),
+    }
+
+    impl<'a> Prefix<'a> {
+        #[inline]
+        pub fn len(&self) -> usize {
+            use self::Prefix::*;
+            fn os_str_len(s: &OsStr) -> usize {
+                unsafe { os_str_as_u8_slice(s).len() }
+            }
+            match *self {
+                Verbatim(x) => 4 + os_str_len(x),
+                VerbatimUNC(x,y) => 8 + os_str_len(x) +
+                    if os_str_len(y) > 0 { 1 + os_str_len(y) }
+                    else { 0 },
+                VerbatimDisk(_) => 6,
+                UNC(x,y) => 2 + os_str_len(x) +
+                    if os_str_len(y) > 0 { 1 + os_str_len(y) }
+                    else { 0 },
+                DeviceNS(x) => 4 + os_str_len(x),
+                Disk(_) => 2
+            }
+
+        }
+
+        #[inline]
+        pub fn is_verbatim(&self) -> bool {
+            use self::Prefix::*;
+            match *self {
+                Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true,
+                _ => false
+            }
+        }
+
+        #[inline]
+        pub fn is_drive(&self) -> bool {
+            match *self {
+                Prefix::Disk(_) => true,
+                _ => false,
+            }
+        }
+
+        #[inline]
+        pub fn has_implicit_root(&self) -> bool {
+            !self.is_drive()
+        }
+    }
+
+    impl<'a> ops::PartialEq for Prefix<'a> {
+        fn eq(&self, other: &Prefix<'a>) -> bool {
+            use self::Prefix::*;
+            match (*self, *other) {
+                (Verbatim(x), Verbatim(y)) => x == y,
+                (VerbatimUNC(x1, x2), Verbatim(y1, y2)) => x1 == y1 && x2 == y2,
+                (VerbatimDisk(x), VerbatimDisk(y)) =>
+                    os_str_as_u8_slice(x).eq_ignore_ascii_case(os_str_as_u8_slice(y)),
+                (DeviceNS(x), DeviceNS(y)) => x == y,
+                (UNC(x1, x2), UNC(y1, y2)) => x1 == y1 && x2 == y2,
+                (Disk(x), Disk(y)) =>
+                    os_str_as_u8_slice(x).eq_ignore_ascii_case(os_str_as_u8_slice(y)),
+                _ => false,
+            }
+        }
+    }
+
+    pub const MAIN_SEP_STR: &'static str = "\\";
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Misc helpers
+////////////////////////////////////////////////////////////////////////////////
+
+// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
+// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
+// `iter` after having exhausted `prefix`.
+fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I> where
+    I: Iterator<Item=A> + Clone, J: Iterator<Item=A>, A: PartialEq
+{
+    loop {
+        let mut iter_next = iter.clone();
+        match (iter_next.next(), prefix.next()) {
+            (Some(x), Some(y)) => {
+                if x != y { return None }
+            }
+            (Some(_), None) => return Some(iter),
+            (None, None) => return Some(iter),
+            (None, Some(_)) => return None,
+        }
+        iter = iter_next;
+    }
+}
+
+// See note at the top of this module to understand why these are used:
+fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
+    unsafe { mem::transmute(s) }
+}
+unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
+    mem::transmute(s)
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Cross-platform parsing
+////////////////////////////////////////////////////////////////////////////////
+
+/// Says whether the path ends in a separator character and therefore needs to
+/// be treated as if it ended with an additional `.`
+fn has_suffix(s: &[u8], prefix: Option<Prefix>) -> bool {
+    let (prefix_len, verbatim) = if let Some(p) = prefix {
+        (p.len(), p.is_verbatim())
+    } else { (0, false) };
+    if prefix_len > 0 && prefix_len == s.len() && !verbatim { return true; }
+    let mut splits = s[prefix_len..].split(|b| is_sep(*b));
+    let last = splits.next_back().unwrap();
+    let more = splits.next_back().is_some();
+    more && last == b""
+}
+
+/// Says whether the first byte after the prefix is a separator.
+fn has_physical_root(s: &[u8], prefix: Option<Prefix>) -> bool {
+    let path = if let Some(p) = prefix { &s[p.len()..] } else { s };
+    path.len() > 0 && is_sep(path[0])
+}
+
+fn parse_single_component(comp: &[u8]) -> Option<Component> {
+    match comp {
+        b"." => Some(Component::CurDir),
+        b".." => Some(Component::ParentDir),
+        b"" => None,
+        _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) }))
+    }
+}
+
+// basic workhorse for splitting stem and extension
+#[allow(unused_unsafe)] // FIXME
+fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
+    unsafe {
+        if os_str_as_u8_slice(file) == b".." { return (Some(file), None) }
+
+        // The unsafety here stems from converting between &OsStr and &[u8]
+        // and back. This is safe to do because (1) we only look at ASCII
+        // contents of the encoding and (2) new &OsStr values are produced
+        // only from ASCII-bounded slices of existing &OsStr values.
+
+        let mut iter = os_str_as_u8_slice(file).rsplitn(1, |b| *b == b'.');
+        let after = iter.next();
+        let before = iter.next();
+        if before == Some(b"") {
+            (Some(file), None)
+        } else {
+            (before.map(|s| u8_slice_as_os_str(s)),
+             after.map(|s| u8_slice_as_os_str(s)))
+        }
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// The core iterators
+////////////////////////////////////////////////////////////////////////////////
+
+/// Component parsing works by a double-ended state machine; the cursors at the
+/// front and back of the path each keep track of what parts of the path have
+/// been consumed so far.
+///
+/// Going front to back, a path is made up of a prefix, a root component, a body
+/// (of normal components), and a suffix/emptycomponent (normalized `.` or ``
+/// for a path ending with the separator)
+#[derive(Copy, Clone, PartialEq, PartialOrd, Show)]
+enum State {
+    Prefix = 0,         // c:
+    Root = 1,           // /
+    Body = 2,           // foo/bar/baz
+    Suffix = 3,         // .
+    Done = 4,
+}
+
+/// A single component of a path.
+///
+/// See the module documentation for an in-depth explanation of components and
+/// their role in the API.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Show)]
+pub enum Component<'a> {
+    /// A Windows path prefix, e.g. `C:` or `\server\share`
+    Prefix(&'a OsStr),
+
+    /// An empty component. Only used on Windows for the last component of
+    /// verbatim paths ending with a separator (e.g. the last component of
+    /// `\\?\C:\windows\` but not `\\?\C:\windows` or `C:\windows`).
+    Empty,
+
+    /// The root directory component, appears after any prefix and before anything else
+    RootDir,
+
+    /// A reference to the current directory, i.e. `.`
+    CurDir,
+
+    /// A reference to the parent directory, i.e. `..`
+    ParentDir,
+
+    /// A normal component, i.e. `a` and `b` in `a/b`
+    Normal(&'a OsStr),
+}
+
+impl<'a> Component<'a> {
+    /// Extract the underlying `OsStr` slice
+    pub fn as_os_str(self) -> &'a OsStr {
+        match self {
+            Component::Prefix(path) => path,
+            Component::Empty => OsStr::from_str(""),
+            Component::RootDir => OsStr::from_str(MAIN_SEP_STR),
+            Component::CurDir => OsStr::from_str("."),
+            Component::ParentDir => OsStr::from_str(".."),
+            Component::Normal(path) => path,
+        }
+    }
+}
+
+/// The core iterator giving the components of a path.
+///
+/// See the module documentation for an in-depth explanation of components and
+/// their role in the API.
+#[derive(Clone)]
+pub struct Components<'a> {
+    // The path left to parse components from
+    path: &'a [u8],
+
+    // The prefix as it was originally parsed, if any
+    prefix: Option<Prefix<'a>>,
+
+    // true if path *physically* has a root separator; for most Windows
+    // prefixes, it may have a "logical" rootseparator for the purposes of
+    // normalization, e.g.  \\server\share == \\server\share\.
+    has_physical_root: bool,
+
+    // The iterator is double-ended, and these two states keep track of what has
+    // been produced from either end
+    front: State,
+    back: State,
+}
+
+/// An iterator over the components of a path, as `OsStr` slices.
+#[derive(Clone)]
+pub struct Iter<'a> {
+    inner: Components<'a>
+}
+
+impl<'a> Components<'a> {
+    // how long is the prefix, if any?
+    #[inline]
+    fn prefix_len(&self) -> usize {
+        self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
+    }
+
+    #[inline]
+    fn prefix_verbatim(&self) -> bool {
+        self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
+    }
+
+    /// how much of the prefix is left from the point of view of iteration?
+    #[inline]
+    fn prefix_remaining(&self) -> usize {
+        if self.front == State::Prefix { self.prefix_len() }
+        else { 0 }
+    }
+
+    fn prefix_and_root(&self) -> usize {
+        let root = if self.front <= State::Root && self.has_physical_root { 1 } else { 0 };
+        self.prefix_remaining() + root
+    }
+
+    // is the iteration complete?
+    #[inline]
+    fn finished(&self) -> bool {
+        self.front == State::Done || self.back == State::Done || self.front > self.back
+    }
+
+    #[inline]
+    fn is_sep(&self, b: u8) -> bool {
+        if self.prefix_verbatim() {
+            is_verbatim_sep(b)
+        } else {
+            is_sep(b)
+        }
+    }
+
+    /// Extract a slice corresponding to the portion of the path remaining for iteration.
+    pub fn as_path(&self) -> &'a Path {
+        let mut comps = self.clone();
+        if comps.front == State::Body { comps.trim_left(); }
+        if comps.back == State::Body { comps.trim_right(); }
+        if comps.path.is_empty() && comps.front < comps.back && comps.back == State::Suffix {
+            Path::new(".")
+        } else {
+            unsafe { Path::from_u8_slice(comps.path) }
+        }
+    }
+
+    /// Is the *original* path rooted?
+    fn has_root(&self) -> bool {
+        if self.has_physical_root { return true }
+        if let Some(p) = self.prefix {
+            if p.has_implicit_root() { return true }
+        }
+        false
+    }
+
+    // parse a component from the left, saying how many bytes to consume to
+    // remove the component
+    fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
+        debug_assert!(self.front == State::Body);
+        let (extra, comp) = match self.path.iter().position(|b| self.is_sep(*b)) {
+            None => (0, self.path),
+            Some(i) => (1, &self.path[.. i]),
+        };
+        (comp.len() + extra, parse_single_component(comp))
+    }
+
+    // parse a component from the right, saying how many bytes to consume to
+    // remove the component
+    fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
+        debug_assert!(self.back == State::Body);
+        let start = self.prefix_and_root();
+        let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep(*b)) {
+            None => (0, &self.path[start ..]),
+            Some(i) => (1, &self.path[start + i + 1 ..]),
+        };
+        (comp.len() + extra, parse_single_component(comp))
+    }
+
+    // trim away repeated separators (i.e. emtpy components) on the left
+    fn trim_left(&mut self) {
+        while !self.path.is_empty() {
+            let (size, comp) = self.parse_next_component();
+            if comp.is_some() {
+                return;
+            } else {
+                self.path = &self.path[size ..];
+            }
+        }
+    }
+
+    // trim away repeated separators (i.e. emtpy components) on the right
+    fn trim_right(&mut self) {
+        while self.path.len() > self.prefix_and_root() {
+            let (size, comp) = self.parse_next_component_back();
+            if comp.is_some() {
+                return;
+            } else {
+                self.path = &self.path[.. self.path.len() - size];
+            }
+        }
+    }
+
+    /// Examine the next component without consuming it.
+    pub fn peek(&self) -> Option<Component<'a>> {
+        self.clone().next()
+    }
+}
+
+impl<'a> Iter<'a> {
+    /// Extract a slice corresponding to the portion of the path remaining for iteration.
+    pub fn as_path(&self) -> &'a Path {
+        self.inner.as_path()
+    }
+}
+
+impl<'a> Iterator for Iter<'a> {
+    type Item = &'a OsStr;
+
+    fn next(&mut self) -> Option<&'a OsStr> {
+        self.inner.next().map(Component::as_os_str)
+    }
+}
+
+impl<'a> DoubleEndedIterator for Iter<'a> {
+    fn next_back(&mut self) -> Option<&'a OsStr> {
+        self.inner.next_back().map(Component::as_os_str)
+    }
+}
+
+impl<'a> Iterator for Components<'a> {
+    type Item = Component<'a>;
+
+    fn next(&mut self) -> Option<Component<'a>> {
+        while !self.finished() {
+            match self.front {
+                State::Prefix if self.prefix_len() > 0 => {
+                    self.front = State::Root;
+                    debug_assert!(self.prefix_len() <= self.path.len());
+                    let prefix = &self.path[.. self.prefix_len()];
+                    self.path = &self.path[self.prefix_len() .. ];
+                    return Some(Component::Prefix(unsafe { u8_slice_as_os_str(prefix) }))
+                }
+                State::Prefix => {
+                    self.front = State::Root;
+                }
+                State::Root => {
+                    self.front = State::Body;
+                    if self.has_physical_root {
+                        debug_assert!(self.path.len() > 0);
+                        self.path = &self.path[1..];
+                        return Some(Component::RootDir)
+                    } else if let Some(p) = self.prefix {
+                        if p.has_implicit_root() && !p.is_verbatim() {
+                            return Some(Component::RootDir)
+                        }
+                    }
+                }
+                State::Body if !self.path.is_empty() => {
+                    let (size, comp) = self.parse_next_component();
+                    self.path = &self.path[size ..];
+                    if comp.is_some() { return comp }
+                }
+                State::Body => {
+                    self.front = State::Suffix;
+                }
+                State::Suffix => {
+                    self.front = State::Done;
+                    if self.prefix_verbatim() {
+                        return Some(Component::Empty)
+                    } else {
+                        return Some(Component::CurDir)
+                    }
+                }
+                State::Done => unreachable!()
+            }
+        }
+        None
+    }
+}
+
+impl<'a> DoubleEndedIterator for Components<'a> {
+    fn next_back(&mut self) -> Option<Component<'a>> {
+        while !self.finished() {
+            match self.back {
+                State::Suffix => {
+                    self.back = State::Body;
+                    if self.prefix_verbatim() {
+                        return Some(Component::Empty)
+                    } else {
+                        return Some(Component::CurDir)
+                    }
+                }
+                State::Body if self.path.len() > self.prefix_and_root() => {
+                    let (size, comp) = self.parse_next_component_back();
+                    self.path = &self.path[.. self.path.len() - size];
+                    if comp.is_some() { return comp }
+                }
+                State::Body => {
+                    self.back = State::Root;
+                }
+                State::Root => {
+                    self.back = State::Prefix;
+                    if self.has_physical_root {
+                        self.path = &self.path[.. self.path.len() - 1];
+                        return Some(Component::RootDir)
+                    } else if let Some(p) = self.prefix {
+                        if p.has_implicit_root() && !p.is_verbatim() {
+                            return Some(Component::RootDir)
+                        }
+                    }
+                }
+                State::Prefix if self.prefix_len() > 0 => {
+                    self.back = State::Done;
+                    return Some(Component::Prefix(unsafe {
+                        u8_slice_as_os_str(self.path)
+                    }))
+                }
+                State::Prefix => {
+                    self.back = State::Done;
+                    return None
+                }
+                State::Done => unreachable!()
+            }
+        }
+        None
+    }
+}
+
+fn optional_path(path: &Path) -> Option<&Path> {
+    if path.as_u8_slice().is_empty() { None } else { Some(path) }
+}
+
+impl<'a> cmp::PartialEq for Components<'a> {
+    fn eq(&self, other: &Components<'a>) -> bool {
+        iter::order::eq(self.clone(), other.clone())
+    }
+}
+
+impl<'a> cmp::Eq for Components<'a> {}
+
+impl<'a> cmp::PartialOrd for Components<'a> {
+    fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
+        iter::order::partial_cmp(self.clone(), other.clone())
+    }
+}
+
+impl<'a> cmp::Ord for Components<'a> {
+    fn cmp(&self, other: &Components<'a>) -> cmp::Ordering {
+        iter::order::cmp(self.clone(), other.clone())
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Basic types and traits
+////////////////////////////////////////////////////////////////////////////////
+
+/// An owned, mutable path (akin to `String`).
+///
+/// This type provides methods like `push` and `set_extension` that mutate the
+/// path in place. It also implements `Deref` to `Path`, meaning that all
+/// methods on `Path` slices are available on `PathBuf` values as well.
+///
+/// More details about the overall approach can be found in
+/// the module documentation.
+///
+/// # Example
+///
+/// ```rust
+/// use std::path::PathBuf;
+///
+/// let mut path = PathBuf::new("c:\\");
+/// path.push("windows");
+/// path.push("system32");
+/// path.set_extension("dll");
+/// ```
+#[derive(Clone, Hash)]
+pub struct PathBuf {
+    inner: OsString
+}
+
+impl PathBuf {
+    fn as_mut_vec(&mut self) -> &mut Vec<u8> {
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Allocate a `PathBuf` with initial contents given by the
+    /// argument.
+    pub fn new<S: ?Sized + AsOsStr>(s: &S) -> PathBuf {
+        PathBuf { inner: s.as_os_str().to_os_string() }
+    }
+
+    /// Extend `self` with `path`.
+    ///
+    /// If `path` is absolute, it replaces the current path.
+    ///
+    /// On Windows:
+    ///
+    /// * if `path` has a root but no prefix (e.g. `\windows`), it
+    ///   replaces everything except for the prefix (if any) of `self`.
+    /// * if `path` has a prefix but no root, it replaces `self.
+    pub fn push<P: ?Sized>(&mut self, path: &P) where P: AsPath {
+        // in general, a separator is needed if the rightmost byte is not a separator
+        let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep(*c)).unwrap_or(false);
+
+        // in the special case of `C:` on Windows, do *not* add a separator
+        {
+            let comps = self.components();
+            if comps.prefix_len() > 0 &&
+                comps.prefix_len() == comps.path.len() &&
+                comps.prefix.unwrap().is_drive()
+            {
+                need_sep = false
+            }
+        }
+
+        let path = path.as_path();
+
+        // absolute `path` replaces `self`
+        if path.is_absolute() || path.prefix().is_some() {
+            self.as_mut_vec().truncate(0);
+
+        // `path` has a root but no prefix, e.g. `\windows` (Windows only)
+        } else if path.has_root() {
+            let prefix_len = self.components().prefix_remaining();
+            self.as_mut_vec().truncate(prefix_len);
+
+        // `path` is a pure relative path
+        } else if need_sep {
+            self.inner.push_os_str(OsStr::from_str(MAIN_SEP_STR));
+        }
+
+        self.inner.push_os_str(path.as_os_str());
+    }
+
+    /// Truncate `self` to `self.parent()`.
+    ///
+    /// Returns `None` and does nothing if `self.parent()` is `None`.
+    pub fn pop(&mut self) -> bool {
+        match self.parent().map(|p| p.as_u8_slice().len()) {
+            Some(len) => {
+                self.as_mut_vec().truncate(len);
+                true
+            }
+            None => false
+        }
+    }
+
+    /// Updates `self.file_name()` to `file_name`.
+    ///
+    /// If `self.file_name()` was `None`, this is equivalent to pushing
+    /// `file_name`.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use std::path::{Path, PathBuf};
+    ///
+    /// let mut buf = PathBuf::new("/foo/");
+    /// assert!(buf.file_name() == None);
+    /// buf.set_file_name("bar");
+    /// assert!(buf == PathBuf::new("/foo/bar"));
+    /// assert!(buf.file_name().is_some());
+    /// buf.set_file_name("baz.txt");
+    /// assert!(buf == PathBuf::new("/foo/baz.txt"));
+    /// ```
+    pub fn set_file_name<S: ?Sized>(&mut self, file_name: &S) where S: AsOsStr {
+        if self.file_name().is_some() && !self.pop() {
+            // Given that there is a file name, this is reachable only for
+            // Windows paths like c:file or paths like `foo`, but not `c:\` or
+            // `/`.
+            let prefix_len = self.components().prefix_remaining();
+            self.as_mut_vec().truncate(prefix_len);
+        }
+        self.push(file_name.as_os_str());
+    }
+
+    /// Updates `self.extension()` to `extension`.
+    ///
+    /// If `self.file_name()` is `None`, does nothing and returns `false`.
+    ///
+    /// Otherwise, returns `tru`; if `self.exension()` is `None`, the extension
+    /// is added; otherwise it is replaced.
+    pub fn set_extension<S: ?Sized + AsOsStr>(&mut self, extension: &S) -> bool {
+        if self.file_name().is_none() { return false; }
+
+        let mut stem = match self.file_stem() {
+            Some(stem) => stem.to_os_string(),
+            None => OsString::from_str(""),
+        };
+
+        let extension = extension.as_os_str();
+        if os_str_as_u8_slice(extension).len() > 0 {
+            stem.push_os_str(OsStr::from_str("."));
+            stem.push_os_str(extension.as_os_str());
+        }
+        self.set_file_name(&stem);
+
+        true
+    }
+}
+
+impl<'a, P: ?Sized + 'a> iter::FromIterator<&'a P> for PathBuf where P: AsPath {
+    fn from_iter<I: Iterator<Item = &'a P>>(iter: I) -> PathBuf {
+        let mut buf = PathBuf::new("");
+        buf.extend(iter);
+        buf
+    }
+}
+
+impl<'a, P: ?Sized + 'a> iter::Extend<&'a P> for PathBuf where P: AsPath {
+    fn extend<I: Iterator<Item = &'a P>>(&mut self, iter: I) {
+        for p in iter {
+            self.push(p)
+        }
+    }
+}
+
+impl fmt::Debug for PathBuf {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        fmt::Debug::fmt(&**self, formatter)
+    }
+}
+
+impl ops::Deref for PathBuf {
+    type Target = Path;
+
+    fn deref(&self) -> &Path {
+        unsafe { mem::transmute(&self.inner[]) }
+    }
+}
+
+impl BorrowFrom<PathBuf> for Path {
+    fn borrow_from(owned: &PathBuf) -> &Path {
+        owned.deref()
+    }
+}
+
+impl cmp::PartialEq for PathBuf {
+    fn eq(&self, other: &PathBuf) -> bool {
+        self.components() == other.components()
+    }
+}
+
+impl cmp::Eq for PathBuf {}
+
+impl cmp::PartialOrd for PathBuf {
+    fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
+        self.components().partial_cmp(&other.components())
+    }
+}
+
+impl cmp::Ord for PathBuf {
+    fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
+        self.components().cmp(&other.components())
+    }
+}
+
+/// A slice of a path (akin to `str`).
+///
+/// This type supports a number of operations for inspecting a path, including
+/// breaking the path into its components (separated by `/` or `\`, depending on
+/// the platform), extracting the file name, determining whether the path is
+/// absolute, and so on. More details about the overall approach can be found in
+/// the module documentation.
+///
+/// This is an *unsized* type, meaning that it must always be used with behind a
+/// pointer like `&` or `Box`.
+///
+/// # Example
+///
+/// ```rust
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo/bar.txt");
+/// let file = path.file_name();
+/// let extension = path.extension();
+/// let parent_dir = path.parent();
+/// ```
+///
+pub struct Path {
+    inner: OsStr
+}
+
+impl Path {
+    // The following (private!) function allows construction of a path from a u8
+    // slice, which is only safe when it is known to follow the OsStr encoding.
+    unsafe fn from_u8_slice(s: &[u8]) -> &Path {
+        mem::transmute(s)
+    }
+    // The following (private!) function reveals the byte encoding used for OsStr.
+    fn as_u8_slice(&self) -> &[u8] {
+        unsafe { mem::transmute(self) }
+    }
+
+    /// Directly wrap a string slice as a `Path` slice.
+    ///
+    /// This is a cost-free conversion.
+    pub fn new<S: ?Sized + AsOsStr>(s: &S) -> &Path {
+        unsafe { mem::transmute(s.as_os_str()) }
+    }
+
+    /// Yield a `&str` slice if the `Path` is valid unicode.
+    ///
+    /// This conversion may entail doing a check for UTF-8 validity.
+    pub fn to_str(&self) -> Option<&str> {
+        self.inner.to_str()
+    }
+
+    /// Convert a `Path` to a `CowString`.
+    ///
+    /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
+    pub fn to_string_lossy(&self) -> CowString {
+        self.inner.to_string_lossy()
+    }
+
+    /// Convert a `Path` to an owned `PathBuf`.
+    pub fn to_path_buf(&self) -> PathBuf {
+        PathBuf::new(self)
+    }
+
+    /// A path is *absolute* if it is indepedent of the current directory.
+    ///
+    /// * On Unix, a path is absolute if it starts with the root, so
+    /// `is_absolute` and `has_root` are equivalent.
+    ///
+    /// * On Windows, a path is absolute if it has a prefix and starts with the
+    /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In
+    /// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`.
+    pub fn is_absolute(&self) -> bool {
+        self.has_root() &&
+            (cfg!(unix) || self.prefix().is_some())
+    }
+
+    /// A path is *relative* if it is not absolute.
+    pub fn is_relative(&self) -> bool {
+        !self.is_absolute()
+    }
+
+    /// Returns the *prefix* of a path, if any.
+    ///
+    /// Prefixes are relevant only for Windows paths, and consist of volumes
+    /// like `C:`, UNC prefixes like `\\server`, and others described in more
+    /// detail in `std::os::windows::PathExt`.
+    pub fn prefix(&self) -> Option<&Path> {
+        let iter = self.components();
+        optional_path(unsafe {
+            Path::from_u8_slice(
+                &self.as_u8_slice()[.. iter.prefix_remaining()])
+        })
+    }
+
+    /// A path has a root if the body of the path begins with the directory separator.
+    ///
+    /// * On Unix, a path has a root if it begins with `/`.
+    ///
+    /// * On Windows, a path has a root if it:
+    ///     * has no prefix and begins with a separator, e.g. `\\windows`
+    ///     * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows`
+    ///     * has any non-disk prefix, e.g. `\\server\share`
+    pub fn has_root(&self) -> bool {
+         self.components().has_root()
+    }
+
+    /// The path without its final component.
+    ///
+    /// Does nothing, returning `None` if the path consists of just a prefix
+    /// and/or root directory reference.
+    ///
+    /// # Examples
+    ///
+    /// ```rust
+    /// use std::path::Path;
+    ///
+    /// let path = Path::new("/foo/bar");
+    /// let foo = path.parent().unwrap();
+    /// assert!(foo == Path::new("/foo"));
+    /// let root = foo.parent().unwrap();
+    /// assert!(root == Path::new("/"));
+    /// assert!(root.parent() == None);
+    /// ```
+    pub fn parent(&self) -> Option<&Path> {
+        let mut comps = self.components();
+        let comp = comps.next_back();
+        let rest = optional_path(comps.as_path());
+
+        match (comp, comps.next_back()) {
+            (Some(Component::CurDir), Some(Component::RootDir)) => None,
+            (Some(Component::CurDir), Some(Component::Prefix(_))) => None,
+            (Some(Component::Empty), Some(Component::RootDir)) => None,
+            (Some(Component::Empty), Some(Component::Prefix(_))) => None,
+            (Some(Component::Prefix(_)), None) => None,
+            (Some(Component::RootDir), Some(Component::Prefix(_))) => None,
+            _ => rest
+        }
+    }
+
+    /// The final component of the path, if it is a normal file.
+    ///
+    /// If the path terminates in `.`, `..`, or consists solely or a root of
+    /// prefix, `file` will return `None`.
+    pub fn file_name(&self) -> Option<&OsStr> {
+        self.components().next_back().and_then(|p| match p {
+            Component::Normal(p) => Some(p.as_os_str()),
+            _ => None
+        })
+    }
+
+    /// Returns a path that, when joined onto `base`, yields `self`.
+    pub fn relative_from<'a, P: ?Sized>(&'a self, base: &'a P) -> Option<&Path> where
+        P: AsPath
+    {
+        iter_after(self.components(), base.as_path().components()).map(|c| c.as_path())
+    }
+
+    /// Determines whether `base` is a prefix of `self`.
+    pub fn starts_with<P: ?Sized>(&self, base: &P) -> bool where P: AsPath {
+        iter_after(self.components(), base.as_path().components()).is_some()
+    }
+
+    /// Determines whether `base` is a suffix of `self`.
+    pub fn ends_with<P: ?Sized>(&self, child: &P) -> bool where P: AsPath {
+        iter_after(self.components().rev(), child.as_path().components().rev()).is_some()
+    }
+
+    /// Extract the stem (non-extension) portion of `self.file()`.
+    ///
+    /// The stem is:
+    ///
+    /// * None, if there is no file name;
+    /// * The entire file name if there is no embedded `.`;
+    /// * The entire file name if the file name begins with `.` and has no other `.`s within;
+    /// * Otherwise, the portion of the file name before the final `.`
+    pub fn file_stem(&self) -> Option<&OsStr> {
+        self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
+    }
+
+    /// Extract the extension of `self.file()`, if possible.
+    ///
+    /// The extension is:
+    ///
+    /// * None, if there is no file name;
+    /// * None, if there is no embedded `.`;
+    /// * None, if the file name begins with `.` and has no other `.`s within;
+    /// * Otherwise, the portion of the file name after the final `.`
+    pub fn extension(&self) -> Option<&OsStr> {
+        self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
+    }
+
+    /// Creates an owned `PathBuf` with `path` adjoined to `self`.
+    ///
+    /// See `PathBuf::push` for more details on what it means to adjoin a path.
+    pub fn join<P: ?Sized>(&self, path: &P) -> PathBuf where P: AsPath {
+        let mut buf = self.to_path_buf();
+        buf.push(path);
+        buf
+    }
+
+    /// Creates an owned `PathBuf` like `self` but with the given file name.
+    ///
+    /// See `PathBuf::set_file_name` for more details.
+    pub fn with_file_name<S: ?Sized>(&self, file_name: &S) -> PathBuf where S: AsOsStr {
+        let mut buf = self.to_path_buf();
+        buf.set_file_name(file_name);
+        buf
+    }
+
+    /// Creates an owned `PathBuf` like `self` but with the given extension.
+    ///
+    /// See `PathBuf::set_extension` for more details.
+    pub fn with_extension<S: ?Sized>(&self, extension: &S) -> PathBuf where S: AsOsStr {
+        let mut buf = self.to_path_buf();
+        buf.set_extension(extension);
+        buf
+    }
+
+    /// Produce an iterator over the components of the path.
+    pub fn components(&self) -> Components {
+        let prefix = parse_prefix(self.as_os_str());
+        Components {
+            path: self.as_u8_slice(),
+            prefix: prefix,
+            has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
+            front: State::Prefix,
+            back: if has_suffix(self.as_u8_slice(), prefix) { State::Suffix }
+                  else { State::Body },
+        }
+    }
+
+    /// Produce an iterator over the path's components viewed as `OsStr` slices.
+    pub fn iter(&self) -> Iter {
+        Iter { inner: self.components() }
+    }
+
+    /// Returns an object that implements `Display` for safely printing paths
+    /// that may contain non-Unicode data.
+    pub fn display(&self) -> Display {
+        Display { path: self }
+    }
+}
+
+impl AsOsStr for Path {
+    fn as_os_str(&self) -> &OsStr {
+        &self.inner
+    }
+}
+
+impl fmt::Debug for Path {
+    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
+        self.inner.fmt(formatter)
+    }
+}
+
+/// Helper struct for safely printing paths with `format!()` and `{}`
+pub struct Display<'a> {
+    path: &'a Path
+}
+
+impl<'a> fmt::Debug for Display<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Debug::fmt(&self.path.to_string_lossy(), f)
+    }
+}
+
+impl<'a> fmt::Display for Display<'a> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        fmt::Display::fmt(&self.path.to_string_lossy(), f)
+    }
+}
+
+impl cmp::PartialEq for Path {
+    fn eq(&self, other: &Path) -> bool {
+        iter::order::eq(self.components(), other.components())
+    }
+}
+
+impl cmp::Eq for Path {}
+
+impl cmp::PartialOrd for Path {
+    fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
+        self.components().partial_cmp(&other.components())
+    }
+}
+
+impl cmp::Ord for Path {
+    fn cmp(&self, other: &Path) -> cmp::Ordering {
+        self.components().cmp(&other.components())
+    }
+}
+
+/// Freely convertible to a `Path`.
+pub trait AsPath {
+    /// Convert to a `Path`.
+    fn as_path(&self) -> &Path;
+}
+
+impl<T: AsOsStr + ?Sized> AsPath for T {
+    fn as_path(&self) -> &Path { Path::new(self.as_os_str()) }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    use ffi::OsStr;
+    use core::prelude::*;
+    use string::{ToString, String};
+    use vec::Vec;
+
+    macro_rules! t(
+        ($path:expr, iter: $iter:expr) => (
+            {
+                let path = Path::new($path);
+
+                // Forward iteration
+                let comps = path.iter()
+                    .map(|p| p.to_string_lossy().into_owned())
+                    .collect::<Vec<String>>();
+                let exp: &[&str] = &$iter;
+                let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
+                assert!(comps == exps, "iter: Expected {:?}, found {:?}",
+                        exps, comps);
+
+                // Reverse iteration
+                let comps = Path::new($path).iter().rev()
+                    .map(|p| p.to_string_lossy().into_owned())
+                    .collect::<Vec<String>>();
+                let exps = exps.into_iter().rev().collect::<Vec<String>>();
+                assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
+                        exps, comps);
+            }
+        );
+
+        ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
+            {
+                let path = Path::new($path);
+
+                let act_root = path.has_root();
+                assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
+                        $has_root, act_root);
+
+                let act_abs = path.is_absolute();
+                assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
+                        $is_absolute, act_abs);
+            }
+        );
+
+        ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
+            {
+                let path = Path::new($path);
+
+                let parent = path.parent().map(|p| p.to_str().unwrap());
+                let exp_parent: Option<&str> = $parent;
+                assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
+                        exp_parent, parent);
+
+                let file = path.file_name().map(|p| p.to_str().unwrap());
+                let exp_file: Option<&str> = $file;
+                assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
+                        exp_file, file);
+            }
+        );
+
+        ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
+            {
+                let path = Path::new($path);
+
+                let stem = path.file_stem().map(|p| p.to_str().unwrap());
+                let exp_stem: Option<&str> = $file_stem;
+                assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
+                        exp_stem, stem);
+
+                let ext = path.extension().map(|p| p.to_str().unwrap());
+                let exp_ext: Option<&str> = $extension;
+                assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
+                        exp_ext, ext);
+            }
+        );
+
+        ($path:expr, iter: $iter:expr,
+                     has_root: $has_root:expr, is_absolute: $is_absolute:expr,
+                     parent: $parent:expr, file_name: $file:expr,
+                     file_stem: $file_stem:expr, extension: $extension:expr) => (
+            {
+                t!($path, iter: $iter);
+                t!($path, has_root: $has_root, is_absolute: $is_absolute);
+                t!($path, parent: $parent, file_name: $file);
+                t!($path, file_stem: $file_stem, extension: $extension);
+            }
+        );
+    );
+
+    #[test]
+    #[cfg(unix)]
+    pub fn test_decompositions_unix() {
+        t!("",
+           iter: [],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo",
+           iter: ["foo"],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: Some("foo"),
+           file_stem: Some("foo"),
+           extension: None
+           );
+
+        t!("/",
+           iter: ["/", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/foo",
+           iter: ["/", "foo"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("/"),
+           file_name: Some("foo"),
+           file_stem: Some("foo"),
+           extension: None
+           );
+
+        t!("foo/",
+           iter: ["foo", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/foo/",
+           iter: ["/", "foo", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("/foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/bar",
+           iter: ["foo", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("/foo/bar",
+           iter: ["/", "foo", "bar"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("/foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("///foo///",
+           iter: ["/", "foo", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("///foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("///foo///bar",
+           iter: ["/", "foo", "bar"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("///foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("./.",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("./.",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/..",
+           iter: ["/", ".."],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("/"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("../",
+           iter: ["..", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some(".."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/.",
+           iter: ["foo", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/..",
+           iter: ["foo", ".."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/./",
+           iter: ["foo", ".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/./bar",
+           iter: ["foo", ".", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/."),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("foo/../",
+           iter: ["foo", "..", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/.."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/../bar",
+           iter: ["foo", "..", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/.."),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("./a",
+           iter: [".", "a"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: Some("a"),
+           file_stem: Some("a"),
+           extension: None
+           );
+
+        t!(".",
+           iter: ["."],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("./",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("a/b",
+           iter: ["a", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a"),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a//b",
+           iter: ["a", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a"),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a/./b",
+           iter: ["a", ".", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a/."),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a/b/c",
+           iter: ["a", "b", "c"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a/b"),
+           file_name: Some("c"),
+           file_stem: Some("c"),
+           extension: None
+           );
+    }
+
+    #[test]
+    #[cfg(windows)]
+    pub fn test_decompositions_windows() {
+        t!("",
+           iter: [],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo",
+           iter: ["foo"],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: Some("foo"),
+           file_stem: Some("foo"),
+           extension: None
+           );
+
+        t!("/",
+           iter: ["\\", "."],
+           has_root: true,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\",
+           iter: ["\\", "."],
+           has_root: true,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("c:",
+           iter: ["c:", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("c:\\",
+           iter: ["c:", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("c:\\",
+           iter: ["c:", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("c:/",
+           iter: ["c:", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/foo",
+           iter: ["\\", "foo"],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("/"),
+           file_name: Some("foo"),
+           file_stem: Some("foo"),
+           extension: None
+           );
+
+        t!("foo/",
+           iter: ["foo", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/foo/",
+           iter: ["\\", "foo", "."],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("/foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/bar",
+           iter: ["foo", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("/foo/bar",
+           iter: ["\\", "foo", "bar"],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("/foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("///foo///",
+           iter: ["\\", "foo", "."],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("///foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("///foo///bar",
+           iter: ["\\", "foo", "bar"],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("///foo"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("./.",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("./.",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("/..",
+           iter: ["\\", ".."],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("/"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("../",
+           iter: ["..", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some(".."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/.",
+           iter: ["foo", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/..",
+           iter: ["foo", ".."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/./",
+           iter: ["foo", ".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/./bar",
+           iter: ["foo", ".", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/."),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("foo/../",
+           iter: ["foo", "..", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/.."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("foo/../bar",
+           iter: ["foo", "..", "bar"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("foo/.."),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+        t!("./a",
+           iter: [".", "a"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: Some("a"),
+           file_stem: Some("a"),
+           extension: None
+           );
+
+        t!(".",
+           iter: ["."],
+           has_root: false,
+           is_absolute: false,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("./",
+           iter: [".", "."],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("."),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("a/b",
+           iter: ["a", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a"),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a//b",
+           iter: ["a", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a"),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a/./b",
+           iter: ["a", ".", "b"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a/."),
+           file_name: Some("b"),
+           file_stem: Some("b"),
+           extension: None
+           );
+
+        t!("a/b/c",
+           iter: ["a", "b", "c"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a/b"),
+           file_name: Some("c"),
+           file_stem: Some("c"),
+           extension: None);
+
+        t!("a\\b\\c",
+           iter: ["a", "b", "c"],
+           has_root: false,
+           is_absolute: false,
+           parent: Some("a\\b"),
+           file_name: Some("c"),
+           file_stem: Some("c"),
+           extension: None
+           );
+
+        t!("\\a",
+           iter: ["\\", "a"],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("\\"),
+           file_name: Some("a"),
+           file_stem: Some("a"),
+           extension: None
+           );
+
+        t!("c:\\foo.txt",
+           iter: ["c:", "\\", "foo.txt"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("c:\\"),
+           file_name: Some("foo.txt"),
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+        t!("\\\\server\\share\\foo.txt",
+           iter: ["\\\\server\\share", "\\", "foo.txt"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\server\\share\\"),
+           file_name: Some("foo.txt"),
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+        t!("\\\\server\\share",
+           iter: ["\\\\server\\share", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\server",
+           iter: ["\\", "server"],
+           has_root: true,
+           is_absolute: false,
+           parent: Some("\\"),
+           file_name: Some("server"),
+           file_stem: Some("server"),
+           extension: None
+           );
+
+        t!("\\\\?\\bar\\foo.txt",
+           iter: ["\\\\?\\bar", "\\", "foo.txt"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\?\\bar\\"),
+           file_name: Some("foo.txt"),
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+        t!("\\\\?\\bar",
+           iter: ["\\\\?\\bar"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\?\\",
+           iter: ["\\\\?\\"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\?\\UNC\\server\\share\\foo.txt",
+           iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\?\\UNC\\server\\share\\"),
+           file_name: Some("foo.txt"),
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+        t!("\\\\?\\UNC\\server",
+           iter: ["\\\\?\\UNC\\server"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\?\\UNC\\",
+           iter: ["\\\\?\\UNC\\"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\?\\C:\\foo.txt",
+           iter: ["\\\\?\\C:", "\\", "foo.txt"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\?\\C:\\"),
+           file_name: Some("foo.txt"),
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+
+        t!("\\\\?\\C:\\",
+           iter: ["\\\\?\\C:", "\\", ""],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\?\\C:",
+           iter: ["\\\\?\\C:"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\?\\foo/bar",
+           iter: ["\\\\?\\foo/bar"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\?\\C:/foo",
+           iter: ["\\\\?\\C:/foo"],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\.\\foo\\bar",
+           iter: ["\\\\.\\foo", "\\", "bar"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\.\\foo\\"),
+           file_name: Some("bar"),
+           file_stem: Some("bar"),
+           extension: None
+           );
+
+
+        t!("\\\\.\\foo",
+           iter: ["\\\\.\\foo", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\.\\foo/bar",
+           iter: ["\\\\.\\foo/bar", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+
+        t!("\\\\.\\foo\\bar/baz",
+           iter: ["\\\\.\\foo", "\\", "bar", "baz"],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\.\\foo\\bar"),
+           file_name: Some("baz"),
+           file_stem: Some("baz"),
+           extension: None
+           );
+
+
+        t!("\\\\.\\",
+           iter: ["\\\\.\\", "\\", "."],
+           has_root: true,
+           is_absolute: true,
+           parent: None,
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+
+        t!("\\\\?\\a\\b\\",
+           iter: ["\\\\?\\a", "\\", "b", ""],
+           has_root: true,
+           is_absolute: true,
+           parent: Some("\\\\?\\a\\b"),
+           file_name: None,
+           file_stem: None,
+           extension: None
+           );
+    }
+
+    #[test]
+    pub fn test_stem_ext() {
+        t!("foo",
+           file_stem: Some("foo"),
+           extension: None
+           );
+
+        t!("foo.",
+           file_stem: Some("foo"),
+           extension: Some("")
+           );
+
+        t!(".foo",
+           file_stem: Some(".foo"),
+           extension: None
+           );
+
+        t!("foo.txt",
+           file_stem: Some("foo"),
+           extension: Some("txt")
+           );
+
+        t!("foo.bar.txt",
+           file_stem: Some("foo.bar"),
+           extension: Some("txt")
+           );
+
+        t!("foo.bar.",
+           file_stem: Some("foo.bar"),
+           extension: Some("")
+           );
+
+        t!(".",
+           file_stem: None,
+           extension: None
+           );
+
+        t!("..",
+           file_stem: None,
+           extension: None
+           );
+
+        t!("",
+           file_stem: None,
+           extension: None
+           );
+    }
+
+    #[test]
+    pub fn test_push() {
+        macro_rules! tp(
+            ($path:expr, $push:expr, $expected:expr) => ( {
+                let mut actual = PathBuf::new($path);
+                actual.push($push);
+                assert!(actual.to_str() == Some($expected),
+                        "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
+                        $push, $path, $expected, actual.to_str().unwrap());
+            });
+        );
+
+        if cfg!(unix) {
+            tp!("", "foo", "foo");
+            tp!("foo", "bar", "foo/bar");
+            tp!("foo/", "bar", "foo/bar");
+            tp!("foo//", "bar", "foo//bar");
+            tp!("foo/.", "bar", "foo/./bar");
+            tp!("foo./.", "bar", "foo././bar");
+            tp!("foo", "", "foo/");
+            tp!("foo", ".", "foo/.");
+            tp!("foo", "..", "foo/..");
+            tp!("foo", "/", "/");
+            tp!("/foo/bar", "/", "/");
+            tp!("/foo/bar", "/baz", "/baz");
+            tp!("/foo/bar", "./baz", "/foo/bar/./baz");
+        } else {
+            tp!("", "foo", "foo");
+            tp!("foo", "bar", r"foo\bar");
+            tp!("foo/", "bar", r"foo/bar");
+            tp!(r"foo\", "bar", r"foo\bar");
+            tp!("foo//", "bar", r"foo//bar");
+            tp!(r"foo\\", "bar", r"foo\\bar");
+            tp!("foo/.", "bar", r"foo/.\bar");
+            tp!("foo./.", "bar", r"foo./.\bar");
+            tp!(r"foo\.", "bar", r"foo\.\bar");
+            tp!(r"foo.\.", "bar", r"foo.\.\bar");
+            tp!("foo", "", "foo\\");
+            tp!("foo", ".", r"foo\.");
+            tp!("foo", "..", r"foo\..");
+            tp!("foo", "/", "/");
+            tp!("foo", r"\", r"\");
+            tp!("/foo/bar", "/", "/");
+            tp!(r"\foo\bar", r"\", r"\");
+            tp!("/foo/bar", "/baz", "/baz");
+            tp!("/foo/bar", r"\baz", r"\baz");
+            tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
+            tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
+
+            tp!("c:\\", "windows", "c:\\windows");
+            tp!("c:", "windows", "c:windows");
+
+            tp!("a\\b\\c", "d", "a\\b\\c\\d");
+            tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
+            tp!("a\\b", "c\\d", "a\\b\\c\\d");
+            tp!("a\\b", "\\c\\d", "\\c\\d");
+            tp!("a\\b", ".", "a\\b\\.");
+            tp!("a\\b", "..\\c", "a\\b\\..\\c");
+            tp!("a\\b", "C:a.txt", "C:a.txt");
+            tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
+            tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
+            tp!("C:\\a\\b\\c", "C:d", "C:d");
+            tp!("C:a\\b\\c", "C:d", "C:d");
+            tp!("C:", r"a\b\c", r"C:a\b\c");
+            tp!("C:", r"..\a", r"C:..\a");
+            tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
+            tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
+            tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
+            tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
+            tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
+            tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
+            tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
+            tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
+            tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
+
+            // Note: modified from old path API
+            tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
+
+            tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
+            tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
+            tp!("\\\\.\\foo\\bar", "C:a", "C:a");
+            // again, not sure about the following, but I'm assuming \\.\ should be verbatim
+            tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
+
+            tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
+        }
+    }
+
+    #[test]
+    pub fn test_pop() {
+        macro_rules! tp(
+            ($path:expr, $expected:expr, $output:expr) => ( {
+                let mut actual = PathBuf::new($path);
+                let output = actual.pop();
+                assert!(actual.to_str() == Some($expected) && output == $output,
+                        "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+                        $path, $expected, $output,
+                        actual.to_str().unwrap(), output);
+            });
+        );
+
+        tp!("", "", false);
+        tp!("/", "/", false);
+        tp!("foo", "foo", false);
+        tp!(".", ".", false);
+        tp!("/foo", "/", true);
+        tp!("/foo/bar", "/foo", true);
+        tp!("foo/bar", "foo", true);
+        tp!("foo/.", "foo", true);
+        tp!("foo//bar", "foo", true);
+
+        if cfg!(windows) {
+            tp!("a\\b\\c", "a\\b", true);
+            tp!("\\a", "\\", true);
+            tp!("\\", "\\", false);
+
+            tp!("C:\\a\\b", "C:\\a", true);
+            tp!("C:\\a", "C:\\", true);
+            tp!("C:\\", "C:\\", false);
+            tp!("C:a\\b", "C:a", true);
+            tp!("C:a", "C:", true);
+            tp!("C:", "C:", false);
+            tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
+            tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
+            tp!("\\\\server\\share", "\\\\server\\share", false);
+            tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
+            tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
+            tp!("\\\\?\\a", "\\\\?\\a", false);
+            tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
+            tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
+            tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
+            tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
+            tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true);
+            tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
+            tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
+            tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
+            tp!("\\\\.\\a", "\\\\.\\a", false);
+
+            tp!("\\\\?\\a\\b\\", "\\\\?\\a\\b", true);
+        }
+    }
+
+    #[test]
+    pub fn test_set_file_name() {
+        macro_rules! tfn(
+                ($path:expr, $file:expr, $expected:expr) => ( {
+                let mut p = PathBuf::new($path);
+                p.set_file_name($file);
+                assert!(p.to_str() == Some($expected),
+                        "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
+                        $path, $file, $expected,
+                        p.to_str().unwrap());
+            });
+        );
+
+        tfn!("foo", "foo", "foo");
+        tfn!("foo", "bar", "bar");
+        tfn!("foo", "", "");
+        tfn!("", "foo", "foo");
+        tfn!(".", "foo", "./foo");
+        tfn!("foo/", "bar", "foo/bar");
+        tfn!("foo/.", "bar", "foo/./bar");
+        tfn!("..", "foo", "../foo");
+        tfn!("foo/..", "bar", "foo/../bar");
+        tfn!("/", "foo", "/foo");
+    }
+
+    #[test]
+    pub fn test_set_extension() {
+        macro_rules! tfe(
+                ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
+                let mut p = PathBuf::new($path);
+                let output = p.set_extension($ext);
+                assert!(p.to_str() == Some($expected) && output == $output,
+                        "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
+                        $path, $ext, $expected, $output,
+                        p.to_str().unwrap(), output);
+            });
+        );
+
+        tfe!("foo", "txt", "foo.txt", true);
+        tfe!("foo.bar", "txt", "foo.txt", true);
+        tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
+        tfe!(".test", "txt", ".test.txt", true);
+        tfe!("foo.txt", "", "foo", true);
+        tfe!("foo", "", "foo", true);
+        tfe!("", "foo", "", false);
+        tfe!(".", "foo", ".", false);
+        tfe!("foo/", "bar", "foo/", false);
+        tfe!("foo/.", "bar", "foo/.", false);
+        tfe!("..", "foo", "..",  false);
+        tfe!("foo/..", "bar", "foo/..", false);
+        tfe!("/", "foo", "/", false);
+    }
+
+    #[test]
+    pub fn test_compare() {
+        macro_rules! tc(
+            ($path1:expr, $path2:expr, eq: $eq:expr,
+             starts_with: $starts_with:expr, ends_with: $ends_with:expr,
+             relative_from: $relative_from:expr) => ({
+                 let path1 = Path::new($path1);
+                 let path2 = Path::new($path2);
+
+                 let eq = path1 == path2;
+                 assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
+                         $path1, $path2, $eq, eq);
+
+                 let starts_with = path1.starts_with(path2);
+                 assert!(starts_with == $starts_with,
+                         "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+                         $starts_with, starts_with);
+
+                 let ends_with = path1.ends_with(path2);
+                 assert!(ends_with == $ends_with,
+                         "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
+                         $ends_with, ends_with);
+
+                 let relative_from = path1.relative_from(path2).map(|p| p.to_str().unwrap());
+                 let exp: Option<&str> = $relative_from;
+                 assert!(relative_from == exp,
+                         "{:?}.relative_from({:?}), expected {:?}, got {:?}", $path1, $path2,
+                         exp, relative_from);
+            });
+        );
+
+        tc!("", "",
+            eq: true,
+            starts_with: true,
+            ends_with: true,
+            relative_from: Some("")
+            );
+
+        tc!("foo", "",
+            eq: false,
+            starts_with: true,
+            ends_with: true,
+            relative_from: Some("foo")
+            );
+
+        tc!("", "foo",
+            eq: false,
+            starts_with: false,
+            ends_with: false,
+            relative_from: None
+            );
+
+        tc!("foo", "foo",
+            eq: true,
+            starts_with: true,
+            ends_with: true,
+            relative_from: Some("")
+            );
+
+        tc!("foo/", "foo",
+            eq: false,
+            starts_with: true,
+            ends_with: false,
+            relative_from: Some(".")
+            );
+
+        tc!("foo/bar", "foo",
+            eq: false,
+            starts_with: true,
+            ends_with: false,
+            relative_from: Some("bar")
+            );
+
+        tc!("foo/bar/baz", "foo/bar",
+            eq: false,
+            starts_with: true,
+            ends_with: false,
+            relative_from: Some("baz")
+            );
+
+        tc!("foo/bar", "foo/bar/baz",
+            eq: false,
+            starts_with: false,
+            ends_with: false,
+            relative_from: None
+            );
+
+        tc!("./foo/bar/", ".",
+            eq: false,
+            starts_with: true,
+            ends_with: true,
+            relative_from: Some("foo/bar/")
+            );
+    }
+}
diff --git a/src/libstd/path/mod.rs b/src/libstd/path/mod.rs
deleted file mode 100644 (file)
index 0d80258..0000000
+++ /dev/null
@@ -1,923 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Cross-platform path support
-//!
-//! This module implements support for two flavors of paths. `PosixPath` represents a path on any
-//! unix-like system, whereas `WindowsPath` represents a path on Windows. This module also exposes
-//! a typedef `Path` which is equal to the appropriate platform-specific path variant.
-//!
-//! Both `PosixPath` and `WindowsPath` implement a trait `GenericPath`, which contains the set of
-//! methods that behave the same for both paths. They each also implement some methods that could
-//! not be expressed in `GenericPath`, yet behave identically for both path flavors, such as
-//! `.components()`.
-//!
-//! The three main design goals of this module are 1) to avoid unnecessary allocation, 2) to behave
-//! the same regardless of which flavor of path is being used, and 3) to support paths that cannot
-//! be represented in UTF-8 (as Linux has 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.
-//!
-//! 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 `.pop()` (and other
-//! setters). The resulting Path can either be passed to another API that expects a path, or can be
-//! turned into a `&[u8]` with `.as_vec()` or a `Option<&str>` with `.as_str()`. Similarly,
-//! attributes of the path can be queried with methods such as `.filename()`. There are also
-//! methods that return a new path instead of modifying the receiver, such as `.join()` or
-//! `.dir_path()`.
-//!
-//! Paths are always kept in normalized form. This means that creating the path
-//! `Path::new("a/b/../c")` will return the path `a/c`. Similarly any attempt to mutate the path
-//! will always leave it in normalized form.
-//!
-//! When rendering a path to some form of output, there is a method `.display()` which is
-//! compatible with the `format!()` parameter `{}`. This will render the path as a string,
-//! replacing all non-utf8 sequences with the Replacement Character (U+FFFD). As such it is not
-//! suitable for passing to any API that actually operates on the path; it is only intended for
-//! display.
-//!
-//! ## Example
-//!
-//! ```rust
-//! use std::old_io::fs::PathExtensions;
-//!
-//! let mut path = Path::new("/tmp/path");
-//! println!("path: {}", path.display());
-//! path.set_filename("foo");
-//! path.push("bar");
-//! println!("new path: {}", path.display());
-//! println!("path exists: {}", path.exists());
-//! ```
-
-#![unstable(feature = "path")]
-
-use core::marker::Sized;
-use ffi::CString;
-use clone::Clone;
-use fmt;
-use iter::IteratorExt;
-use option::Option;
-use option::Option::{None, Some};
-use str;
-use str::StrExt;
-use string::{String, CowString};
-use slice::SliceExt;
-use vec::Vec;
-
-/// Typedef for POSIX file paths.
-/// See `posix::Path` for more info.
-pub use self::posix::Path as PosixPath;
-
-/// Typedef for Windows file paths.
-/// See `windows::Path` for more info.
-pub use self::windows::Path as WindowsPath;
-
-/// Typedef for the platform-native path type
-#[cfg(unix)]
-pub use self::posix::Path as Path;
-/// Typedef for the platform-native path type
-#[cfg(windows)]
-pub use self::windows::Path as Path;
-
-/// Typedef for the platform-native component iterator
-#[cfg(unix)]
-pub use self::posix::Components as Components;
-/// Typedef for the platform-native component iterator
-#[cfg(windows)]
-pub use self::windows::Components as Components;
-
-/// Typedef for the platform-native str component iterator
-#[cfg(unix)]
-pub use self::posix::StrComponents as StrComponents;
-/// Typedef for the platform-native str component iterator
-#[cfg(windows)]
-pub use self::windows::StrComponents as StrComponents;
-
-/// Alias for the platform-native separator character.
-#[cfg(unix)]
-pub use self::posix::SEP as SEP;
-/// Alias for the platform-native separator character.
-#[cfg(windows)]
-pub use self::windows::SEP as SEP;
-
-/// Alias for the platform-native separator byte.
-#[cfg(unix)]
-pub use self::posix::SEP_BYTE as SEP_BYTE;
-/// Alias for the platform-native separator byte.
-#[cfg(windows)]
-pub use self::windows::SEP_BYTE as SEP_BYTE;
-
-/// Typedef for the platform-native separator char func
-#[cfg(unix)]
-pub use self::posix::is_sep as is_sep;
-/// Typedef for the platform-native separator char func
-#[cfg(windows)]
-pub use self::windows::is_sep as is_sep;
-/// Typedef for the platform-native separator byte func
-#[cfg(unix)]
-pub use self::posix::is_sep_byte as is_sep_byte;
-/// Typedef for the platform-native separator byte func
-#[cfg(windows)]
-pub use self::windows::is_sep_byte as is_sep_byte;
-
-pub mod posix;
-pub mod windows;
-
-/// A trait that represents the generic operations available on paths
-pub trait GenericPath: Clone + GenericPathUnsafe {
-    /// Creates a new Path from a byte vector or string.
-    /// The resulting Path will always be normalized.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let path = Path::new("foo/bar");
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the path contains a NUL.
-    ///
-    /// See individual Path impls for additional restrictions.
-    #[inline]
-    fn new<T: BytesContainer>(path: T) -> Self {
-        assert!(!contains_nul(&path));
-        unsafe { GenericPathUnsafe::new_unchecked(path) }
-    }
-
-    /// Creates a new Path from a byte vector or string, if possible.
-    /// The resulting Path will always be normalized.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let x: &[u8] = b"foo\0";
-    /// assert!(Path::new_opt(x).is_none());
-    /// # }
-    /// ```
-    #[inline]
-    fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
-        if contains_nul(&path) {
-            None
-        } else {
-            Some(unsafe { GenericPathUnsafe::new_unchecked(path) })
-        }
-    }
-
-    /// Returns the path as a string, if possible.
-    /// If the path is not representable in utf-8, this returns None.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("/abc/def");
-    /// assert_eq!(p.as_str(), Some("/abc/def"));
-    /// # }
-    /// ```
-    #[inline]
-    fn as_str<'a>(&'a self) -> Option<&'a str> {
-        str::from_utf8(self.as_vec()).ok()
-    }
-
-    /// Returns the path as a byte vector
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def");
-    /// assert_eq!(p.as_vec(), b"abc/def");
-    /// # }
-    /// ```
-    fn as_vec<'a>(&'a self) -> &'a [u8];
-
-    /// Converts the Path into an owned byte vector
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def");
-    /// assert_eq!(p.into_vec(), b"abc/def".to_vec());
-    /// // attempting to use p now results in "error: use of moved value"
-    /// # }
-    /// ```
-    fn into_vec(self) -> Vec<u8>;
-
-    /// Returns an object that implements `Show` for printing paths
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def");
-    /// println!("{}", p.display()); // prints "abc/def"
-    /// # }
-    /// ```
-    fn display<'a>(&'a self) -> Display<'a, Self> {
-        Display{ path: self, filename: false }
-    }
-
-    /// Returns an object that implements `Show` for printing filenames
-    ///
-    /// If there is no filename, nothing will be printed.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def");
-    /// println!("{}", p.filename_display()); // prints "def"
-    /// # }
-    /// ```
-    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).
-    /// If `self` has no directory component, returns ['.'].
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def/ghi");
-    /// assert_eq!(p.dirname(), b"abc/def");
-    /// # }
-    /// ```
-    fn dirname<'a>(&'a self) -> &'a [u8];
-
-    /// Returns the directory component of `self`, as a string, if possible.
-    /// See `dirname` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def/ghi");
-    /// assert_eq!(p.dirname_str(), Some("abc/def"));
-    /// # }
-    /// ```
-    #[inline]
-    fn dirname_str<'a>(&'a self) -> Option<&'a str> {
-        str::from_utf8(self.dirname()).ok()
-    }
-
-    /// Returns the file component of `self`, as a byte vector.
-    /// If `self` represents the root of the file hierarchy, returns None.
-    /// If `self` is "." or "..", returns None.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def/ghi");
-    /// assert_eq!(p.filename(), Some(b"ghi"));
-    /// # }
-    /// ```
-    fn filename<'a>(&'a self) -> Option<&'a [u8]>;
-
-    /// Returns the file component of `self`, as a string, if possible.
-    /// See `filename` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def/ghi");
-    /// assert_eq!(p.filename_str(), Some("ghi"));
-    /// # }
-    /// ```
-    #[inline]
-    fn filename_str<'a>(&'a self) -> Option<&'a str> {
-        self.filename().and_then(|s| str::from_utf8(s).ok())
-    }
-
-    /// Returns the stem of the filename of `self`, as a byte vector.
-    /// The stem is the portion of the filename just before the last '.'.
-    /// If there is no '.', the entire filename is returned.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("/abc/def.txt");
-    /// assert_eq!(p.filestem(), Some(b"def"));
-    /// # }
-    /// ```
-    fn filestem<'a>(&'a self) -> Option<&'a [u8]> {
-        match self.filename() {
-            None => None,
-            Some(name) => Some({
-                let dot = b'.';
-                match name.rposition_elem(&dot) {
-                    None | Some(0) => name,
-                    Some(1) if name == b".." => name,
-                    Some(pos) => &name[..pos]
-                }
-            })
-        }
-    }
-
-    /// Returns the stem of the filename of `self`, as a string, if possible.
-    /// See `filestem` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("/abc/def.txt");
-    /// assert_eq!(p.filestem_str(), Some("def"));
-    /// # }
-    /// ```
-    #[inline]
-    fn filestem_str<'a>(&'a self) -> Option<&'a str> {
-        self.filestem().and_then(|s| str::from_utf8(s).ok())
-    }
-
-    /// Returns the extension of the filename of `self`, as an optional byte vector.
-    /// The extension is the portion of the filename just after the last '.'.
-    /// If there is no extension, None is returned.
-    /// If the filename ends in '.', the empty vector is returned.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def.txt");
-    /// assert_eq!(p.extension(), Some(b"txt"));
-    /// # }
-    /// ```
-    fn extension<'a>(&'a self) -> Option<&'a [u8]> {
-        match self.filename() {
-            None => None,
-            Some(name) => {
-                let dot = b'.';
-                match name.rposition_elem(&dot) {
-                    None | Some(0) => None,
-                    Some(1) if name == b".." => None,
-                    Some(pos) => Some(&name[pos+1..])
-                }
-            }
-        }
-    }
-
-    /// Returns the extension of the filename of `self`, as a string, if possible.
-    /// See `extension` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def.txt");
-    /// assert_eq!(p.extension_str(), Some("txt"));
-    /// # }
-    /// ```
-    #[inline]
-    fn extension_str<'a>(&'a self) -> Option<&'a str> {
-        self.extension().and_then(|s| str::from_utf8(s).ok())
-    }
-
-    /// Replaces the filename portion of the path with the given byte vector or string.
-    /// If the replacement name is [], this is equivalent to popping the path.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("abc/def.txt");
-    /// p.set_filename("foo.dat");
-    /// assert!(p == Path::new("abc/foo.dat"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the filename contains a NUL.
-    #[inline]
-    fn set_filename<T: BytesContainer>(&mut self, filename: T) {
-        assert!(!contains_nul(&filename));
-        unsafe { self.set_filename_unchecked(filename) }
-    }
-
-    /// Replaces the extension with the given byte vector or string.
-    /// If there is no extension in `self`, this adds one.
-    /// If the argument is [] or "", this removes the extension.
-    /// If `self` has no filename, this is a no-op.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("abc/def.txt");
-    /// p.set_extension("csv");
-    /// assert_eq!(p, Path::new("abc/def.csv"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the extension contains a NUL.
-    fn set_extension<T: BytesContainer>(&mut self, extension: T) {
-        assert!(!contains_nul(&extension));
-
-        let val = self.filename().and_then(|name| {
-            let dot = b'.';
-            let extlen = extension.container_as_bytes().len();
-            match (name.rposition_elem(&dot), extlen) {
-                (None, 0) | (Some(0), 0) => None,
-                (Some(idx), 0) => Some(name[..idx].to_vec()),
-                (idx, extlen) => {
-                    let idx = match idx {
-                        None | Some(0) => name.len(),
-                        Some(val) => val
-                    };
-
-                    let mut v;
-                    v = Vec::with_capacity(idx + extlen + 1);
-                    v.push_all(&name[..idx]);
-                    v.push(dot);
-                    v.push_all(extension.container_as_bytes());
-                    Some(v)
-                }
-            }
-        });
-
-        match val {
-            None => (),
-            Some(v) => unsafe { self.set_filename_unchecked(v) }
-        }
-    }
-
-    /// Returns a new Path constructed by replacing the filename with the given
-    /// byte vector or string.
-    /// See `set_filename` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("abc/def.txt");
-    /// assert_eq!(p.with_filename("foo.dat"), Path::new("abc/foo.dat"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the filename contains a NUL.
-    #[inline]
-    fn with_filename<T: BytesContainer>(&self, filename: T) -> Self {
-        let mut p = self.clone();
-        p.set_filename(filename);
-        p
-    }
-
-    /// Returns a new Path constructed by setting the extension to the given
-    /// byte vector or string.
-    /// See `set_extension` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("abc/def.txt");
-    /// assert_eq!(p.with_extension("csv"), Path::new("abc/def.csv"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the extension contains a NUL.
-    #[inline]
-    fn with_extension<T: BytesContainer>(&self, extension: T) -> Self {
-        let mut p = self.clone();
-        p.set_extension(extension);
-        p
-    }
-
-    /// Returns the directory component of `self`, as a Path.
-    /// If `self` represents the root of the filesystem hierarchy, returns `self`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def/ghi");
-    /// assert_eq!(p.dir_path(), Path::new("abc/def"));
-    /// # }
-    /// ```
-    fn dir_path(&self) -> Self {
-        // self.dirname() returns a NUL-free vector
-        unsafe { GenericPathUnsafe::new_unchecked(self.dirname()) }
-    }
-
-    /// Returns a Path that represents the filesystem root that `self` is rooted in.
-    ///
-    /// If `self` is not absolute, or vol/cwd-relative in the case of Windows, this returns None.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// assert_eq!(Path::new("abc/def").root_path(), None);
-    /// assert_eq!(Path::new("/abc/def").root_path(), Some(Path::new("/")));
-    /// # }
-    /// ```
-    fn root_path(&self) -> Option<Self>;
-
-    /// Pushes a path (as a byte vector or string) onto `self`.
-    /// If the argument represents an absolute path, it replaces `self`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("foo/bar");
-    /// p.push("baz.txt");
-    /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the path contains a NUL.
-    #[inline]
-    fn push<T: BytesContainer>(&mut self, path: T) {
-        assert!(!contains_nul(&path));
-        unsafe { self.push_unchecked(path) }
-    }
-
-    /// Pushes multiple paths (as byte vectors or strings) onto `self`.
-    /// See `push` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("foo");
-    /// p.push_many(&["bar", "baz.txt"]);
-    /// assert_eq!(p, Path::new("foo/bar/baz.txt"));
-    /// # }
-    /// ```
-    #[inline]
-    fn push_many<T: BytesContainer>(&mut self, paths: &[T]) {
-        let t: Option<&T> = None;
-        if BytesContainer::is_str(t) {
-            for p in paths {
-                self.push(p.container_as_str().unwrap())
-            }
-        } else {
-            for p in paths {
-                self.push(p.container_as_bytes())
-            }
-        }
-    }
-
-    /// Removes the last path component from the receiver.
-    /// Returns `true` if the receiver was modified, or `false` if it already
-    /// represented the root of the file hierarchy.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let mut p = Path::new("foo/bar/baz.txt");
-    /// p.pop();
-    /// assert_eq!(p, Path::new("foo/bar"));
-    /// # }
-    /// ```
-    fn pop(&mut self) -> bool;
-
-    /// Returns a new Path constructed by joining `self` with the given path
-    /// (as a byte vector or string).
-    /// If the given path is absolute, the new Path will represent just that.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("/foo");
-    /// assert_eq!(p.join("bar.txt"), Path::new("/foo/bar.txt"));
-    /// # }
-    /// ```
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the path contains a NUL.
-    #[inline]
-    fn join<T: BytesContainer>(&self, path: T) -> Self {
-        let mut p = self.clone();
-        p.push(path);
-        p
-    }
-
-    /// Returns a new Path constructed by joining `self` with the given paths
-    /// (as byte vectors or strings).
-    /// See `join` for details.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("foo");
-    /// let fbbq = Path::new("foo/bar/baz/quux.txt");
-    /// assert_eq!(p.join_many(&["bar", "baz", "quux.txt"]), fbbq);
-    /// # }
-    /// ```
-    #[inline]
-    fn join_many<T: BytesContainer>(&self, paths: &[T]) -> Self {
-        let mut p = self.clone();
-        p.push_many(paths);
-        p
-    }
-
-    /// Returns whether `self` represents an absolute path.
-    /// An absolute path is defined as one that, when joined to another path, will
-    /// yield back the same absolute path.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("/abc/def");
-    /// assert!(p.is_absolute());
-    /// # }
-    /// ```
-    fn is_absolute(&self) -> bool;
-
-    /// Returns whether `self` represents a relative path.
-    /// Typically this is the inverse of `is_absolute`.
-    /// But for Windows paths, it also means the path is not volume-relative or
-    /// relative to the current working directory.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("abc/def");
-    /// assert!(p.is_relative());
-    /// # }
-    /// ```
-    fn is_relative(&self) -> bool {
-        !self.is_absolute()
-    }
-
-    /// Returns whether `self` is equal to, or is an ancestor of, the given path.
-    /// If both paths are relative, they are compared as though they are relative
-    /// to the same parent path.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("foo/bar/baz/quux.txt");
-    /// let fb = Path::new("foo/bar");
-    /// let bq = Path::new("baz/quux.txt");
-    /// assert!(fb.is_ancestor_of(&p));
-    /// # }
-    /// ```
-    fn is_ancestor_of(&self, other: &Self) -> bool;
-
-    /// Returns the Path that, were it joined to `base`, would yield `self`.
-    /// If no such path exists, None is returned.
-    /// If `self` is absolute and `base` is relative, or on Windows if both
-    /// paths refer to separate drives, an absolute path is returned.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("foo/bar/baz/quux.txt");
-    /// let fb = Path::new("foo/bar");
-    /// let bq = Path::new("baz/quux.txt");
-    /// assert_eq!(p.path_relative_from(&fb), Some(bq));
-    /// # }
-    /// ```
-    fn path_relative_from(&self, base: &Self) -> Option<Self>;
-
-    /// Returns whether the relative path `child` is a suffix of `self`.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// # foo();
-    /// # #[cfg(windows)] fn foo() {}
-    /// # #[cfg(unix)] fn foo() {
-    /// let p = Path::new("foo/bar/baz/quux.txt");
-    /// let bq = Path::new("baz/quux.txt");
-    /// assert!(p.ends_with_path(&bq));
-    /// # }
-    /// ```
-    fn ends_with_path(&self, child: &Self) -> bool;
-}
-
-/// A trait that represents something bytes-like (e.g. a &[u8] or a &str)
-pub trait BytesContainer {
-    /// Returns a &[u8] representing the receiver
-    fn container_as_bytes<'a>(&'a self) -> &'a [u8];
-    /// Returns the receiver interpreted as a utf-8 string, if possible
-    #[inline]
-    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
-        str::from_utf8(self.container_as_bytes()).ok()
-    }
-    /// 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 }
-}
-
-/// A trait that represents the unsafe operations on GenericPaths
-pub trait GenericPathUnsafe {
-    /// Creates a new Path without checking for null bytes.
-    /// The resulting Path will always be normalized.
-    unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Self;
-
-    /// Replaces the filename portion of the path without checking for null
-    /// bytes.
-    /// See `set_filename` for details.
-    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T);
-
-    /// Pushes a path onto `self` without checking for null bytes.
-    /// See `push` for details.
-    unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T);
-}
-
-/// Helper struct for printing paths with format!()
-pub struct Display<'a, P:'a> {
-    path: &'a P,
-    filename: bool
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: GenericPath> fmt::Debug for Display<'a, P> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.as_cow(), f)
-    }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, P: GenericPath> fmt::Display for Display<'a, P> {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        self.as_cow().fmt(f)
-    }
-}
-
-impl<'a, P: GenericPath> Display<'a, P> {
-    /// Returns the path as a possibly-owned string.
-    ///
-    /// If the path is not UTF-8, invalid sequences will be replaced with the
-    /// Unicode replacement char. This involves allocation.
-    #[inline]
-    pub fn as_cow(&self) -> CowString<'a> {
-        String::from_utf8_lossy(if self.filename {
-            match self.path.filename() {
-                None => {
-                    let result: &[u8] = &[];
-                    result
-                }
-                Some(v) => v
-            }
-        } else {
-            self.path.as_vec()
-        })
-    }
-}
-
-impl BytesContainer for str {
-    #[inline]
-    fn container_as_bytes(&self) -> &[u8] {
-        self.as_bytes()
-    }
-    #[inline]
-    fn container_as_str(&self) -> Option<&str> {
-        Some(self)
-    }
-    #[inline]
-    fn is_str(_: Option<&str>) -> bool { true }
-}
-
-impl BytesContainer for String {
-    #[inline]
-    fn container_as_bytes(&self) -> &[u8] {
-        self.as_bytes()
-    }
-    #[inline]
-    fn container_as_str(&self) -> Option<&str> {
-        Some(&self[])
-    }
-    #[inline]
-    fn is_str(_: Option<&String>) -> bool { true }
-}
-
-impl BytesContainer for [u8] {
-    #[inline]
-    fn container_as_bytes(&self) -> &[u8] {
-        self
-    }
-}
-
-impl BytesContainer for Vec<u8> {
-    #[inline]
-    fn container_as_bytes(&self) -> &[u8] {
-        &self[]
-    }
-}
-
-impl BytesContainer for CString {
-    #[inline]
-    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
-        self.as_bytes()
-    }
-}
-
-impl<'a, T: ?Sized + BytesContainer> BytesContainer for &'a T {
-    #[inline]
-    fn container_as_bytes(&self) -> &[u8] {
-        (**self).container_as_bytes()
-    }
-    #[inline]
-    fn container_as_str(&self) -> Option<&str> {
-        (**self).container_as_str()
-    }
-    #[inline]
-    fn is_str(_: Option<& &'a T>) -> bool { BytesContainer::is_str(None::<&T>) }
-}
-
-#[inline(always)]
-fn contains_nul<T: BytesContainer>(v: &T) -> bool {
-    v.container_as_bytes().iter().any(|&x| x == 0)
-}
diff --git a/src/libstd/path/posix.rs b/src/libstd/path/posix.rs
deleted file mode 100644 (file)
index 69f815e..0000000
+++ /dev/null
@@ -1,1348 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! POSIX file path handling
-
-use clone::Clone;
-use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
-use fmt;
-use hash;
-use old_io::Writer;
-use iter::{AdditiveIterator, Extend};
-use iter::{Iterator, IteratorExt, Map};
-use marker::Sized;
-use option::Option::{self, Some, None};
-use result::Result::{self, Ok, Err};
-use slice::{AsSlice, Split, SliceExt, SliceConcatExt};
-use str::{self, FromStr, StrExt};
-use vec::Vec;
-
-use super::{BytesContainer, GenericPath, GenericPathUnsafe};
-
-/// Iterator that yields successive components of a Path as &[u8]
-pub type Components<'a> = Split<'a, u8, fn(&u8) -> bool>;
-
-/// Iterator that yields successive components of a Path as Option<&str>
-pub type StrComponents<'a> =
-    Map<Components<'a>, fn(&[u8]) -> Option<&str>>;
-
-/// Represents a POSIX file path
-#[derive(Clone)]
-pub struct Path {
-    repr: Vec<u8>, // assumed to never be empty or contain NULs
-    sepidx: Option<uint> // index of the final separator in repr
-}
-
-/// The standard path separator character
-pub const SEP: char = '/';
-
-/// The standard path separator byte
-pub const SEP_BYTE: u8 = SEP as u8;
-
-/// Returns whether the given byte is a path separator
-#[inline]
-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
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Path {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.display(), f)
-    }
-}
-
-impl PartialEq for Path {
-    #[inline]
-    fn eq(&self, other: &Path) -> bool {
-        self.repr == other.repr
-    }
-}
-
-impl Eq for Path {}
-
-impl PartialOrd for Path {
-    fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Path {
-    fn cmp(&self, other: &Path) -> Ordering {
-        self.repr.cmp(&other.repr)
-    }
-}
-
-impl FromStr for Path {
-    type Err = ParsePathError;
-    fn from_str(s: &str) -> Result<Path, ParsePathError> {
-        match Path::new_opt(s) {
-            Some(p) => Ok(p),
-            None => Err(ParsePathError),
-        }
-    }
-}
-
-/// Valuelue indicating that a path could not be parsed from a string.
-#[derive(Debug, Clone, PartialEq, Copy)]
-pub struct ParsePathError;
-
-impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
-    #[inline]
-    fn hash(&self, state: &mut S) {
-        self.repr.hash(state)
-    }
-}
-
-impl BytesContainer for 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_BYTE);
-        Path{ repr: path, sepidx: idx }
-    }
-
-    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
-        let filename = filename.container_as_bytes();
-        match self.sepidx {
-            None if b".." == self.repr => {
-                let mut v = Vec::with_capacity(3 + filename.len());
-                v.push_all(dot_dot_static);
-                v.push(SEP_BYTE);
-                v.push_all(filename);
-                // FIXME: this is slow
-                self.repr = Path::normalize(v.as_slice());
-            }
-            None => {
-                self.repr = Path::normalize(filename);
-            }
-            Some(idx) if &self.repr[idx+1..] == b".." => {
-                let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len());
-                v.push_all(self.repr.as_slice());
-                v.push(SEP_BYTE);
-                v.push_all(filename);
-                // FIXME: this is slow
-                self.repr = Path::normalize(v.as_slice());
-            }
-            Some(idx) => {
-                let mut v = Vec::with_capacity(idx + 1 + filename.len());
-                v.push_all(&self.repr[..idx+1]);
-                v.push_all(filename);
-                // FIXME: this is slow
-                self.repr = Path::normalize(v.as_slice());
-            }
-        }
-        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_BYTE {
-                self.repr = Path::normalize(path);
-            }  else {
-                let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1);
-                v.push_all(self.repr.as_slice());
-                v.push(SEP_BYTE);
-                v.push_all(path);
-                // FIXME: this is slow
-                self.repr = Path::normalize(v.as_slice());
-            }
-            self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
-        }
-    }
-}
-
-impl GenericPath for Path {
-    #[inline]
-    fn as_vec<'a>(&'a self) -> &'a [u8] {
-        self.repr.as_slice()
-    }
-
-    fn into_vec(self) -> Vec<u8> {
-        self.repr
-    }
-
-    fn dirname<'a>(&'a self) -> &'a [u8] {
-        match self.sepidx {
-            None if b".." == self.repr => self.repr.as_slice(),
-            None => dot_static,
-            Some(0) => &self.repr[..1],
-            Some(idx) if &self.repr[idx+1..] == b".." => self.repr.as_slice(),
-            Some(idx) => &self.repr[..idx]
-        }
-    }
-
-    fn filename<'a>(&'a self) -> Option<&'a [u8]> {
-        match self.sepidx {
-            None if b"." == self.repr ||
-                b".." == self.repr => None,
-            None => Some(self.repr.as_slice()),
-            Some(idx) if &self.repr[idx+1..] == b".." => None,
-            Some(0) if self.repr[1..].is_empty() => None,
-            Some(idx) => Some(&self.repr[idx+1..])
-        }
-    }
-
-    fn pop(&mut self) -> bool {
-        match self.sepidx {
-            None if b"." == self.repr => false,
-            None => {
-                self.repr = vec![b'.'];
-                self.sepidx = None;
-                true
-            }
-            Some(0) if b"/" == self.repr => false,
-            Some(idx) => {
-                if idx == 0 {
-                    self.repr.truncate(idx+1);
-                } else {
-                    self.repr.truncate(idx);
-                }
-                self.sepidx = self.repr.rposition_elem(&SEP_BYTE);
-                true
-            }
-        }
-    }
-
-    fn root_path(&self) -> Option<Path> {
-        if self.is_absolute() {
-            Some(Path::new("/"))
-        } else {
-            None
-        }
-    }
-
-    #[inline]
-    fn is_absolute(&self) -> bool {
-        self.repr[0] == SEP_BYTE
-    }
-
-    fn is_ancestor_of(&self, other: &Path) -> bool {
-        if self.is_absolute() != other.is_absolute() {
-            false
-        } else {
-            let mut ita = self.components();
-            let mut itb = other.components();
-            if b"." == self.repr {
-                return match itb.next() {
-                    None => true,
-                    Some(b) => b != b".."
-                };
-            }
-            loop {
-                match (ita.next(), itb.next()) {
-                    (None, _) => break,
-                    (Some(a), Some(b)) if a == b => { continue },
-                    (Some(a), _) if a == b".." => {
-                        // if ita contains only .. components, it's an ancestor
-                        return ita.all(|x| x == b"..");
-                    }
-                    _ => return false
-                }
-            }
-            true
-        }
-    }
-
-    fn path_relative_from(&self, base: &Path) -> Option<Path> {
-        if self.is_absolute() != base.is_absolute() {
-            if self.is_absolute() {
-                Some(self.clone())
-            } else {
-                None
-            }
-        } else {
-            let mut ita = self.components();
-            let mut itb = base.components();
-            let mut comps = vec![];
-            loop {
-                match (ita.next(), itb.next()) {
-                    (None, None) => break,
-                    (Some(a), None) => {
-                        comps.push(a);
-                        comps.extend(ita.by_ref());
-                        break;
-                    }
-                    (None, _) => comps.push(dot_dot_static),
-                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
-                    (Some(a), Some(b)) if b == b"." => comps.push(a),
-                    (Some(_), Some(b)) if b == b".." => return None,
-                    (Some(a), Some(_)) => {
-                        comps.push(dot_dot_static);
-                        for _ in itb {
-                            comps.push(dot_dot_static);
-                        }
-                        comps.push(a);
-                        comps.extend(ita.by_ref());
-                        break;
-                    }
-                }
-            }
-            Some(Path::new(comps.connect(&SEP_BYTE)))
-        }
-    }
-
-    fn ends_with_path(&self, child: &Path) -> bool {
-        if !child.is_relative() { return false; }
-        let mut selfit = self.components().rev();
-        let mut childit = child.components().rev();
-        loop {
-            match (selfit.next(), childit.next()) {
-                (Some(a), Some(b)) => if a != b { return false; },
-                (Some(_), None) => break,
-                (None, Some(_)) => return false,
-                (None, None) => break
-            }
-        }
-        true
-    }
-}
-
-impl Path {
-    /// Returns a new Path from a byte vector or string
-    ///
-    /// # Panics
-    ///
-    /// Panics the task if the vector contains a NUL.
-    #[inline]
-    pub fn new<T: BytesContainer>(path: T) -> Path {
-        GenericPath::new(path)
-    }
-
-    /// Returns a new Path from a byte vector or string, if possible
-    #[inline]
-    pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
-        GenericPath::new_opt(path)
-    }
-
-    /// Returns a normalized byte vector representation of a path, by removing all empty
-    /// components, and unnecessary . and .. components.
-    fn normalize<V: ?Sized + AsSlice<u8>>(v: &V) -> Vec<u8> {
-        // borrowck is being very picky
-        let val = {
-            let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
-            let v_ = if is_abs { &v.as_slice()[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(vec![SEP_BYTE])
-                    } else {
-                        let n = if is_abs { comps.len() } else { comps.len() - 1} +
-                                comps.iter().map(|v| v.len()).sum();
-                        let mut v = Vec::with_capacity(n);
-                        let mut it = comps.into_iter();
-                        if !is_abs {
-                            match it.next() {
-                                None => (),
-                                Some(comp) => v.push_all(comp)
-                            }
-                        }
-                        for comp in it {
-                            v.push(SEP_BYTE);
-                            v.push_all(comp);
-                        }
-                        Some(v)
-                    }
-                }
-            }
-        };
-        match val {
-            None => v.as_slice().to_vec(),
-            Some(val) => val
-        }
-    }
-
-    /// Returns an iterator that yields each component of the path in turn.
-    /// Does not distinguish between absolute and relative paths, e.g.
-    /// /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 components<'a>(&'a self) -> Components<'a> {
-        let v = if self.repr[0] == SEP_BYTE {
-            &self.repr[1..]
-        } else { self.repr.as_slice() };
-        let is_sep_byte: fn(&u8) -> bool = is_sep_byte; // coerce to fn ptr
-        let mut ret = v.split(is_sep_byte);
-        if v.is_empty() {
-            // consume the empty "" component
-            ret.next();
-        }
-        ret
-    }
-
-    /// Returns an iterator that yields each component of the path as Option<&str>.
-    /// See components() for details.
-    pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
-        fn from_utf8(s: &[u8]) -> Option<&str> {
-            str::from_utf8(s).ok()
-        }
-        let f: fn(&[u8]) -> Option<&str> = from_utf8; // coerce to fn ptr
-        self.components().map(f)
-    }
-}
-
-// None result means the byte vector didn't need normalizing
-fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<Vec<&'a [u8]>> {
-    if is_abs && v.is_empty() {
-        return None;
-    }
-    let mut comps: Vec<&'a [u8]> = vec![];
-    let mut n_up = 0u;
-    let mut changed = false;
-    for comp in v.split(is_sep_byte) {
-        if comp.is_empty() { changed = true }
-        else if comp == b"." { changed = true }
-        else if comp == b".." {
-            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().unwrap(); changed = true }
-        } else { comps.push(comp) }
-    }
-    if changed {
-        if comps.is_empty() && !is_abs {
-            if v == b"." {
-                return None;
-            }
-            comps.push(dot_static);
-        }
-        Some(comps)
-    } else {
-        None
-    }
-}
-
-#[allow(non_upper_case_globals)]
-static dot_static: &'static [u8] = b".";
-#[allow(non_upper_case_globals)]
-static dot_dot_static: &'static [u8] = b"..";
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    use clone::Clone;
-    use iter::IteratorExt;
-    use option::Option::{self, Some, None};
-    use path::GenericPath;
-    use slice::{AsSlice, SliceExt};
-    use str::{self, Str, StrExt};
-    use string::ToString;
-    use vec::Vec;
-
-    macro_rules! t {
-        (s: $path:expr, $exp:expr) => (
-            {
-                let path = $path;
-                assert_eq!(path.as_str(), Some($exp));
-            }
-        );
-        (v: $path:expr, $exp:expr) => (
-            {
-                let path = $path;
-                assert_eq!(path.as_vec(), $exp);
-            }
-        )
-    }
-
-    #[test]
-    fn test_paths() {
-        let empty: &[u8] = &[];
-        t!(v: Path::new(empty), b".");
-        t!(v: Path::new(b"/"), b"/");
-        t!(v: Path::new(b"a/b/c"), b"a/b/c");
-        t!(v: Path::new(b"a/b/c\xFF"), b"a/b/c\xFF");
-        t!(v: Path::new(b"\xFF/../foo\x80"), b"foo\x80");
-        let p = Path::new(b"a/b/c\xFF");
-        assert!(p.as_str().is_none());
-
-        t!(s: Path::new(""), ".");
-        t!(s: Path::new("/"), "/");
-        t!(s: Path::new("hi"), "hi");
-        t!(s: Path::new("hi/"), "hi");
-        t!(s: Path::new("/lib"), "/lib");
-        t!(s: Path::new("/lib/"), "/lib");
-        t!(s: Path::new("hi/there"), "hi/there");
-        t!(s: Path::new("hi/there.txt"), "hi/there.txt");
-
-        t!(s: Path::new("hi/there/"), "hi/there");
-        t!(s: Path::new("hi/../there"), "there");
-        t!(s: Path::new("../hi/there"), "../hi/there");
-        t!(s: Path::new("/../hi/there"), "/hi/there");
-        t!(s: Path::new("foo/.."), ".");
-        t!(s: Path::new("/foo/.."), "/");
-        t!(s: Path::new("/foo/../.."), "/");
-        t!(s: Path::new("/foo/../../bar"), "/bar");
-        t!(s: Path::new("/./hi/./there/."), "/hi/there");
-        t!(s: Path::new("/./hi/./there/./.."), "/hi");
-        t!(s: Path::new("foo/../.."), "..");
-        t!(s: Path::new("foo/../../.."), "../..");
-        t!(s: Path::new("foo/../../bar"), "../bar");
-
-        assert_eq!(Path::new(b"foo/bar").into_vec(), b"foo/bar");
-        assert_eq!(Path::new(b"/foo/../../bar").into_vec(),
-                   b"/bar");
-
-        let p = Path::new(b"foo/bar\x80");
-        assert!(p.as_str().is_none());
-    }
-
-    #[test]
-    fn test_opt_paths() {
-        assert!(Path::new_opt(b"foo/bar\0").is_none());
-        t!(v: Path::new_opt(b"foo/bar").unwrap(), b"foo/bar");
-        assert!(Path::new_opt("foo/bar\0").is_none());
-        t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar");
-    }
-
-    #[test]
-    fn test_null_byte() {
-        use thread::Thread;
-        let result = Thread::scoped(move|| {
-            Path::new(b"foo/bar\0")
-        }).join();
-        assert!(result.is_err());
-
-        let result = Thread::scoped(move|| {
-            Path::new("test").set_filename(b"f\0o")
-        }).join();
-        assert!(result.is_err());
-
-        let result = Thread::scoped(move|| {
-            Path::new("test").push(b"f\0o");
-        }).join();
-        assert!(result.is_err());
-    }
-
-    #[test]
-    fn test_display_str() {
-        macro_rules! t {
-            ($path:expr, $disp:ident, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    assert_eq!(path.$disp().to_string(), $exp);
-                }
-            )
-        }
-        t!("foo", display, "foo");
-        t!(b"foo\x80", display, "foo\u{FFFD}");
-        t!(b"foo\xFFbar", display, "foo\u{FFFD}bar");
-        t!(b"foo\xFF/bar", filename_display, "bar");
-        t!(b"foo/\xFFbar", filename_display, "\u{FFFD}bar");
-        t!(b"/", filename_display, "");
-
-        macro_rules! t {
-            ($path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let mo = path.display().as_cow();
-                    assert_eq!(mo.as_slice(), $exp);
-                }
-            );
-            ($path:expr, $exp:expr, filename) => (
-                {
-                    let path = Path::new($path);
-                    let mo = path.filename_display().as_cow();
-                    assert_eq!(mo.as_slice(), $exp);
-                }
-            )
-        }
-
-        t!("foo", "foo");
-        t!(b"foo\x80", "foo\u{FFFD}");
-        t!(b"foo\xFFbar", "foo\u{FFFD}bar");
-        t!(b"foo\xFF/bar", "bar", filename);
-        t!(b"foo/\xFFbar", "\u{FFFD}bar", filename);
-        t!(b"/", "", filename);
-    }
-
-    #[test]
-    fn test_display() {
-        macro_rules! t {
-            ($path:expr, $exp:expr, $expf:expr) => (
-                {
-                    let path = Path::new($path);
-                    let f = format!("{}", path.display());
-                    assert_eq!(f, $exp);
-                    let f = format!("{}", path.filename_display());
-                    assert_eq!(f, $expf);
-                }
-            )
-        }
-
-        t!(b"foo", "foo", "foo");
-        t!(b"foo/bar", "foo/bar", "bar");
-        t!(b"/", "/", "");
-        t!(b"foo\xFF", "foo\u{FFFD}", "foo\u{FFFD}");
-        t!(b"foo\xFF/bar", "foo\u{FFFD}/bar", "bar");
-        t!(b"foo/\xFFbar", "foo/\u{FFFD}bar", "\u{FFFD}bar");
-        t!(b"\xFFfoo/bar\xFF", "\u{FFFD}foo/bar\u{FFFD}", "bar\u{FFFD}");
-    }
-
-    #[test]
-    fn test_components() {
-        macro_rules! t {
-            (s: $path:expr, $op:ident, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    assert_eq!(path.$op(), ($exp).as_bytes());
-                }
-            );
-            (s: $path:expr, $op:ident, $exp:expr, opt) => (
-                {
-                    let path = Path::new($path);
-                    let left = path.$op().map(|x| str::from_utf8(x).unwrap());
-                    assert_eq!(left, $exp);
-                }
-            );
-            (v: $path:expr, $op:ident, $exp:expr) => (
-                {
-                    let arg = $path;
-                    let path = Path::new(arg);
-                    assert_eq!(path.$op(), $exp);
-                }
-            );
-        }
-
-        t!(v: b"a/b/c", filename, Some(b"c"));
-        t!(v: b"a/b/c\xFF", filename, Some(b"c\xFF"));
-        t!(v: b"a/b\xFF/c", filename, Some(b"c"));
-        t!(s: "a/b/c", filename, Some("c"), opt);
-        t!(s: "/a/b/c", filename, Some("c"), opt);
-        t!(s: "a", filename, Some("a"), opt);
-        t!(s: "/a", filename, Some("a"), opt);
-        t!(s: ".", filename, None, opt);
-        t!(s: "/", filename, None, opt);
-        t!(s: "..", filename, None, opt);
-        t!(s: "../..", filename, None, opt);
-
-        t!(v: b"a/b/c", dirname, b"a/b");
-        t!(v: b"a/b/c\xFF", dirname, b"a/b");
-        t!(v: b"a/b\xFF/c", dirname, b"a/b\xFF");
-        t!(s: "a/b/c", dirname, "a/b");
-        t!(s: "/a/b/c", dirname, "/a/b");
-        t!(s: "a", dirname, ".");
-        t!(s: "/a", dirname, "/");
-        t!(s: ".", dirname, ".");
-        t!(s: "/", dirname, "/");
-        t!(s: "..", dirname, "..");
-        t!(s: "../..", dirname, "../..");
-
-        t!(v: b"hi/there.txt", filestem, Some(b"there"));
-        t!(v: b"hi/there\x80.txt", filestem, Some(b"there\x80"));
-        t!(v: b"hi/there.t\x80xt", filestem, Some(b"there"));
-        t!(s: "hi/there.txt", filestem, Some("there"), opt);
-        t!(s: "hi/there", filestem, Some("there"), opt);
-        t!(s: "there.txt", filestem, Some("there"), opt);
-        t!(s: "there", filestem, Some("there"), opt);
-        t!(s: ".", filestem, None, opt);
-        t!(s: "/", filestem, None, opt);
-        t!(s: "foo/.bar", filestem, Some(".bar"), opt);
-        t!(s: ".bar", filestem, Some(".bar"), opt);
-        t!(s: "..bar", filestem, Some("."), opt);
-        t!(s: "hi/there..txt", filestem, Some("there."), opt);
-        t!(s: "..", filestem, None, opt);
-        t!(s: "../..", filestem, None, opt);
-
-        t!(v: b"hi/there.txt", extension, Some(b"txt"));
-        t!(v: b"hi/there\x80.txt", extension, Some(b"txt"));
-        t!(v: b"hi/there.t\x80xt", extension, Some(b"t\x80xt"));
-        t!(v: b"hi/there", extension, None);
-        t!(v: b"hi/there\x80", extension, None);
-        t!(s: "hi/there.txt", extension, Some("txt"), opt);
-        t!(s: "hi/there", extension, None, opt);
-        t!(s: "there.txt", extension, Some("txt"), opt);
-        t!(s: "there", extension, None, opt);
-        t!(s: ".", extension, None, opt);
-        t!(s: "/", extension, None, opt);
-        t!(s: "foo/.bar", extension, None, opt);
-        t!(s: ".bar", extension, None, opt);
-        t!(s: "..bar", extension, Some("bar"), opt);
-        t!(s: "hi/there..txt", extension, Some("txt"), opt);
-        t!(s: "..", extension, None, opt);
-        t!(s: "../..", extension, None, opt);
-    }
-
-    #[test]
-    fn test_push() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr) => (
-                {
-                    let path = $path;
-                    let join = $join;
-                    let mut p1 = Path::new(path);
-                    let p2 = p1.clone();
-                    p1.push(join);
-                    assert_eq!(p1, p2.join(join));
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "..");
-        t!(s: "/a/b/c", "d");
-        t!(s: "a/b", "c/d");
-        t!(s: "a/b", "/c/d");
-    }
-
-    #[test]
-    fn test_push_path() {
-        macro_rules! t {
-            (s: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    let push = Path::new($push);
-                    p.push(&push);
-                    assert_eq!(p.as_str(), Some($exp));
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "d", "a/b/c/d");
-        t!(s: "/a/b/c", "d", "/a/b/c/d");
-        t!(s: "a/b", "c/d", "a/b/c/d");
-        t!(s: "a/b", "/c/d", "/c/d");
-        t!(s: "a/b", ".", "a/b");
-        t!(s: "a/b", "../c", "a/c");
-    }
-
-    #[test]
-    fn test_push_many() {
-        macro_rules! t {
-            (s: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    p.push_many(&$push);
-                    assert_eq!(p.as_str(), Some($exp));
-                }
-            );
-            (v: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    p.push_many(&$push);
-                    assert_eq!(p.as_vec(), $exp);
-                }
-            )
-        }
-
-        t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
-        t!(s: "a/b/c", ["d", "/e"], "/e");
-        t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
-        t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e");
-        t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e");
-        t!(v: b"a/b/c", [b"d", b"/e", b"f"], b"/e/f");
-        t!(v: b"a/b/c", [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e");
-    }
-
-    #[test]
-    fn test_pop() {
-        macro_rules! t {
-            (s: $path:expr, $left:expr, $right:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    let result = p.pop();
-                    assert_eq!(p.as_str(), Some($left));
-                    assert_eq!(result, $right);
-                }
-            );
-            (b: $path:expr, $left:expr, $right:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    let result = p.pop();
-                    assert_eq!(p.as_vec(), $left);
-                    assert_eq!(result, $right);
-                }
-            )
-        }
-
-        t!(b: b"a/b/c", b"a/b", true);
-        t!(b: b"a", b".", true);
-        t!(b: b".", b".", false);
-        t!(b: b"/a", b"/", true);
-        t!(b: b"/", b"/", false);
-        t!(b: b"a/b/c\x80", b"a/b", true);
-        t!(b: b"a/b\x80/c", b"a/b\x80", true);
-        t!(b: b"\xFF", b".", true);
-        t!(b: b"/\xFF", b"/", true);
-        t!(s: "a/b/c", "a/b", true);
-        t!(s: "a", ".", true);
-        t!(s: ".", ".", false);
-        t!(s: "/a", "/", true);
-        t!(s: "/", "/", false);
-    }
-
-    #[test]
-    fn test_root_path() {
-        assert_eq!(Path::new(b"a/b/c").root_path(), None);
-        assert_eq!(Path::new(b"/a/b/c").root_path(), Some(Path::new("/")));
-    }
-
-    #[test]
-    fn test_join() {
-        t!(v: Path::new(b"a/b/c").join(b".."), b"a/b");
-        t!(v: Path::new(b"/a/b/c").join(b"d"), b"/a/b/c/d");
-        t!(v: Path::new(b"a/\x80/c").join(b"\xFF"), b"a/\x80/c/\xFF");
-        t!(s: Path::new("a/b/c").join(".."), "a/b");
-        t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d");
-        t!(s: Path::new("a/b").join("c/d"), "a/b/c/d");
-        t!(s: Path::new("a/b").join("/c/d"), "/c/d");
-        t!(s: Path::new(".").join("a/b"), "a/b");
-        t!(s: Path::new("/").join("a/b"), "/a/b");
-    }
-
-    #[test]
-    fn test_join_path() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let join = Path::new($join);
-                    let res = path.join(&join);
-                    assert_eq!(res.as_str(), Some($exp));
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "..", "a/b");
-        t!(s: "/a/b/c", "d", "/a/b/c/d");
-        t!(s: "a/b", "c/d", "a/b/c/d");
-        t!(s: "a/b", "/c/d", "/c/d");
-        t!(s: ".", "a/b", "a/b");
-        t!(s: "/", "a/b", "/a/b");
-    }
-
-    #[test]
-    fn test_join_many() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let res = path.join_many(&$join);
-                    assert_eq!(res.as_str(), Some($exp));
-                }
-            );
-            (v: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let res = path.join_many(&$join);
-                    assert_eq!(res.as_vec(), $exp);
-                }
-            )
-        }
-
-        t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
-        t!(s: "a/b/c", ["..", "d"], "a/b/d");
-        t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
-        t!(s: "a/b/c", ["d".to_string(), "e".to_string()], "a/b/c/d/e");
-        t!(v: b"a/b/c", [b"d", b"e"], b"a/b/c/d/e");
-        t!(v: b"a/b/c", [b"d".to_vec(), b"e".to_vec()], b"a/b/c/d/e");
-    }
-
-    #[test]
-    fn test_with_helpers() {
-        let empty: &[u8] = &[];
-
-        t!(v: Path::new(b"a/b/c").with_filename(b"d"), b"a/b/d");
-        t!(v: Path::new(b"a/b/c\xFF").with_filename(b"\x80"), b"a/b/\x80");
-        t!(v: Path::new(b"/\xFF/foo").with_filename(b"\xCD"),
-              b"/\xFF/\xCD");
-        t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d");
-        t!(s: Path::new(".").with_filename("foo"), "foo");
-        t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d");
-        t!(s: Path::new("/").with_filename("foo"), "/foo");
-        t!(s: Path::new("/a").with_filename("foo"), "/foo");
-        t!(s: Path::new("foo").with_filename("bar"), "bar");
-        t!(s: Path::new("/").with_filename("foo/"), "/foo");
-        t!(s: Path::new("/a").with_filename("foo/"), "/foo");
-        t!(s: Path::new("a/b/c").with_filename(""), "a/b");
-        t!(s: Path::new("a/b/c").with_filename("."), "a/b");
-        t!(s: Path::new("a/b/c").with_filename(".."), "a");
-        t!(s: Path::new("/a").with_filename(""), "/");
-        t!(s: Path::new("foo").with_filename(""), ".");
-        t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e");
-        t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d");
-        t!(s: Path::new("..").with_filename("foo"), "../foo");
-        t!(s: Path::new("../..").with_filename("foo"), "../../foo");
-        t!(s: Path::new("..").with_filename(""), "..");
-        t!(s: Path::new("../..").with_filename(""), "../..");
-
-        t!(v: Path::new(b"hi/there\x80.txt").with_extension(b"exe"),
-              b"hi/there\x80.exe");
-        t!(v: Path::new(b"hi/there.txt\x80").with_extension(b"\xFF"),
-              b"hi/there.\xFF");
-        t!(v: Path::new(b"hi/there\x80").with_extension(b"\xFF"),
-              b"hi/there\x80.\xFF");
-        t!(v: Path::new(b"hi/there.\xFF").with_extension(empty), b"hi/there");
-        t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe");
-        t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there");
-        t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there..");
-        t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there...");
-        t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt");
-        t!(s: Path::new("hi/there").with_extension("."), "hi/there..");
-        t!(s: Path::new("hi/there").with_extension(".."), "hi/there...");
-        t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt");
-        t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt");
-        t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo");
-        t!(s: Path::new("/").with_extension("txt"), "/");
-        t!(s: Path::new("/").with_extension("."), "/");
-        t!(s: Path::new("/").with_extension(".."), "/");
-        t!(s: Path::new(".").with_extension("txt"), ".");
-    }
-
-    #[test]
-    fn test_setters() {
-        macro_rules! t {
-            (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
-                {
-                    let path = $path;
-                    let arg = $arg;
-                    let mut p1 = Path::new(path);
-                    p1.$set(arg);
-                    let p2 = Path::new(path);
-                    assert_eq!(p1, p2.$with(arg));
-                }
-            );
-            (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
-                {
-                    let path = $path;
-                    let arg = $arg;
-                    let mut p1 = Path::new(path);
-                    p1.$set(arg);
-                    let p2 = Path::new(path);
-                    assert_eq!(p1, p2.$with(arg));
-                }
-            )
-        }
-
-        t!(v: b"a/b/c", set_filename, with_filename, b"d");
-        t!(v: b"/", set_filename, with_filename, b"foo");
-        t!(v: b"\x80", set_filename, with_filename, b"\xFF");
-        t!(s: "a/b/c", set_filename, with_filename, "d");
-        t!(s: "/", set_filename, with_filename, "foo");
-        t!(s: ".", set_filename, with_filename, "foo");
-        t!(s: "a/b", set_filename, with_filename, "");
-        t!(s: "a", set_filename, with_filename, "");
-
-        t!(v: b"hi/there.txt", set_extension, with_extension, b"exe");
-        t!(v: b"hi/there.t\x80xt", set_extension, with_extension, b"exe\xFF");
-        t!(s: "hi/there.txt", set_extension, with_extension, "exe");
-        t!(s: "hi/there.", set_extension, with_extension, "txt");
-        t!(s: "hi/there", set_extension, with_extension, "txt");
-        t!(s: "hi/there.txt", set_extension, with_extension, "");
-        t!(s: "hi/there", set_extension, with_extension, "");
-        t!(s: ".", set_extension, with_extension, "txt");
-    }
-
-    #[test]
-    fn test_getters() {
-        macro_rules! t {
-            (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
-                {
-                    let path = $path;
-                    assert_eq!(path.filename_str(), $filename);
-                    assert_eq!(path.dirname_str(), $dirname);
-                    assert_eq!(path.filestem_str(), $filestem);
-                    assert_eq!(path.extension_str(), $ext);
-               }
-            );
-            (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
-                {
-                    let path = $path;
-                    assert_eq!(path.filename(), $filename);
-                    assert_eq!(path.dirname(), $dirname);
-                    assert_eq!(path.filestem(), $filestem);
-                    assert_eq!(path.extension(), $ext);
-                }
-            )
-        }
-
-        t!(v: Path::new(b"a/b/c"), Some(b"c"), b"a/b", Some(b"c"), None);
-        t!(v: Path::new(b"a/b/\xFF"), Some(b"\xFF"), b"a/b", Some(b"\xFF"), None);
-        t!(v: Path::new(b"hi/there.\xFF"), Some(b"there.\xFF"), b"hi",
-              Some(b"there"), Some(b"\xFF"));
-        t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None);
-        t!(s: Path::new("."), None, Some("."), None, None);
-        t!(s: Path::new("/"), None, Some("/"), None, None);
-        t!(s: Path::new(".."), None, Some(".."), None, None);
-        t!(s: Path::new("../.."), None, Some("../.."), None, None);
-        t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
-              Some("there"), Some("txt"));
-        t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
-        t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
-              Some("there"), Some(""));
-        t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
-        t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
-              Some("."), Some("there"));
-        t!(s: Path::new(b"a/b/\xFF"), None, Some("a/b"), None, None);
-        t!(s: Path::new(b"a/b/\xFF.txt"), None, Some("a/b"), None, Some("txt"));
-        t!(s: Path::new(b"a/b/c.\x80"), None, Some("a/b"), Some("c"), None);
-        t!(s: Path::new(b"\xFF/b"), Some("b"), None, Some("b"), None);
-    }
-
-    #[test]
-    fn test_dir_path() {
-        t!(v: Path::new(b"hi/there\x80").dir_path(), b"hi");
-        t!(v: Path::new(b"hi\xFF/there").dir_path(), b"hi\xFF");
-        t!(s: Path::new("hi/there").dir_path(), "hi");
-        t!(s: Path::new("hi").dir_path(), ".");
-        t!(s: Path::new("/hi").dir_path(), "/");
-        t!(s: Path::new("/").dir_path(), "/");
-        t!(s: Path::new("..").dir_path(), "..");
-        t!(s: Path::new("../..").dir_path(), "../..");
-    }
-
-    #[test]
-    fn test_is_absolute() {
-        macro_rules! t {
-            (s: $path:expr, $abs:expr, $rel:expr) => (
-                {
-                    let path = Path::new($path);
-                    assert_eq!(path.is_absolute(), $abs);
-                    assert_eq!(path.is_relative(), $rel);
-                }
-            )
-        }
-        t!(s: "a/b/c", false, true);
-        t!(s: "/a/b/c", true, false);
-        t!(s: "a", false, true);
-        t!(s: "/a", true, false);
-        t!(s: ".", false, true);
-        t!(s: "/", true, false);
-        t!(s: "..", false, true);
-        t!(s: "../..", false, true);
-    }
-
-    #[test]
-    fn test_is_ancestor_of() {
-        macro_rules! t {
-            (s: $path:expr, $dest:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let dest = Path::new($dest);
-                    assert_eq!(path.is_ancestor_of(&dest), $exp);
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "a/b/c/d", true);
-        t!(s: "a/b/c", "a/b/c", true);
-        t!(s: "a/b/c", "a/b", false);
-        t!(s: "/a/b/c", "/a/b/c", true);
-        t!(s: "/a/b", "/a/b/c", true);
-        t!(s: "/a/b/c/d", "/a/b/c", false);
-        t!(s: "/a/b", "a/b/c", false);
-        t!(s: "a/b", "/a/b/c", false);
-        t!(s: "a/b/c", "a/b/d", false);
-        t!(s: "../a/b/c", "a/b/c", false);
-        t!(s: "a/b/c", "../a/b/c", false);
-        t!(s: "a/b/c", "a/b/cd", false);
-        t!(s: "a/b/cd", "a/b/c", false);
-        t!(s: "../a/b", "../a/b/c", true);
-        t!(s: ".", "a/b", true);
-        t!(s: ".", ".", true);
-        t!(s: "/", "/", true);
-        t!(s: "/", "/a/b", true);
-        t!(s: "..", "a/b", true);
-        t!(s: "../..", "a/b", true);
-    }
-
-    #[test]
-    fn test_ends_with_path() {
-        macro_rules! t {
-            (s: $path:expr, $child:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let child = Path::new($child);
-                    assert_eq!(path.ends_with_path(&child), $exp);
-                }
-            );
-            (v: $path:expr, $child:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let child = Path::new($child);
-                    assert_eq!(path.ends_with_path(&child), $exp);
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "c", true);
-        t!(s: "a/b/c", "d", false);
-        t!(s: "foo/bar/quux", "bar", false);
-        t!(s: "foo/bar/quux", "barquux", false);
-        t!(s: "a/b/c", "b/c", true);
-        t!(s: "a/b/c", "a/b/c", true);
-        t!(s: "a/b/c", "foo/a/b/c", false);
-        t!(s: "/a/b/c", "a/b/c", true);
-        t!(s: "/a/b/c", "/a/b/c", false); // child must be relative
-        t!(s: "/a/b/c", "foo/a/b/c", false);
-        t!(s: "a/b/c", "", false);
-        t!(s: "", "", true);
-        t!(s: "/a/b/c", "d/e/f", false);
-        t!(s: "a/b/c", "a/b", false);
-        t!(s: "a/b/c", "b", false);
-        t!(v: b"a/b/c", b"b/c", true);
-        t!(v: b"a/b/\xFF", b"\xFF", true);
-        t!(v: b"a/b/\xFF", b"b/\xFF", true);
-    }
-
-    #[test]
-    fn test_path_relative_from() {
-        macro_rules! t {
-            (s: $path:expr, $other:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let other = Path::new($other);
-                    let res = path.path_relative_from(&other);
-                    assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
-                }
-            )
-        }
-
-        t!(s: "a/b/c", "a/b", Some("c"));
-        t!(s: "a/b/c", "a/b/d", Some("../c"));
-        t!(s: "a/b/c", "a/b/c/d", Some(".."));
-        t!(s: "a/b/c", "a/b/c", Some("."));
-        t!(s: "a/b/c", "a/b/c/d/e", Some("../.."));
-        t!(s: "a/b/c", "a/d/e", Some("../../b/c"));
-        t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c"));
-        t!(s: "a/b/c", "/a/b/c", None);
-        t!(s: "/a/b/c", "a/b/c", Some("/a/b/c"));
-        t!(s: "/a/b/c", "/a/b/c/d", Some(".."));
-        t!(s: "/a/b/c", "/a/b", Some("c"));
-        t!(s: "/a/b/c", "/a/b/c/d/e", Some("../.."));
-        t!(s: "/a/b/c", "/a/d/e", Some("../../b/c"));
-        t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c"));
-        t!(s: "hi/there.txt", "hi/there", Some("../there.txt"));
-        t!(s: ".", "a", Some(".."));
-        t!(s: ".", "a/b", Some("../.."));
-        t!(s: ".", ".", Some("."));
-        t!(s: "a", ".", Some("a"));
-        t!(s: "a/b", ".", Some("a/b"));
-        t!(s: "..", ".", Some(".."));
-        t!(s: "a/b/c", "a/b/c", Some("."));
-        t!(s: "/a/b/c", "/a/b/c", Some("."));
-        t!(s: "/", "/", Some("."));
-        t!(s: "/", ".", Some("/"));
-        t!(s: "../../a", "b", Some("../../../a"));
-        t!(s: "a", "../../b", None);
-        t!(s: "../../a", "../../b", Some("../a"));
-        t!(s: "../../a", "../../a/b", Some(".."));
-        t!(s: "../../a/b", "../../a", Some("b"));
-    }
-
-    #[test]
-    fn test_components_iter() {
-        macro_rules! t {
-            (s: $path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let comps = path.components().collect::<Vec<&[u8]>>();
-                    let exp: &[&str] = &$exp;
-                    let exps = exp.iter().map(|x| x.as_bytes()).collect::<Vec<&[u8]>>();
-                    assert_eq!(comps, exps);
-                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
-                    let exps = exps.into_iter().rev().collect::<Vec<&[u8]>>();
-                    assert_eq!(comps, exps);
-                }
-            );
-            (b: $arg:expr, [$($exp:expr),*]) => (
-                {
-                    let path = Path::new($arg);
-                    let comps = path.components().collect::<Vec<&[u8]>>();
-                    let exp: &[&[u8]] = &[$($exp),*];
-                    assert_eq!(comps, exp);
-                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
-                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
-                    assert_eq!(comps, exp)
-                }
-            )
-        }
-
-        t!(b: b"a/b/c", [b"a", b"b", b"c"]);
-        t!(b: b"/\xFF/a/\x80", [b"\xFF", b"a", b"\x80"]);
-        t!(b: b"../../foo\xCDbar", [b"..", b"..", b"foo\xCDbar"]);
-        t!(s: "a/b/c", ["a", "b", "c"]);
-        t!(s: "a/b/d", ["a", "b", "d"]);
-        t!(s: "a/b/cd", ["a", "b", "cd"]);
-        t!(s: "/a/b/c", ["a", "b", "c"]);
-        t!(s: "a", ["a"]);
-        t!(s: "/a", ["a"]);
-        t!(s: "/", []);
-        t!(s: ".", ["."]);
-        t!(s: "..", [".."]);
-        t!(s: "../..", ["..", ".."]);
-        t!(s: "../../foo", ["..", "..", "foo"]);
-    }
-
-    #[test]
-    fn test_str_components() {
-        macro_rules! t {
-            (b: $arg:expr, $exp:expr) => (
-                {
-                    let path = Path::new($arg);
-                    let comps = path.str_components().collect::<Vec<Option<&str>>>();
-                    let exp: &[Option<&str>] = &$exp;
-                    assert_eq!(comps, exp);
-                    let comps = path.str_components().rev().collect::<Vec<Option<&str>>>();
-                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<Option<&str>>>();
-                    assert_eq!(comps, exp);
-                }
-            )
-        }
-
-        t!(b: b"a/b/c", [Some("a"), Some("b"), Some("c")]);
-        t!(b: b"/\xFF/a/\x80", [None, Some("a"), None]);
-        t!(b: b"../../foo\xCDbar", [Some(".."), Some(".."), None]);
-        // str_components is a wrapper around components, so no need to do
-        // the full set of tests
-    }
-}
-
-#[cfg(test)]
-mod bench {
-    extern crate test;
-    use self::test::Bencher;
-    use super::*;
-    use prelude::v1::{Clone, GenericPath};
-
-    #[bench]
-    fn join_home_dir(b: &mut Bencher) {
-        let posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.join("home");
-        });
-    }
-
-    #[bench]
-    fn join_abs_path_home_dir(b: &mut Bencher) {
-        let posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.join("/home");
-        });
-    }
-
-    #[bench]
-    fn join_many_home_dir(b: &mut Bencher) {
-        let posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.join_many(&["home"]);
-        });
-    }
-
-    #[bench]
-    fn join_many_abs_path_home_dir(b: &mut Bencher) {
-        let posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.join_many(&["/home"]);
-        });
-    }
-
-    #[bench]
-    fn push_home_dir(b: &mut Bencher) {
-        let mut posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.push("home");
-        });
-    }
-
-    #[bench]
-    fn push_abs_path_home_dir(b: &mut Bencher) {
-        let mut posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.push("/home");
-        });
-    }
-
-    #[bench]
-    fn push_many_home_dir(b: &mut Bencher) {
-        let mut posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.push_many(&["home"]);
-        });
-    }
-
-    #[bench]
-    fn push_many_abs_path_home_dir(b: &mut Bencher) {
-        let mut posix_path = Path::new("/");
-        b.iter(|| {
-            posix_path.push_many(&["/home"]);
-        });
-    }
-
-    #[bench]
-    fn ends_with_path_home_dir(b: &mut Bencher) {
-        let posix_home_path = Path::new("/home");
-        b.iter(|| {
-            posix_home_path.ends_with_path(&Path::new("home"));
-        });
-    }
-
-    #[bench]
-    fn ends_with_path_missmatch_jome_home(b: &mut Bencher) {
-        let posix_home_path = Path::new("/home");
-        b.iter(|| {
-            posix_home_path.ends_with_path(&Path::new("jome"));
-        });
-    }
-
-    #[bench]
-    fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) {
-        let path = Path::new("/home/1/2/3/4/5/6/7/8/9");
-        let mut sub = path.clone();
-        sub.pop();
-        b.iter(|| {
-            path.is_ancestor_of(&sub);
-        });
-    }
-
-    #[bench]
-    fn path_relative_from_forward(b: &mut Bencher) {
-        let path = Path::new("/a/b/c");
-        let mut other = path.clone();
-        other.pop();
-        b.iter(|| {
-            path.path_relative_from(&other);
-        });
-    }
-
-    #[bench]
-    fn path_relative_from_same_level(b: &mut Bencher) {
-        let path = Path::new("/a/b/c");
-        let mut other = path.clone();
-        other.pop();
-        other.push("d");
-        b.iter(|| {
-            path.path_relative_from(&other);
-        });
-    }
-
-    #[bench]
-    fn path_relative_from_backward(b: &mut Bencher) {
-        let path = Path::new("/a/b");
-        let mut other = path.clone();
-        other.push("c");
-        b.iter(|| {
-            path.path_relative_from(&other);
-        });
-    }
-}
diff --git a/src/libstd/path/windows.rs b/src/libstd/path/windows.rs
deleted file mode 100644 (file)
index fcdebaf..0000000
+++ /dev/null
@@ -1,2329 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-//
-// ignore-lexer-test FIXME #15883
-
-//! Windows file path handling
-
-use self::PathPrefix::*;
-
-use ascii::AsciiExt;
-use char::CharExt;
-use clone::Clone;
-use cmp::{Ordering, Eq, Ord, PartialEq, PartialOrd};
-use fmt;
-use hash;
-use old_io::Writer;
-use iter::{AdditiveIterator, Extend};
-use iter::{Iterator, IteratorExt, Map, repeat};
-use mem;
-use option::Option::{self, Some, None};
-use result::Result::{self, Ok, Err};
-use slice::{SliceExt, SliceConcatExt};
-use str::{SplitTerminator, FromStr, StrExt};
-use string::{String, ToString};
-use vec::Vec;
-
-use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe};
-
-/// Iterator that yields successive components of a Path as &str
-///
-/// Each component is yielded as Option<&str> for compatibility with PosixPath, but
-/// every component in WindowsPath is guaranteed to be Some.
-pub type StrComponents<'a> =
-    Map<SplitTerminator<'a, char>, fn(&'a str) -> Option<&'a str>>;
-
-/// Iterator that yields successive components of a Path as &[u8]
-pub type Components<'a> =
-    Map<StrComponents<'a>, fn(Option<&str>) -> &[u8]>;
-
-/// Represents a Windows path
-// Notes for Windows path impl:
-// The MAX_PATH is 260, but 253 is the practical limit due to some API bugs
-// See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information
-// about windows paths.
-// That same page puts a bunch of restrictions on allowed characters in a path.
-// `\foo.txt` means "relative to current drive", but will not be considered to be absolute here
-// as `∃P | P.join("\foo.txt") != "\foo.txt"`.
-// `C:` is interesting, that means "the current directory on drive C".
-// Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be
-// ignored for now, though, and only added in a hypothetical .to_pwstr() function.
-// However, if a path is parsed that has \\?\, this needs to be preserved as it disables the
-// processing of "." and ".." components and / as a separator.
-// Experimentally, \\?\foo is not the same thing as \foo.
-// Also, \\foo is not valid either (certainly not equivalent to \foo).
-// Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent
-// to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be
-// best to just ignore that and normalize it to C:\foo\bar.
-//
-// Based on all this, I think the right approach is to do the following:
-// * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible
-// to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure).
-// * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly.
-// * If \\?\UNC\, treat following two path components as server\share. Don't error for missing
-//   server\share.
-// * If \\?\, parse disk from following component, if present. Don't error for missing disk.
-// * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled
-//   here, they probably aren't, but I'm not going to worry about that.
-// * Else if starts with \\, treat following two components as server\share. Don't error for missing
-//   server\share.
-// * Otherwise, attempt to parse drive from start of path.
-//
-// The only error condition imposed here is valid utf-8. All other invalid paths are simply
-// preserved by the data structure; let the Windows API error out on them.
-#[derive(Clone)]
-pub struct Path {
-    repr: String, // assumed to never be empty
-    prefix: Option<PathPrefix>,
-    sepidx: Option<uint> // index of the final separator in the non-prefix portion of repr
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl fmt::Debug for Path {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        fmt::Debug::fmt(&self.display(), f)
-    }
-}
-
-impl PartialEq for Path {
-    #[inline]
-    fn eq(&self, other: &Path) -> bool {
-        self.repr == other.repr
-    }
-}
-
-impl Eq for Path {}
-
-impl PartialOrd for Path {
-    fn partial_cmp(&self, other: &Path) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for Path {
-    fn cmp(&self, other: &Path) -> Ordering {
-        self.repr.cmp(&other.repr)
-    }
-}
-
-impl FromStr for Path {
-    type Err = ParsePathError;
-    fn from_str(s: &str) -> Result<Path, ParsePathError> {
-        match Path::new_opt(s) {
-            Some(p) => Ok(p),
-            None => Err(ParsePathError),
-        }
-    }
-}
-
-/// Value indicating that a path could not be parsed from a string.
-#[derive(Debug, Clone, PartialEq, Copy)]
-pub struct ParsePathError;
-
-impl<S: hash::Writer + hash::Hasher> hash::Hash<S> for Path {
-    #[cfg(not(test))]
-    #[inline]
-    fn hash(&self, state: &mut S) {
-        self.repr.hash(state)
-    }
-
-    #[cfg(test)]
-    #[inline]
-    fn hash(&self, _: &mut S) {
-        // No-op because the `hash` implementation will be wrong.
-    }
-}
-
-impl BytesContainer for Path {
-    #[inline]
-    fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
-        self.as_vec()
-    }
-    #[inline]
-    fn container_as_str<'a>(&'a self) -> Option<&'a str> {
-        self.as_str()
-    }
-    #[inline]
-    fn is_str(_: Option<&Path>) -> bool { true }
-}
-
-impl GenericPathUnsafe for Path {
-    /// See `GenericPathUnsafe::from_vec_unchecked`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if not valid UTF-8.
-    #[inline]
-    unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
-        let (prefix, path) = Path::normalize_(path.container_as_str().unwrap());
-        assert!(!path.is_empty());
-        let mut ret = Path{ repr: path, prefix: prefix, sepidx: None };
-        ret.update_sepidx();
-        ret
-    }
-
-    /// See `GenericPathUnsafe::set_filename_unchecked`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if not valid UTF-8.
-    unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
-        let filename = filename.container_as_str().unwrap();
-        match self.sepidx_or_prefix_len() {
-            None if ".." == self.repr => {
-                let mut s = String::with_capacity(3 + filename.len());
-                s.push_str("..");
-                s.push(SEP);
-                s.push_str(filename);
-                self.update_normalized(&s[]);
-            }
-            None => {
-                self.update_normalized(filename);
-            }
-            Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => {
-                let mut s = String::with_capacity(end + 1 + filename.len());
-                s.push_str(&self.repr[..end]);
-                s.push(SEP);
-                s.push_str(filename);
-                self.update_normalized(&s[]);
-            }
-            Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => {
-                let mut s = String::with_capacity(idxb + filename.len());
-                s.push_str(&self.repr[..idxb]);
-                s.push_str(filename);
-                self.update_normalized(&s[]);
-            }
-            Some((idxb,_,_)) => {
-                let mut s = String::with_capacity(idxb + 1 + filename.len());
-                s.push_str(&self.repr[..idxb]);
-                s.push(SEP);
-                s.push_str(filename);
-                self.update_normalized(&s[]);
-            }
-        }
-    }
-
-    /// See `GenericPathUnsafe::push_unchecked`.
-    ///
-    /// Concatenating two Windows Paths is rather complicated.
-    /// For the most part, it will behave as expected, except in the case of
-    /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no
-    /// concept of per-volume cwds like Windows does, we can't behave exactly
-    /// like Windows will. Instead, if the receiver is an absolute path on
-    /// the same volume as the new path, it will be treated as the cwd that
-    /// the new path is relative to. Otherwise, the new path will be treated
-    /// as if it were absolute and will replace the receiver outright.
-    unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
-        let path = path.container_as_str().unwrap();
-        fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool {
-            // assume prefix is Some(DiskPrefix)
-            let rest = &path[prefix_len(prefix)..];
-            !rest.is_empty() && rest.as_bytes()[0].is_ascii() && is_sep(rest.as_bytes()[0] as char)
-        }
-        fn shares_volume(me: &Path, path: &str) -> bool {
-            // path is assumed to have a prefix of Some(DiskPrefix)
-            let repr = &me.repr[];
-            match me.prefix {
-                Some(DiskPrefix) => {
-                    repr.as_bytes()[0] == path.as_bytes()[0].to_ascii_uppercase()
-                }
-                Some(VerbatimDiskPrefix) => {
-                    repr.as_bytes()[4] == path.as_bytes()[0].to_ascii_uppercase()
-                }
-                _ => false
-            }
-        }
-        fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
-            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>) {
-            let newpath = Path::normalize__(path, prefix);
-            me.repr = match newpath {
-                Some(p) => p,
-                None => String::from_str(path)
-            };
-            me.prefix = prefix;
-            me.update_sepidx();
-        }
-        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 is_verbatim(me) { Path::normalize__(path, None) }
-                        else { None };
-            let pathlen = path_.as_ref().map_or(path.len(), |p| p.len());
-            let mut s = String::with_capacity(me.repr.len() + 1 + pathlen);
-            s.push_str(&me.repr[]);
-            let plen = me.prefix_len();
-            // if me is "C:" we don't want to add a path separator
-            match me.prefix {
-                Some(DiskPrefix) if me.repr.len() == plen => (),
-                _ if !(me.repr.len() > plen && me.repr.as_bytes()[me.repr.len()-1] == SEP_BYTE) => {
-                    s.push(SEP);
-                }
-                _ => ()
-            }
-            match path_ {
-                None => s.push_str(path),
-                Some(p) => s.push_str(&p[]),
-            };
-            me.update_normalized(&s[])
-        }
-
-        if !path.is_empty() {
-            let prefix = parse_prefix(path);
-            match prefix {
-                Some(DiskPrefix) if !is_vol_abs(path, prefix) && shares_volume(self, path) => {
-                    // cwd-relative path, self is on the same volume
-                    append_path(self, &path[prefix_len(prefix)..]);
-                }
-                Some(_) => {
-                    // absolute path, or cwd-relative and self is not same volume
-                    replace_path(self, path, prefix);
-                }
-                None if !path.is_empty() && is_sep_(self.prefix, path.as_bytes()[0]) => {
-                    // volume-relative path
-                    if self.prefix.is_some() {
-                        // truncate self down to the prefix, then append
-                        let n = self.prefix_len();
-                        self.repr.truncate(n);
-                        append_path(self, path);
-                    } else {
-                        // we have no prefix, so nothing to be relative to
-                        replace_path(self, path, prefix);
-                    }
-                }
-                None => {
-                    // relative path
-                    append_path(self, path);
-                }
-            }
-        }
-    }
-}
-
-impl GenericPath for Path {
-    #[inline]
-    fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
-        match path.container_as_str() {
-            None => None,
-            Some(ref s) => {
-                if contains_nul(s) {
-                    None
-                } else {
-                    Some(unsafe { GenericPathUnsafe::new_unchecked(*s) })
-                }
-            }
-        }
-    }
-
-    /// See `GenericPath::as_str` for info.
-    /// Always returns a `Some` value.
-    #[inline]
-    fn as_str<'a>(&'a self) -> Option<&'a str> {
-        Some(&self.repr[])
-    }
-
-    #[inline]
-    fn as_vec<'a>(&'a self) -> &'a [u8] {
-        self.repr.as_bytes()
-    }
-
-    #[inline]
-    fn into_vec(self) -> Vec<u8> {
-        self.repr.into_bytes()
-    }
-
-    #[inline]
-    fn dirname<'a>(&'a self) -> &'a [u8] {
-        self.dirname_str().unwrap().as_bytes()
-    }
-
-    /// See `GenericPath::dirname_str` for info.
-    /// Always returns a `Some` value.
-    fn dirname_str<'a>(&'a self) -> Option<&'a str> {
-        Some(match self.sepidx_or_prefix_len() {
-            None if ".." == self.repr => &self.repr[],
-            None => ".",
-            Some((_,idxa,end)) if &self.repr[idxa..end] == ".." => {
-                &self.repr[]
-            }
-            Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => {
-                &self.repr[]
-            }
-            Some((0,idxa,_)) => &self.repr[..idxa],
-            Some((idxb,idxa,_)) => {
-                match self.prefix {
-                    Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => {
-                        &self.repr[..idxa]
-                    }
-                    _ => &self.repr[..idxb]
-                }
-            }
-        })
-    }
-
-    #[inline]
-    fn filename<'a>(&'a self) -> Option<&'a [u8]> {
-        self.filename_str().map(|x| x.as_bytes())
-    }
-
-    /// See `GenericPath::filename_str` for info.
-    /// Always returns a `Some` value if `filename` returns a `Some` value.
-    fn filename_str<'a>(&'a self) -> Option<&'a str> {
-        let repr = &self.repr[];
-        match self.sepidx_or_prefix_len() {
-            None if "." == repr || ".." == repr => None,
-            None => Some(repr),
-            Some((_,idxa,end)) if &repr[idxa..end] == ".." => None,
-            Some((_,idxa,end)) if idxa == end => None,
-            Some((_,idxa,end)) => Some(&repr[idxa..end])
-        }
-    }
-
-    /// See `GenericPath::filestem_str` for info.
-    /// Always returns a `Some` value if `filestem` returns a `Some` value.
-    #[inline]
-    fn filestem_str<'a>(&'a self) -> Option<&'a str> {
-        // filestem() returns a byte vector that's guaranteed valid UTF-8
-        self.filestem().map(|t| unsafe { mem::transmute(t) })
-    }
-
-    #[inline]
-    fn extension_str<'a>(&'a self) -> Option<&'a str> {
-        // extension() returns a byte vector that's guaranteed valid UTF-8
-        self.extension().map(|t| unsafe { mem::transmute(t) })
-    }
-
-    fn dir_path(&self) -> Path {
-        unsafe { GenericPathUnsafe::new_unchecked(self.dirname_str().unwrap()) }
-    }
-
-    #[inline]
-    fn pop(&mut self) -> bool {
-        match self.sepidx_or_prefix_len() {
-            None if "." == self.repr => false,
-            None => {
-                self.repr = String::from_str(".");
-                self.sepidx = None;
-                true
-            }
-            Some((idxb,idxa,end)) if idxb == idxa && idxb == end => false,
-            Some((idxb,_,end)) if &self.repr[idxb..end] == "\\" => false,
-            Some((idxb,idxa,_)) => {
-                let trunc = match self.prefix {
-                    Some(DiskPrefix) | Some(VerbatimDiskPrefix) | None => {
-                        let plen = self.prefix_len();
-                        if idxb == plen { idxa } else { idxb }
-                    }
-                    _ => idxb
-                };
-                self.repr.truncate(trunc);
-                self.update_sepidx();
-                true
-            }
-        }
-    }
-
-    fn root_path(&self) -> Option<Path> {
-        if self.prefix.is_some() {
-            Some(Path::new(match self.prefix {
-                Some(DiskPrefix) if self.is_absolute() => {
-                    &self.repr[..self.prefix_len()+1]
-                }
-                Some(VerbatimDiskPrefix) => {
-                    &self.repr[..self.prefix_len()+1]
-                }
-                _ => &self.repr[..self.prefix_len()]
-            }))
-        } else if is_vol_relative(self) {
-            Some(Path::new(&self.repr[..1]))
-        } else {
-            None
-        }
-    }
-
-    /// See `GenericPath::is_absolute` for info.
-    ///
-    /// A Windows Path is considered absolute only if it has a non-volume prefix,
-    /// or if it has a volume prefix and the path starts with '\'.
-    /// A path of `\foo` is not considered absolute because it's actually
-    /// relative to the "current volume". A separate method `Path::is_vol_relative`
-    /// is provided to indicate this case. Similarly a path of `C:foo` is not
-    /// considered absolute because it's relative to the cwd on volume C:. A
-    /// separate method `Path::is_cwd_relative` is provided to indicate this case.
-    #[inline]
-    fn is_absolute(&self) -> bool {
-        match self.prefix {
-            Some(DiskPrefix) => {
-                let rest = &self.repr[self.prefix_len()..];
-                rest.len() > 0 && rest.as_bytes()[0] == SEP_BYTE
-            }
-            Some(_) => true,
-            None => false
-        }
-    }
-
-    #[inline]
-    fn is_relative(&self) -> bool {
-        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() ||
-                  is_vol_relative(self) != is_vol_relative(other) {
-            false
-        } else {
-            let mut ita = self.str_components().map(|x|x.unwrap());
-            let mut itb = other.str_components().map(|x|x.unwrap());
-            if "." == self.repr {
-                return itb.next() != Some("..");
-            }
-            loop {
-                match (ita.next(), itb.next()) {
-                    (None, _) => break,
-                    (Some(a), Some(b)) if a == b => { continue },
-                    (Some(a), _) if a == ".." => {
-                        // if ita contains only .. components, it's an ancestor
-                        return ita.all(|x| x == "..");
-                    }
-                    _ => return false
-                }
-            }
-            true
-        }
-    }
-
-    fn path_relative_from(&self, base: &Path) -> Option<Path> {
-        fn comp_requires_verbatim(s: &str) -> bool {
-            s == "." || s == ".." || s.contains_char(SEP2)
-        }
-
-        if !self.equiv_prefix(base) {
-            // prefixes differ
-            if self.is_absolute() {
-                Some(self.clone())
-            } else if self.prefix == Some(DiskPrefix) && base.prefix == Some(DiskPrefix) {
-                // both drives, drive letters must differ or they'd be equiv
-                Some(self.clone())
-            } else {
-                None
-            }
-        } else if self.is_absolute() != base.is_absolute() {
-            if self.is_absolute() {
-                Some(self.clone())
-            } else {
-                None
-            }
-        } else if is_vol_relative(self) != is_vol_relative(base) {
-            if is_vol_relative(self) {
-                Some(self.clone())
-            } else {
-                None
-            }
-        } else {
-            let mut ita = self.str_components().map(|x|x.unwrap());
-            let mut itb = base.str_components().map(|x|x.unwrap());
-            let mut comps = vec![];
-
-            let a_verb = is_verbatim(self);
-            let b_verb = is_verbatim(base);
-            loop {
-                match (ita.next(), itb.next()) {
-                    (None, None) => break,
-                    (Some(a), None) if a_verb && comp_requires_verbatim(a) => {
-                        return Some(self.clone())
-                    }
-                    (Some(a), None) => {
-                        comps.push(a);
-                        if !a_verb {
-                            comps.extend(ita.by_ref());
-                            break;
-                        }
-                    }
-                    (None, _) => comps.push(".."),
-                    (Some(a), Some(b)) if comps.is_empty() && a == b => (),
-                    (Some(a), Some(b)) if !b_verb && b == "." => {
-                        if a_verb && comp_requires_verbatim(a) {
-                            return Some(self.clone())
-                        } else { comps.push(a) }
-                    }
-                    (Some(_), Some(b)) if !b_verb && b == ".." => return None,
-                    (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => {
-                        return Some(self.clone())
-                    }
-                    (Some(a), Some(_)) => {
-                        comps.push("..");
-                        for _ in itb.by_ref() {
-                            comps.push("..");
-                        }
-                        comps.push(a);
-                        if !a_verb {
-                            comps.extend(ita.by_ref());
-                            break;
-                        }
-                    }
-                }
-            }
-            Some(Path::new(comps.connect("\\")))
-        }
-    }
-
-    fn ends_with_path(&self, child: &Path) -> bool {
-        if !child.is_relative() { return false; }
-        let mut selfit = self.str_components().rev();
-        let mut childit = child.str_components().rev();
-        loop {
-            match (selfit.next(), childit.next()) {
-                (Some(a), Some(b)) => if a != b { return false; },
-                (Some(_), None) => break,
-                (None, Some(_)) => return false,
-                (None, None) => break
-            }
-        }
-        true
-    }
-}
-
-impl Path {
-    /// Returns a new `Path` from a `BytesContainer`.
-    ///
-    /// # Panics
-    ///
-    /// Panics if the vector contains a `NUL`, or if it contains invalid UTF-8.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// println!("{}", Path::new(r"C:\some\path").display());
-    /// ```
-    #[inline]
-    pub fn new<T: BytesContainer>(path: T) -> Path {
-        GenericPath::new(path)
-    }
-
-    /// Returns a new `Some(Path)` from a `BytesContainer`.
-    ///
-    /// Returns `None` if the vector contains a `NUL`, or if it contains invalid UTF-8.
-    ///
-    /// # Example
-    ///
-    /// ```
-    /// let path = Path::new_opt(r"C:\some\path");
-    ///
-    /// match path {
-    ///     Some(path) => println!("{}", path.display()),
-    ///     None       => println!("There was a problem with your path."),
-    /// }
-    /// ```
-    #[inline]
-    pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
-        GenericPath::new_opt(path)
-    }
-
-    /// Returns an iterator that yields each component of the path in turn as a Option<&str>.
-    /// Every component is guaranteed to be Some.
-    /// Does not yield the path prefix (including server/share components in UNC paths).
-    /// Does not distinguish between volume-relative and relative paths, e.g.
-    /// \a\b\c and a\b\c.
-    /// Does not distinguish between absolute and cwd-relative paths, e.g.
-    /// C:\foo and C:foo.
-    pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
-        let repr = &self.repr[];
-        let s = match self.prefix {
-            Some(_) => {
-                let plen = self.prefix_len();
-                if repr.len() > plen && repr.as_bytes()[plen] == SEP_BYTE {
-                    &repr[plen+1..]
-                } else { &repr[plen..] }
-            }
-            None if repr.as_bytes()[0] == SEP_BYTE => &repr[1..],
-            None => repr
-        };
-        let some: fn(&'a str) -> Option<&'a str> = Some; // coerce to fn ptr
-        let ret = s.split_terminator(SEP).map(some);
-        ret
-    }
-
-    /// Returns an iterator that yields each component of the path in turn as a &[u8].
-    /// See str_components() for details.
-    pub fn components<'a>(&'a self) -> Components<'a> {
-        fn convert<'a>(x: Option<&'a str>) -> &'a [u8] {
-            #![inline]
-            x.unwrap().as_bytes()
-        }
-        let convert: for<'b> fn(Option<&'b str>) -> &'b [u8] = convert; // coerce to fn ptr
-        self.str_components().map(convert)
-    }
-
-    fn equiv_prefix(&self, other: &Path) -> bool {
-        let s_repr = &self.repr[];
-        let o_repr = &other.repr[];
-        match (self.prefix, other.prefix) {
-            (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
-                self.is_absolute() &&
-                    s_repr.as_bytes()[0].to_ascii_lowercase() ==
-                        o_repr.as_bytes()[4].to_ascii_lowercase()
-            }
-            (Some(VerbatimDiskPrefix), Some(DiskPrefix)) => {
-                other.is_absolute() &&
-                    s_repr.as_bytes()[4].to_ascii_lowercase() ==
-                        o_repr.as_bytes()[0].to_ascii_lowercase()
-            }
-            (Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => {
-                s_repr.as_bytes()[4].to_ascii_lowercase() ==
-                    o_repr.as_bytes()[4].to_ascii_lowercase()
-            }
-            (Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => {
-                &s_repr[2..self.prefix_len()] == &o_repr[8..other.prefix_len()]
-            }
-            (Some(VerbatimUNCPrefix(_,_)), Some(UNCPrefix(_,_))) => {
-                &s_repr[8..self.prefix_len()] == &o_repr[2..other.prefix_len()]
-            }
-            (None, None) => true,
-            (a, b) if a == b => {
-                &s_repr[..self.prefix_len()] == &o_repr[..other.prefix_len()]
-            }
-            _ => false
-        }
-    }
-
-    fn normalize_(s: &str) -> (Option<PathPrefix>, String) {
-        // make borrowck happy
-        let (prefix, val) = {
-            let prefix = parse_prefix(s);
-            let path = Path::normalize__(s, prefix);
-            (prefix, path)
-        };
-        (prefix, match val {
-            None => s.to_string(),
-            Some(val) => val
-        })
-    }
-
-    fn normalize__(s: &str, prefix: Option<PathPrefix>) -> Option<String> {
-        if prefix_is_verbatim(prefix) {
-            // don't do any normalization
-            match prefix {
-                Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => {
-                    // the server component has no trailing '\'
-                    let mut s = String::from_str(s);
-                    s.push(SEP);
-                    Some(s)
-                }
-                _ => None
-            }
-        } else {
-            let (is_abs, comps) = normalize_helper(s, prefix);
-            let mut comps = comps;
-            match (comps.is_some(),prefix) {
-                (false, Some(DiskPrefix)) => {
-                    if s.as_bytes()[0] >= b'a' && s.as_bytes()[0] <= b'z' {
-                        comps = Some(vec![]);
-                    }
-                }
-                (false, Some(VerbatimDiskPrefix)) => {
-                    if s.as_bytes()[4] >= b'a' && s.as_bytes()[0] <= b'z' {
-                        comps = Some(vec![]);
-                    }
-                }
-                _ => ()
-            }
-            match comps {
-                None => None,
-                Some(comps) => {
-                    if prefix.is_some() && comps.is_empty() {
-                        match prefix.unwrap() {
-                            DiskPrefix => {
-                                let len = prefix_len(prefix) + is_abs as uint;
-                                let mut s = String::from_str(&s[..len]);
-                                unsafe {
-                                    let v = s.as_mut_vec();
-                                    v[0] = (*v)[0].to_ascii_uppercase();
-                                }
-                                if is_abs {
-                                    // normalize C:/ to C:\
-                                    unsafe {
-                                        s.as_mut_vec()[2] = SEP_BYTE;
-                                    }
-                                }
-                                Some(s)
-                            }
-                            VerbatimDiskPrefix => {
-                                let len = prefix_len(prefix) + is_abs as uint;
-                                let mut s = String::from_str(&s[..len]);
-                                unsafe {
-                                    let v = s.as_mut_vec();
-                                    v[4] = (*v)[4].to_ascii_uppercase();
-                                }
-                                Some(s)
-                            }
-                            _ => {
-                                let plen = prefix_len(prefix);
-                                if s.len() > plen {
-                                    Some(String::from_str(&s[..plen]))
-                                } else { None }
-                            }
-                        }
-                    } else if is_abs && comps.is_empty() {
-                        Some(repeat(SEP).take(1).collect())
-                    } else {
-                        let prefix_ = &s[..prefix_len(prefix)];
-                        let n = prefix_.len() +
-                                if is_abs { comps.len() } else { comps.len() - 1} +
-                                comps.iter().map(|v| v.len()).sum();
-                        let mut s = String::with_capacity(n);
-                        match prefix {
-                            Some(DiskPrefix) => {
-                                s.push(prefix_.as_bytes()[0].to_ascii_uppercase() as char);
-                                s.push(':');
-                            }
-                            Some(VerbatimDiskPrefix) => {
-                                s.push_str(&prefix_[..4]);
-                                s.push(prefix_.as_bytes()[4].to_ascii_uppercase() as char);
-                                s.push_str(&prefix_[5..]);
-                            }
-                            Some(UNCPrefix(a,b)) => {
-                                s.push_str("\\\\");
-                                s.push_str(&prefix_[2..a+2]);
-                                s.push(SEP);
-                                s.push_str(&prefix_[3+a..3+a+b]);
-                            }
-                            Some(_) => s.push_str(prefix_),
-                            None => ()
-                        }
-                        let mut it = comps.into_iter();
-                        if !is_abs {
-                            match it.next() {
-                                None => (),
-                                Some(comp) => s.push_str(comp)
-                            }
-                        }
-                        for comp in it {
-                            s.push(SEP);
-                            s.push_str(comp);
-                        }
-                        Some(s)
-                    }
-                }
-            }
-        }
-    }
-
-    fn update_sepidx(&mut self) {
-        let s = if self.has_nonsemantic_trailing_slash() {
-                    &self.repr[..self.repr.len()-1]
-                } else { &self.repr[] };
-        let sep_test: fn(char) -> bool = if !prefix_is_verbatim(self.prefix) {
-            is_sep
-        } else {
-            is_sep_verbatim
-        };
-        let idx = s.rfind(sep_test);
-        let prefixlen = self.prefix_len();
-        self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
-    }
-
-    fn prefix_len(&self) -> uint {
-        prefix_len(self.prefix)
-    }
-
-    // Returns a tuple (before, after, end) where before is the index of the separator
-    // and after is the index just after the separator.
-    // end is the length of the string, normally, or the index of the final character if it is
-    // a non-semantic trailing separator in a verbatim string.
-    // If the prefix is considered the separator, before and after are the same.
-    fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> {
-        match self.sepidx {
-            None => match self.prefix_len() { 0 => None, x => Some((x,x,self.repr.len())) },
-            Some(x) => {
-                if self.has_nonsemantic_trailing_slash() {
-                    Some((x,x+1,self.repr.len()-1))
-                } else { Some((x,x+1,self.repr.len())) }
-            }
-        }
-    }
-
-    fn has_nonsemantic_trailing_slash(&self) -> bool {
-        is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
-            self.repr.as_bytes()[self.repr.len()-1] == SEP_BYTE
-    }
-
-    fn update_normalized(&mut self, s: &str) {
-        let (prefix, path) = Path::normalize_(s);
-        self.repr = path;
-        self.prefix = prefix;
-        self.update_sepidx();
-    }
-}
-
-/// 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.as_bytes()[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)
-}
-
-/// Returns the non-verbatim equivalent of the input path, if possible.
-/// If the input path is a device namespace path, None is returned.
-/// If the input path is not verbatim, it is returned as-is.
-/// If the input path is verbatim, but the same path can be expressed as
-/// non-verbatim, the non-verbatim version is returned.
-/// Otherwise, None is returned.
-pub fn make_non_verbatim(path: &Path) -> Option<Path> {
-    let repr = &path.repr[];
-    let new_path = match path.prefix {
-        Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None,
-        Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()),
-        Some(VerbatimDiskPrefix) => {
-            // \\?\D:\
-            Path::new(&repr[4..])
-        }
-        Some(VerbatimUNCPrefix(_,_)) => {
-            // \\?\UNC\server\share
-            Path::new(format!(r"\{}", &repr[7..]))
-        }
-    };
-    if new_path.prefix.is_none() {
-        // \\?\UNC\server is a VerbatimUNCPrefix
-        // but \\server is nothing
-        return None;
-    }
-    // now ensure normalization didn't change anything
-    if &repr[path.prefix_len()..] == &new_path.repr[new_path.prefix_len()..] {
-        Some(new_path)
-    } else {
-        None
-    }
-}
-
-/// The standard path separator character
-pub const SEP: char = '\\';
-/// The standard path separator byte
-pub const SEP_BYTE: u8 = SEP as u8;
-
-/// The alternative path separator character
-pub const SEP2: char = '/';
-/// The alternative path separator character
-pub const SEP2_BYTE: u8 = SEP2 as u8;
-
-/// 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_sep_byte(u: &u8) -> bool {
-    *u == SEP_BYTE || *u == SEP2_BYTE
-}
-
-/// 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 == SEP_BYTE
-}
-
-/// Prefix types for Path
-#[derive(Copy, PartialEq, Clone, Debug)]
-pub enum PathPrefix {
-    /// Prefix `\\?\`, uint is the length of the following component
-    VerbatimPrefix(uint),
-    /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components
-    VerbatimUNCPrefix(uint, uint),
-    /// Prefix `\\?\C:\` (for any alphabetic character)
-    VerbatimDiskPrefix,
-    /// Prefix `\\.\`, uint is the length of the following component
-    DeviceNSPrefix(uint),
-    /// UNC prefix `\\server\share`, uints are the lengths of the server/share
-    UNCPrefix(uint, uint),
-    /// Prefix `C:` for any alphabetic character
-    DiskPrefix
-}
-
-fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
-    if path.starts_with("\\\\") {
-        // \\
-        path = &path[2..];
-        if path.starts_with("?\\") {
-            // \\?\
-            path = &path[2..];
-            if path.starts_with("UNC\\") {
-                // \\?\UNC\server\share
-                path = &path[4..];
-                let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
-                    Some(x) => x,
-                    None => (path.len(), 0)
-                };
-                return Some(VerbatimUNCPrefix(idx_a, idx_b));
-            } else {
-                // \\?\path
-                let idx = path.find('\\');
-                if idx == Some(2) && path.as_bytes()[1] == b':' {
-                    let c = path.as_bytes()[0];
-                    if c.is_ascii() && (c as char).is_alphabetic() {
-                        // \\?\C:\ path
-                        return Some(VerbatimDiskPrefix);
-                    }
-                }
-                let idx = idx.unwrap_or(path.len());
-                return Some(VerbatimPrefix(idx));
-            }
-        } else if path.starts_with(".\\") {
-            // \\.\path
-            path = &path[2..];
-            let idx = path.find('\\').unwrap_or(path.len());
-            return Some(DeviceNSPrefix(idx));
-        }
-        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));
-            }
-            _ => ()
-        }
-    } else if path.len() > 1 && path.as_bytes()[1] == b':' {
-        // C:
-        let c = path.as_bytes()[0];
-        if c.is_ascii() && (c as char).is_alphabetic() {
-            return Some(DiskPrefix);
-        }
-    }
-    return None;
-
-    fn parse_two_comps(mut path: &str, f: fn(char) -> bool) -> Option<(uint, uint)> {
-        let idx_a = match path.find(f) {
-            None => return None,
-            Some(x) => x
-        };
-        path = &path[idx_a+1..];
-        let idx_b = path.find(f).unwrap_or(path.len());
-        Some((idx_a, idx_b))
-    }
-}
-
-// None result means the string didn't need normalizing
-fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
-    let f: fn(char) -> bool = 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[prefix_len(prefix)..];
-    let s_ = if is_abs { &s_[1..] } else { s_ };
-
-    if is_abs && s_.is_empty() {
-        return (is_abs, match prefix {
-            Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
-                                        else { Some(vec![]) }),
-            Some(_) => Some(vec![]), // need to trim the trailing separator
-        });
-    }
-    let mut comps: Vec<&'a str> = vec![];
-    let mut n_up = 0u;
-    let mut changed = false;
-    for comp in s_.split(f) {
-        if comp.is_empty() { changed = true }
-        else if comp == "." { changed = true }
-        else if comp == ".." {
-            let has_abs_prefix = match prefix {
-                Some(DiskPrefix) => false,
-                Some(_) => true,
-                None => false
-            };
-            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().unwrap(); changed = true }
-        } else { comps.push(comp) }
-    }
-    if !changed && !prefix_is_verbatim(prefix) {
-        changed = s.find(is_sep).is_some();
-    }
-    if changed {
-        if comps.is_empty() && !is_abs && prefix.is_none() {
-            if s == "." {
-                return (is_abs, None);
-            }
-            comps.push(".");
-        }
-        (is_abs, Some(comps))
-    } else {
-        (is_abs, None)
-    }
-}
-
-fn prefix_is_verbatim(p: Option<PathPrefix>) -> bool {
-    match p {
-        Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true,
-        Some(DeviceNSPrefix(_)) => true, // not really sure, but I think so
-        _ => false
-    }
-}
-
-fn prefix_len(p: Option<PathPrefix>) -> uint {
-    match p {
-        None => 0,
-        Some(VerbatimPrefix(x)) => 4 + x,
-        Some(VerbatimUNCPrefix(x,y)) => 8 + x + 1 + y,
-        Some(VerbatimDiskPrefix) => 6,
-        Some(UNCPrefix(x,y)) => 2 + x + 1 + y,
-        Some(DeviceNSPrefix(x)) => 4 + x,
-        Some(DiskPrefix) => 2
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::PathPrefix::*;
-    use super::parse_prefix;
-    use super::*;
-
-    use clone::Clone;
-    use iter::IteratorExt;
-    use option::Option::{self, Some, None};
-    use path::GenericPath;
-    use slice::{AsSlice, SliceExt};
-    use str::Str;
-    use string::ToString;
-    use vec::Vec;
-
-    macro_rules! t {
-        (s: $path:expr, $exp:expr) => (
-            {
-                let path = $path;
-                assert_eq!(path.as_str(), Some($exp));
-            }
-        );
-        (v: $path:expr, $exp:expr) => (
-            {
-                let path = $path;
-                assert_eq!(path.as_vec(), $exp);
-            }
-        )
-    }
-
-    #[test]
-    fn test_parse_prefix() {
-        macro_rules! t {
-            ($path:expr, $exp:expr) => (
-                {
-                    let path = $path;
-                    let exp = $exp;
-                    let res = parse_prefix(path);
-                    assert_eq!(res, exp);
-                }
-            )
-        }
-
-        t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
-        t!("\\\\", None);
-        t!("\\\\SERVER", None);
-        t!("\\\\SERVER\\", None);
-        t!("\\\\SERVER\\\\", None);
-        t!("\\\\SERVER\\\\foo", None);
-        t!("\\\\SERVER\\share", Some(UNCPrefix(6,5)));
-        t!("\\\\SERVER/share/foo", Some(UNCPrefix(6,5)));
-        t!("\\\\SERVER\\share/foo", Some(UNCPrefix(6,5)));
-        t!("//SERVER/share/foo", None);
-        t!("\\\\\\a\\b\\c", None);
-        t!("\\\\?\\a\\b\\c", Some(VerbatimPrefix(1)));
-        t!("\\\\?\\a/b/c", Some(VerbatimPrefix(5)));
-        t!("//?/a/b/c", None);
-        t!("\\\\.\\a\\b", Some(DeviceNSPrefix(1)));
-        t!("\\\\.\\a/b", Some(DeviceNSPrefix(3)));
-        t!("//./a/b", None);
-        t!("\\\\?\\UNC\\server\\share\\foo", Some(VerbatimUNCPrefix(6,5)));
-        t!("\\\\?\\UNC\\\\share\\foo", Some(VerbatimUNCPrefix(0,5)));
-        t!("\\\\?\\UNC\\", Some(VerbatimUNCPrefix(0,0)));
-        t!("\\\\?\\UNC\\server/share/foo", Some(VerbatimUNCPrefix(16,0)));
-        t!("\\\\?\\UNC\\server", Some(VerbatimUNCPrefix(6,0)));
-        t!("\\\\?\\UNC\\server\\", Some(VerbatimUNCPrefix(6,0)));
-        t!("\\\\?\\UNC/server/share", Some(VerbatimPrefix(16)));
-        t!("\\\\?\\UNC", Some(VerbatimPrefix(3)));
-        t!("\\\\?\\C:\\a\\b.txt", Some(VerbatimDiskPrefix));
-        t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
-        t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
-        t!("\\\\?\\C:a.txt", Some(VerbatimPrefix(7)));
-        t!("\\\\?\\C:a\\b.txt", Some(VerbatimPrefix(3)));
-        t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
-        t!("C:\\foo", Some(DiskPrefix));
-        t!("z:/foo", Some(DiskPrefix));
-        t!("d:", Some(DiskPrefix));
-        t!("ab:", None);
-        t!("ü:\\foo", None);
-        t!("3:\\foo", None);
-        t!(" :\\foo", None);
-        t!("::\\foo", None);
-        t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
-        t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
-        t!("\\\\?\\ab:\\", Some(VerbatimPrefix(3)));
-        t!("\\\\?\\C:\\a", Some(VerbatimDiskPrefix));
-        t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
-        t!("\\\\?\\C:\\a/b", Some(VerbatimDiskPrefix));
-    }
-
-    #[test]
-    fn test_paths() {
-        let empty: &[u8] = &[];
-        t!(v: Path::new(empty), b".");
-        t!(v: Path::new(b"\\"), b"\\");
-        t!(v: Path::new(b"a\\b\\c"), b"a\\b\\c");
-
-        t!(s: Path::new(""), ".");
-        t!(s: Path::new("\\"), "\\");
-        t!(s: Path::new("hi"), "hi");
-        t!(s: Path::new("hi\\"), "hi");
-        t!(s: Path::new("\\lib"), "\\lib");
-        t!(s: Path::new("\\lib\\"), "\\lib");
-        t!(s: Path::new("hi\\there"), "hi\\there");
-        t!(s: Path::new("hi\\there.txt"), "hi\\there.txt");
-        t!(s: Path::new("/"), "\\");
-        t!(s: Path::new("hi/"), "hi");
-        t!(s: Path::new("/lib"), "\\lib");
-        t!(s: Path::new("/lib/"), "\\lib");
-        t!(s: Path::new("hi/there"), "hi\\there");
-
-        t!(s: Path::new("hi\\there\\"), "hi\\there");
-        t!(s: Path::new("hi\\..\\there"), "there");
-        t!(s: Path::new("hi/../there"), "there");
-        t!(s: Path::new("..\\hi\\there"), "..\\hi\\there");
-        t!(s: Path::new("\\..\\hi\\there"), "\\hi\\there");
-        t!(s: Path::new("/../hi/there"), "\\hi\\there");
-        t!(s: Path::new("foo\\.."), ".");
-        t!(s: Path::new("\\foo\\.."), "\\");
-        t!(s: Path::new("\\foo\\..\\.."), "\\");
-        t!(s: Path::new("\\foo\\..\\..\\bar"), "\\bar");
-        t!(s: Path::new("\\.\\hi\\.\\there\\."), "\\hi\\there");
-        t!(s: Path::new("\\.\\hi\\.\\there\\.\\.."), "\\hi");
-        t!(s: Path::new("foo\\..\\.."), "..");
-        t!(s: Path::new("foo\\..\\..\\.."), "..\\..");
-        t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar");
-
-        assert_eq!(Path::new(b"foo\\bar").into_vec(), b"foo\\bar");
-        assert_eq!(Path::new(b"\\foo\\..\\..\\bar").into_vec(), b"\\bar");
-
-        t!(s: Path::new("\\\\a"), "\\a");
-        t!(s: Path::new("\\\\a\\"), "\\a");
-        t!(s: Path::new("\\\\a\\b"), "\\\\a\\b");
-        t!(s: Path::new("\\\\a\\b\\"), "\\\\a\\b");
-        t!(s: Path::new("\\\\a\\b/"), "\\\\a\\b");
-        t!(s: Path::new("\\\\\\b"), "\\b");
-        t!(s: Path::new("\\\\a\\\\b"), "\\a\\b");
-        t!(s: Path::new("\\\\a\\b\\c"), "\\\\a\\b\\c");
-        t!(s: Path::new("\\\\server\\share/path"), "\\\\server\\share\\path");
-        t!(s: Path::new("\\\\server/share/path"), "\\\\server\\share\\path");
-        t!(s: Path::new("C:a\\b.txt"), "C:a\\b.txt");
-        t!(s: Path::new("C:a/b.txt"), "C:a\\b.txt");
-        t!(s: Path::new("z:\\a\\b.txt"), "Z:\\a\\b.txt");
-        t!(s: Path::new("z:/a/b.txt"), "Z:\\a\\b.txt");
-        t!(s: Path::new("ab:/a/b.txt"), "ab:\\a\\b.txt");
-        t!(s: Path::new("C:\\"), "C:\\");
-        t!(s: Path::new("C:"), "C:");
-        t!(s: Path::new("q:"), "Q:");
-        t!(s: Path::new("C:/"), "C:\\");
-        t!(s: Path::new("C:\\foo\\.."), "C:\\");
-        t!(s: Path::new("C:foo\\.."), "C:");
-        t!(s: Path::new("C:\\a\\"), "C:\\a");
-        t!(s: Path::new("C:\\a/"), "C:\\a");
-        t!(s: Path::new("C:\\a\\b\\"), "C:\\a\\b");
-        t!(s: Path::new("C:\\a\\b/"), "C:\\a\\b");
-        t!(s: Path::new("C:a\\"), "C:a");
-        t!(s: Path::new("C:a/"), "C:a");
-        t!(s: Path::new("C:a\\b\\"), "C:a\\b");
-        t!(s: Path::new("C:a\\b/"), "C:a\\b");
-        t!(s: Path::new("\\\\?\\z:\\a\\b.txt"), "\\\\?\\z:\\a\\b.txt");
-        t!(s: Path::new("\\\\?\\C:/a/b.txt"), "\\\\?\\C:/a/b.txt");
-        t!(s: Path::new("\\\\?\\C:\\a/b.txt"), "\\\\?\\C:\\a/b.txt");
-        t!(s: Path::new("\\\\?\\test\\a\\b.txt"), "\\\\?\\test\\a\\b.txt");
-        t!(s: Path::new("\\\\?\\foo\\bar\\"), "\\\\?\\foo\\bar\\");
-        t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
-        t!(s: Path::new("\\\\.\\"), "\\\\.\\");
-        t!(s: Path::new("\\\\?\\UNC\\server\\share\\foo"), "\\\\?\\UNC\\server\\share\\foo");
-        t!(s: Path::new("\\\\?\\UNC\\server/share"), "\\\\?\\UNC\\server/share\\");
-        t!(s: Path::new("\\\\?\\UNC\\server"), "\\\\?\\UNC\\server\\");
-        t!(s: Path::new("\\\\?\\UNC\\"), "\\\\?\\UNC\\\\");
-        t!(s: Path::new("\\\\?\\UNC"), "\\\\?\\UNC");
-
-        // I'm not sure whether \\.\foo/bar should normalize to \\.\foo\bar
-        // as information is sparse and this isn't really googleable.
-        // I'm going to err on the side of not normalizing it, as this skips the filesystem
-        t!(s: Path::new("\\\\.\\foo/bar"), "\\\\.\\foo/bar");
-        t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
-    }
-
-    #[test]
-    fn test_opt_paths() {
-        assert!(Path::new_opt(b"foo\\bar\0") == None);
-        assert!(Path::new_opt(b"foo\\bar\x80") == None);
-        t!(v: Path::new_opt(b"foo\\bar").unwrap(), b"foo\\bar");
-        assert!(Path::new_opt("foo\\bar\0") == None);
-        t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar");
-    }
-
-    #[test]
-    fn test_null_byte() {
-        use thread::Thread;
-        let result = Thread::scoped(move|| {
-            Path::new(b"foo/bar\0")
-        }).join();
-        assert!(result.is_err());
-
-        let result = Thread::scoped(move|| {
-            Path::new("test").set_filename(b"f\0o")
-        }).join();
-        assert!(result.is_err());
-
-        let result = Thread::scoped(move || {
-            Path::new("test").push(b"f\0o");
-        }).join();
-        assert!(result.is_err());
-    }
-
-    #[test]
-    #[should_fail]
-    fn test_not_utf8_panics() {
-        Path::new(b"hello\x80.txt");
-    }
-
-    #[test]
-    fn test_display_str() {
-        let path = Path::new("foo");
-        assert_eq!(path.display().to_string(), "foo");
-        let path = Path::new(b"\\");
-        assert_eq!(path.filename_display().to_string(), "");
-
-        let path = Path::new("foo");
-        let mo = path.display().as_cow();
-        assert_eq!(mo.as_slice(), "foo");
-        let path = Path::new(b"\\");
-        let mo = path.filename_display().as_cow();
-        assert_eq!(mo.as_slice(), "");
-    }
-
-    #[test]
-    fn test_display() {
-        macro_rules! t {
-            ($path:expr, $exp:expr, $expf:expr) => (
-                {
-                    let path = Path::new($path);
-                    let f = format!("{}", path.display());
-                    assert_eq!(f, $exp);
-                    let f = format!("{}", path.filename_display());
-                    assert_eq!(f, $expf);
-                }
-            )
-        }
-
-        t!("foo", "foo", "foo");
-        t!("foo\\bar", "foo\\bar", "bar");
-        t!("\\", "\\", "");
-    }
-
-    #[test]
-    fn test_components() {
-        macro_rules! t {
-            (s: $path:expr, $op:ident, $exp:expr) => (
-                {
-                    let path = $path;
-                    let path = Path::new(path);
-                    assert_eq!(path.$op(), Some($exp));
-                }
-            );
-            (s: $path:expr, $op:ident, $exp:expr, opt) => (
-                {
-                    let path = $path;
-                    let path = Path::new(path);
-                    let left = path.$op();
-                    assert_eq!(left, $exp);
-                }
-            );
-            (v: $path:expr, $op:ident, $exp:expr) => (
-                {
-                    let path = $path;
-                    let path = Path::new(path);
-                    assert_eq!(path.$op(), $exp);
-                }
-            )
-        }
-
-        t!(v: b"a\\b\\c", filename, Some(b"c"));
-        t!(s: "a\\b\\c", filename_str, "c");
-        t!(s: "\\a\\b\\c", filename_str, "c");
-        t!(s: "a", filename_str, "a");
-        t!(s: "\\a", filename_str, "a");
-        t!(s: ".", filename_str, None, opt);
-        t!(s: "\\", filename_str, None, opt);
-        t!(s: "..", filename_str, None, opt);
-        t!(s: "..\\..", filename_str, None, opt);
-        t!(s: "c:\\foo.txt", filename_str, "foo.txt");
-        t!(s: "C:\\", filename_str, None, opt);
-        t!(s: "C:", filename_str, None, opt);
-        t!(s: "\\\\server\\share\\foo.txt", filename_str, "foo.txt");
-        t!(s: "\\\\server\\share", filename_str, None, opt);
-        t!(s: "\\\\server", filename_str, "server");
-        t!(s: "\\\\?\\bar\\foo.txt", filename_str, "foo.txt");
-        t!(s: "\\\\?\\bar", filename_str, None, opt);
-        t!(s: "\\\\?\\", filename_str, None, opt);
-        t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", filename_str, "foo.txt");
-        t!(s: "\\\\?\\UNC\\server", filename_str, None, opt);
-        t!(s: "\\\\?\\UNC\\", filename_str, None, opt);
-        t!(s: "\\\\?\\C:\\foo.txt", filename_str, "foo.txt");
-        t!(s: "\\\\?\\C:\\", filename_str, None, opt);
-        t!(s: "\\\\?\\C:", filename_str, None, opt);
-        t!(s: "\\\\?\\foo/bar", filename_str, None, opt);
-        t!(s: "\\\\?\\C:/foo", filename_str, None, opt);
-        t!(s: "\\\\.\\foo\\bar", filename_str, "bar");
-        t!(s: "\\\\.\\foo", filename_str, None, opt);
-        t!(s: "\\\\.\\foo/bar", filename_str, None, opt);
-        t!(s: "\\\\.\\foo\\bar/baz", filename_str, "bar/baz");
-        t!(s: "\\\\.\\", filename_str, None, opt);
-        t!(s: "\\\\?\\a\\b\\", filename_str, "b");
-
-        t!(v: b"a\\b\\c", dirname, b"a\\b");
-        t!(s: "a\\b\\c", dirname_str, "a\\b");
-        t!(s: "\\a\\b\\c", dirname_str, "\\a\\b");
-        t!(s: "a", dirname_str, ".");
-        t!(s: "\\a", dirname_str, "\\");
-        t!(s: ".", dirname_str, ".");
-        t!(s: "\\", dirname_str, "\\");
-        t!(s: "..", dirname_str, "..");
-        t!(s: "..\\..", dirname_str, "..\\..");
-        t!(s: "c:\\foo.txt", dirname_str, "C:\\");
-        t!(s: "C:\\", dirname_str, "C:\\");
-        t!(s: "C:", dirname_str, "C:");
-        t!(s: "C:foo.txt", dirname_str, "C:");
-        t!(s: "\\\\server\\share\\foo.txt", dirname_str, "\\\\server\\share");
-        t!(s: "\\\\server\\share", dirname_str, "\\\\server\\share");
-        t!(s: "\\\\server", dirname_str, "\\");
-        t!(s: "\\\\?\\bar\\foo.txt", dirname_str, "\\\\?\\bar");
-        t!(s: "\\\\?\\bar", dirname_str, "\\\\?\\bar");
-        t!(s: "\\\\?\\", dirname_str, "\\\\?\\");
-        t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", dirname_str, "\\\\?\\UNC\\server\\share");
-        t!(s: "\\\\?\\UNC\\server", dirname_str, "\\\\?\\UNC\\server\\");
-        t!(s: "\\\\?\\UNC\\", dirname_str, "\\\\?\\UNC\\\\");
-        t!(s: "\\\\?\\C:\\foo.txt", dirname_str, "\\\\?\\C:\\");
-        t!(s: "\\\\?\\C:\\", dirname_str, "\\\\?\\C:\\");
-        t!(s: "\\\\?\\C:", dirname_str, "\\\\?\\C:");
-        t!(s: "\\\\?\\C:/foo/bar", dirname_str, "\\\\?\\C:/foo/bar");
-        t!(s: "\\\\?\\foo/bar", dirname_str, "\\\\?\\foo/bar");
-        t!(s: "\\\\.\\foo\\bar", dirname_str, "\\\\.\\foo");
-        t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo");
-        t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a");
-
-        t!(v: b"hi\\there.txt", filestem, Some(b"there"));
-        t!(s: "hi\\there.txt", filestem_str, "there");
-        t!(s: "hi\\there", filestem_str, "there");
-        t!(s: "there.txt", filestem_str, "there");
-        t!(s: "there", filestem_str, "there");
-        t!(s: ".", filestem_str, None, opt);
-        t!(s: "\\", filestem_str, None, opt);
-        t!(s: "foo\\.bar", filestem_str, ".bar");
-        t!(s: ".bar", filestem_str, ".bar");
-        t!(s: "..bar", filestem_str, ".");
-        t!(s: "hi\\there..txt", filestem_str, "there.");
-        t!(s: "..", filestem_str, None, opt);
-        t!(s: "..\\..", filestem_str, None, opt);
-        // filestem is based on filename, so we don't need the full set of prefix tests
-
-        t!(v: b"hi\\there.txt", extension, Some(b"txt"));
-        t!(v: b"hi\\there", extension, None);
-        t!(s: "hi\\there.txt", extension_str, Some("txt"), opt);
-        t!(s: "hi\\there", extension_str, None, opt);
-        t!(s: "there.txt", extension_str, Some("txt"), opt);
-        t!(s: "there", extension_str, None, opt);
-        t!(s: ".", extension_str, None, opt);
-        t!(s: "\\", extension_str, None, opt);
-        t!(s: "foo\\.bar", extension_str, None, opt);
-        t!(s: ".bar", extension_str, None, opt);
-        t!(s: "..bar", extension_str, Some("bar"), opt);
-        t!(s: "hi\\there..txt", extension_str, Some("txt"), opt);
-        t!(s: "..", extension_str, None, opt);
-        t!(s: "..\\..", extension_str, None, opt);
-        // extension is based on filename, so we don't need the full set of prefix tests
-    }
-
-    #[test]
-    fn test_push() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr) => (
-                {
-                    let path = $path;
-                    let join = $join;
-                    let mut p1 = Path::new(path);
-                    let p2 = p1.clone();
-                    p1.push(join);
-                    assert_eq!(p1, p2.join(join));
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "..");
-        t!(s: "\\a\\b\\c", "d");
-        t!(s: "a\\b", "c\\d");
-        t!(s: "a\\b", "\\c\\d");
-        // this is just a sanity-check test. push and join share an implementation,
-        // so there's no need for the full set of prefix 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!(prefix(&p), Some(VerbatimPrefix(2)));
-        p.push("foo");
-        assert_eq!(prefix(&p), Some(VerbatimDiskPrefix));
-        assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
-
-        // and another with verbatim non-normalized paths
-        let mut p = Path::new("\\\\?\\C:\\a\\");
-        p.push("foo");
-        assert_eq!(p.as_str(), Some("\\\\?\\C:\\a\\foo"));
-    }
-
-    #[test]
-    fn test_push_path() {
-        macro_rules! t {
-            (s: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    let push = Path::new($push);
-                    p.push(&push);
-                    assert_eq!(p.as_str(), Some($exp));
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "d", "a\\b\\c\\d");
-        t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
-        t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
-        t!(s: "a\\b", "\\c\\d", "\\c\\d");
-        t!(s: "a\\b", ".", "a\\b");
-        t!(s: "a\\b", "..\\c", "a\\c");
-        t!(s: "a\\b", "C:a.txt", "C:a.txt");
-        t!(s: "a\\b", "..\\..\\..\\c", "..\\c");
-        t!(s: "a\\b", "C:\\a.txt", "C:\\a.txt");
-        t!(s: "C:\\a", "C:\\b.txt", "C:\\b.txt");
-        t!(s: "C:\\a\\b\\c", "C:d", "C:\\a\\b\\c\\d");
-        t!(s: "C:a\\b\\c", "C:d", "C:a\\b\\c\\d");
-        t!(s: "C:a\\b", "..\\..\\..\\c", "C:..\\c");
-        t!(s: "C:\\a\\b", "..\\..\\..\\c", "C:\\c");
-        t!(s: "C:", r"a\b\c", r"C:a\b\c");
-        t!(s: "C:", r"..\a", r"C:..\a");
-        t!(s: "\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
-        t!(s: "\\\\server\\share\\foo", "..\\..\\bar", "\\\\server\\share\\bar");
-        t!(s: "\\\\server\\share\\foo", "C:baz", "C:baz");
-        t!(s: "\\\\?\\C:\\a\\b", "C:c\\d", "\\\\?\\C:\\a\\b\\c\\d");
-        t!(s: "\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
-        t!(s: "\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
-        t!(s: "\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
-        t!(s: "\\\\?\\C:\\a\\b", "..\\..\\..\\c", "\\\\?\\C:\\a\\b\\..\\..\\..\\c");
-        t!(s: "\\\\?\\foo\\bar", "..\\..\\c", "\\\\?\\foo\\bar\\..\\..\\c");
-        t!(s: "\\\\?\\", "foo", "\\\\?\\\\foo");
-        t!(s: "\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
-        t!(s: "\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
-        t!(s: "\\\\?\\UNC\\server\\share", "C:a", "C:a");
-        t!(s: "\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\\\foo");
-        t!(s: "C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
-        t!(s: "\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
-        t!(s: "\\\\.\\foo\\bar", "C:a", "C:a");
-        // again, not sure about the following, but I'm assuming \\.\ should be verbatim
-        t!(s: "\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
-
-        t!(s: "\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
-    }
-
-    #[test]
-    fn test_push_many() {
-        macro_rules! t {
-            (s: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    p.push_many(&$push);
-                    assert_eq!(p.as_str(), Some($exp));
-                }
-            );
-            (v: $path:expr, $push:expr, $exp:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    p.push_many(&$push);
-                    assert_eq!(p.as_vec(), $exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
-        t!(s: "a\\b\\c", ["d", "\\e"], "\\e");
-        t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
-        t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e");
-        t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e");
-        t!(v: b"a\\b\\c", [b"d", b"\\e", b"f"], b"\\e\\f");
-        t!(v: b"a\\b\\c", [b"d".to_vec(), b"e".to_vec()],
-           b"a\\b\\c\\d\\e");
-    }
-
-    #[test]
-    fn test_pop() {
-        macro_rules! t {
-            (s: $path:expr, $left:expr, $right:expr) => (
-                {
-                    let pstr = $path;
-                    let mut p = Path::new(pstr);
-                    let result = p.pop();
-                    let left = $left;
-                    assert_eq!(p.as_str(), Some(left));
-                    assert_eq!(result, $right);
-                }
-            );
-            (b: $path:expr, $left:expr, $right:expr) => (
-                {
-                    let mut p = Path::new($path);
-                    let result = p.pop();
-                    assert_eq!(p.as_vec(), $left);
-                    assert_eq!(result, $right);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "a\\b", true);
-        t!(s: "a", ".", true);
-        t!(s: ".", ".", false);
-        t!(s: "\\a", "\\", true);
-        t!(s: "\\", "\\", false);
-        t!(b: b"a\\b\\c", b"a\\b", true);
-        t!(b: b"a", b".", true);
-        t!(b: b".", b".", false);
-        t!(b: b"\\a", b"\\", true);
-        t!(b: b"\\", b"\\", false);
-
-        t!(s: "C:\\a\\b", "C:\\a", true);
-        t!(s: "C:\\a", "C:\\", true);
-        t!(s: "C:\\", "C:\\", false);
-        t!(s: "C:a\\b", "C:a", true);
-        t!(s: "C:a", "C:", true);
-        t!(s: "C:", "C:", false);
-        t!(s: "\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
-        t!(s: "\\\\server\\share\\a", "\\\\server\\share", true);
-        t!(s: "\\\\server\\share", "\\\\server\\share", false);
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
-        t!(s: "\\\\?\\a\\b", "\\\\?\\a", true);
-        t!(s: "\\\\?\\a", "\\\\?\\a", false);
-        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\", true);
-        t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\", false);
-        t!(s: "\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
-        t!(s: "\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share", true);
-        t!(s: "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
-        t!(s: "\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
-        t!(s: "\\\\.\\a\\b", "\\\\.\\a", true);
-        t!(s: "\\\\.\\a", "\\\\.\\a", false);
-
-        t!(s: "\\\\?\\a\\b\\", "\\\\?\\a", true);
-    }
-
-    #[test]
-    fn test_root_path() {
-        assert_eq!(Path::new("a\\b\\c").root_path(),  None);
-        assert_eq!(Path::new("\\a\\b\\c").root_path(), Some(Path::new("\\")));
-        assert_eq!(Path::new("C:a").root_path(), Some(Path::new("C:")));
-        assert_eq!(Path::new("C:\\a").root_path(), Some(Path::new("C:\\")));
-        assert_eq!(Path::new("\\\\a\\b\\c").root_path(), Some(Path::new("\\\\a\\b")));
-        assert_eq!(Path::new("\\\\?\\a\\b").root_path(), Some(Path::new("\\\\?\\a")));
-        assert_eq!(Path::new("\\\\?\\C:\\a").root_path(), Some(Path::new("\\\\?\\C:\\")));
-        assert_eq!(Path::new("\\\\?\\UNC\\a\\b\\c").root_path(),
-                Some(Path::new("\\\\?\\UNC\\a\\b")));
-        assert_eq!(Path::new("\\\\.\\a\\b").root_path(), Some(Path::new("\\\\.\\a")));
-    }
-
-    #[test]
-    fn test_join() {
-        t!(s: Path::new("a\\b\\c").join(".."), "a\\b");
-        t!(s: Path::new("\\a\\b\\c").join("d"), "\\a\\b\\c\\d");
-        t!(s: Path::new("a\\b").join("c\\d"), "a\\b\\c\\d");
-        t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d");
-        t!(s: Path::new(".").join("a\\b"), "a\\b");
-        t!(s: Path::new("\\").join("a\\b"), "\\a\\b");
-        t!(v: Path::new(b"a\\b\\c").join(b".."), b"a\\b");
-        t!(v: Path::new(b"\\a\\b\\c").join(b"d"), b"\\a\\b\\c\\d");
-        // full join testing is covered under test_push_path, so no need for
-        // the full set of prefix tests
-    }
-
-    #[test]
-    fn test_join_path() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let join = Path::new($join);
-                    let res = path.join(&join);
-                    assert_eq!(res.as_str(), Some($exp));
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "..", "a\\b");
-        t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
-        t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
-        t!(s: "a\\b", "\\c\\d", "\\c\\d");
-        t!(s: ".", "a\\b", "a\\b");
-        t!(s: "\\", "a\\b", "\\a\\b");
-        // join is implemented using push, so there's no need for
-        // the full set of prefix tests
-    }
-
-    #[test]
-    fn test_join_many() {
-        macro_rules! t {
-            (s: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let res = path.join_many(&$join);
-                    assert_eq!(res.as_str(), Some($exp));
-                }
-            );
-            (v: $path:expr, $join:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let res = path.join_many(&$join);
-                    assert_eq!(res.as_vec(), $exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
-        t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
-        t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
-        t!(s: "a\\b\\c", ["d".to_string(), "e".to_string()], "a\\b\\c\\d\\e");
-        t!(v: b"a\\b\\c", [b"d", b"e"], b"a\\b\\c\\d\\e");
-        t!(v: b"a\\b\\c", [b"d".to_vec(), b"e".to_vec()],
-           b"a\\b\\c\\d\\e");
-    }
-
-    #[test]
-    fn test_with_helpers() {
-        macro_rules! t {
-            (s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
-                {
-                    let pstr = $path;
-                    let path = Path::new(pstr);
-                    let arg = $arg;
-                    let res = path.$op(arg);
-                    let exp = Path::new($res);
-                    assert_eq!(res, exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
-        t!(s: ".", with_filename, "foo", "foo");
-        t!(s: "\\a\\b\\c", with_filename, "d", "\\a\\b\\d");
-        t!(s: "\\", with_filename, "foo", "\\foo");
-        t!(s: "\\a", with_filename, "foo", "\\foo");
-        t!(s: "foo", with_filename, "bar", "bar");
-        t!(s: "\\", with_filename, "foo\\", "\\foo");
-        t!(s: "\\a", with_filename, "foo\\", "\\foo");
-        t!(s: "a\\b\\c", with_filename, "", "a\\b");
-        t!(s: "a\\b\\c", with_filename, ".", "a\\b");
-        t!(s: "a\\b\\c", with_filename, "..", "a");
-        t!(s: "\\a", with_filename, "", "\\");
-        t!(s: "foo", with_filename, "", ".");
-        t!(s: "a\\b\\c", with_filename, "d\\e", "a\\b\\d\\e");
-        t!(s: "a\\b\\c", with_filename, "\\d", "a\\b\\d");
-        t!(s: "..", with_filename, "foo", "..\\foo");
-        t!(s: "..\\..", with_filename, "foo", "..\\..\\foo");
-        t!(s: "..", with_filename, "", "..");
-        t!(s: "..\\..", with_filename, "", "..\\..");
-        t!(s: "C:\\foo\\bar", with_filename, "baz", "C:\\foo\\baz");
-        t!(s: "C:\\foo", with_filename, "bar", "C:\\bar");
-        t!(s: "C:\\", with_filename, "foo", "C:\\foo");
-        t!(s: "C:foo\\bar", with_filename, "baz", "C:foo\\baz");
-        t!(s: "C:foo", with_filename, "bar", "C:bar");
-        t!(s: "C:", with_filename, "foo", "C:foo");
-        t!(s: "C:\\foo", with_filename, "", "C:\\");
-        t!(s: "C:foo", with_filename, "", "C:");
-        t!(s: "C:\\foo\\bar", with_filename, "..", "C:\\");
-        t!(s: "C:\\foo", with_filename, "..", "C:\\");
-        t!(s: "C:\\", with_filename, "..", "C:\\");
-        t!(s: "C:foo\\bar", with_filename, "..", "C:");
-        t!(s: "C:foo", with_filename, "..", "C:..");
-        t!(s: "C:", with_filename, "..", "C:..");
-        t!(s: "\\\\server\\share\\foo", with_filename, "bar", "\\\\server\\share\\bar");
-        t!(s: "\\\\server\\share", with_filename, "foo", "\\\\server\\share\\foo");
-        t!(s: "\\\\server\\share\\foo", with_filename, "", "\\\\server\\share");
-        t!(s: "\\\\server\\share", with_filename, "", "\\\\server\\share");
-        t!(s: "\\\\server\\share\\foo", with_filename, "..", "\\\\server\\share");
-        t!(s: "\\\\server\\share", with_filename, "..", "\\\\server\\share");
-        t!(s: "\\\\?\\C:\\foo\\bar", with_filename, "baz", "\\\\?\\C:\\foo\\baz");
-        t!(s: "\\\\?\\C:\\foo", with_filename, "bar", "\\\\?\\C:\\bar");
-        t!(s: "\\\\?\\C:\\", with_filename, "foo", "\\\\?\\C:\\foo");
-        t!(s: "\\\\?\\C:\\foo", with_filename, "..", "\\\\?\\C:\\..");
-        t!(s: "\\\\?\\foo\\bar", with_filename, "baz", "\\\\?\\foo\\baz");
-        t!(s: "\\\\?\\foo", with_filename, "bar", "\\\\?\\foo\\bar");
-        t!(s: "\\\\?\\", with_filename, "foo", "\\\\?\\\\foo");
-        t!(s: "\\\\?\\foo\\bar", with_filename, "..", "\\\\?\\foo\\..");
-        t!(s: "\\\\.\\foo\\bar", with_filename, "baz", "\\\\.\\foo\\baz");
-        t!(s: "\\\\.\\foo", with_filename, "bar", "\\\\.\\foo\\bar");
-        t!(s: "\\\\.\\foo\\bar", with_filename, "..", "\\\\.\\foo\\..");
-
-        t!(s: "hi\\there.txt", with_extension, "exe", "hi\\there.exe");
-        t!(s: "hi\\there.txt", with_extension, "", "hi\\there");
-        t!(s: "hi\\there.txt", with_extension, ".", "hi\\there..");
-        t!(s: "hi\\there.txt", with_extension, "..", "hi\\there...");
-        t!(s: "hi\\there", with_extension, "txt", "hi\\there.txt");
-        t!(s: "hi\\there", with_extension, ".", "hi\\there..");
-        t!(s: "hi\\there", with_extension, "..", "hi\\there...");
-        t!(s: "hi\\there.", with_extension, "txt", "hi\\there.txt");
-        t!(s: "hi\\.foo", with_extension, "txt", "hi\\.foo.txt");
-        t!(s: "hi\\there.txt", with_extension, ".foo", "hi\\there..foo");
-        t!(s: "\\", with_extension, "txt", "\\");
-        t!(s: "\\", with_extension, ".", "\\");
-        t!(s: "\\", with_extension, "..", "\\");
-        t!(s: ".", with_extension, "txt", ".");
-        // extension setter calls filename setter internally, no need for extended tests
-    }
-
-    #[test]
-    fn test_setters() {
-        macro_rules! t {
-            (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
-                {
-                    let path = $path;
-                    let arg = $arg;
-                    let mut p1 = Path::new(path);
-                    p1.$set(arg);
-                    let p2 = Path::new(path);
-                    assert_eq!(p1, p2.$with(arg));
-                }
-            );
-            (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
-                {
-                    let path = $path;
-                    let arg = $arg;
-                    let mut p1 = Path::new(path);
-                    p1.$set(arg);
-                    let p2 = Path::new(path);
-                    assert_eq!(p1, p2.$with(arg));
-                }
-            )
-        }
-
-        t!(v: b"a\\b\\c", set_filename, with_filename, b"d");
-        t!(v: b"\\", set_filename, with_filename, b"foo");
-        t!(s: "a\\b\\c", set_filename, with_filename, "d");
-        t!(s: "\\", set_filename, with_filename, "foo");
-        t!(s: ".", set_filename, with_filename, "foo");
-        t!(s: "a\\b", set_filename, with_filename, "");
-        t!(s: "a", set_filename, with_filename, "");
-
-        t!(v: b"hi\\there.txt", set_extension, with_extension, b"exe");
-        t!(s: "hi\\there.txt", set_extension, with_extension, "exe");
-        t!(s: "hi\\there.", set_extension, with_extension, "txt");
-        t!(s: "hi\\there", set_extension, with_extension, "txt");
-        t!(s: "hi\\there.txt", set_extension, with_extension, "");
-        t!(s: "hi\\there", set_extension, with_extension, "");
-        t!(s: ".", set_extension, with_extension, "txt");
-
-        // with_ helpers use the setter internally, so the tests for the with_ helpers
-        // will suffice. No need for the full set of prefix tests.
-    }
-
-    #[test]
-    fn test_getters() {
-        macro_rules! t {
-            (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
-                {
-                    let path = $path;
-                    assert_eq!(path.filename_str(), $filename);
-                    assert_eq!(path.dirname_str(), $dirname);
-                    assert_eq!(path.filestem_str(), $filestem);
-                    assert_eq!(path.extension_str(), $ext);
-                }
-            );
-            (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
-                {
-                    let path = $path;
-                    assert_eq!(path.filename(), $filename);
-                    assert_eq!(path.dirname(), $dirname);
-                    assert_eq!(path.filestem(), $filestem);
-                    assert_eq!(path.extension(), $ext);
-                }
-            )
-        }
-
-        t!(v: Path::new(b"a\\b\\c"), Some(b"c"), b"a\\b", Some(b"c"), None);
-        t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
-        t!(s: Path::new("."), None, Some("."), None, None);
-        t!(s: Path::new("\\"), None, Some("\\"), None, None);
-        t!(s: Path::new(".."), None, Some(".."), None, None);
-        t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None);
-        t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"),
-              Some("there"), Some("txt"));
-        t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None);
-        t!(s: Path::new("hi\\there."), Some("there."), Some("hi"),
-              Some("there"), Some(""));
-        t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None);
-        t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"),
-              Some("."), Some("there"));
-
-        // these are already tested in test_components, so no need for extended tests
-    }
-
-    #[test]
-    fn test_dir_path() {
-        t!(s: Path::new("hi\\there").dir_path(), "hi");
-        t!(s: Path::new("hi").dir_path(), ".");
-        t!(s: Path::new("\\hi").dir_path(), "\\");
-        t!(s: Path::new("\\").dir_path(), "\\");
-        t!(s: Path::new("..").dir_path(), "..");
-        t!(s: Path::new("..\\..").dir_path(), "..\\..");
-
-        // dir_path is just dirname interpreted as a path.
-        // No need for extended tests
-    }
-
-    #[test]
-    fn test_is_absolute() {
-        macro_rules! t {
-            ($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
-                {
-                    let path = Path::new($path);
-                    let (abs, vol, cwd, rel) = ($abs, $vol, $cwd, $rel);
-                    assert_eq!(path.is_absolute(), abs);
-                    assert_eq!(is_vol_relative(&path), vol);
-                    assert_eq!(is_cwd_relative(&path), cwd);
-                    assert_eq!(path.is_relative(), rel);
-                }
-            )
-        }
-        t!("a\\b\\c", false, false, false, true);
-        t!("\\a\\b\\c", false, true, false, false);
-        t!("a", false, false, false, true);
-        t!("\\a", false, true, false, false);
-        t!(".", false, false, false, true);
-        t!("\\", false, true, false, false);
-        t!("..", false, false, false, true);
-        t!("..\\..", false, false, false, true);
-        t!("C:a\\b.txt", false, false, true, false);
-        t!("C:\\a\\b.txt", true, false, false, false);
-        t!("\\\\server\\share\\a\\b.txt", true, false, false, false);
-        t!("\\\\?\\a\\b\\c.txt", true, false, false, false);
-        t!("\\\\?\\C:\\a\\b.txt", true, false, false, false);
-        t!("\\\\?\\C:a\\b.txt", true, false, false, false); // NB: not equivalent to C:a\b.txt
-        t!("\\\\?\\UNC\\server\\share\\a\\b.txt", true, false, false, false);
-        t!("\\\\.\\a\\b", true, false, false, false);
-    }
-
-    #[test]
-    fn test_is_ancestor_of() {
-        macro_rules! t {
-            (s: $path:expr, $dest:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let dest = Path::new($dest);
-                    let exp = $exp;
-                    let res = path.is_ancestor_of(&dest);
-                    assert_eq!(res, exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "a\\b\\c\\d", true);
-        t!(s: "a\\b\\c", "a\\b\\c", true);
-        t!(s: "a\\b\\c", "a\\b", false);
-        t!(s: "\\a\\b\\c", "\\a\\b\\c", true);
-        t!(s: "\\a\\b", "\\a\\b\\c", true);
-        t!(s: "\\a\\b\\c\\d", "\\a\\b\\c", false);
-        t!(s: "\\a\\b", "a\\b\\c", false);
-        t!(s: "a\\b", "\\a\\b\\c", false);
-        t!(s: "a\\b\\c", "a\\b\\d", false);
-        t!(s: "..\\a\\b\\c", "a\\b\\c", false);
-        t!(s: "a\\b\\c", "..\\a\\b\\c", false);
-        t!(s: "a\\b\\c", "a\\b\\cd", false);
-        t!(s: "a\\b\\cd", "a\\b\\c", false);
-        t!(s: "..\\a\\b", "..\\a\\b\\c", true);
-        t!(s: ".", "a\\b", true);
-        t!(s: ".", ".", true);
-        t!(s: "\\", "\\", true);
-        t!(s: "\\", "\\a\\b", true);
-        t!(s: "..", "a\\b", true);
-        t!(s: "..\\..", "a\\b", true);
-        t!(s: "foo\\bar", "foobar", false);
-        t!(s: "foobar", "foo\\bar", false);
-
-        t!(s: "foo", "C:foo", false);
-        t!(s: "C:foo", "foo", false);
-        t!(s: "C:foo", "C:foo\\bar", true);
-        t!(s: "C:foo\\bar", "C:foo", false);
-        t!(s: "C:\\foo", "C:\\foo\\bar", true);
-        t!(s: "C:", "C:", true);
-        t!(s: "C:", "C:\\", false);
-        t!(s: "C:\\", "C:", false);
-        t!(s: "C:\\", "C:\\", true);
-        t!(s: "C:\\foo\\bar", "C:\\foo", false);
-        t!(s: "C:foo\\bar", "C:foo", false);
-        t!(s: "C:\\foo", "\\foo", false);
-        t!(s: "\\foo", "C:\\foo", false);
-        t!(s: "\\\\server\\share\\foo", "\\\\server\\share\\foo\\bar", true);
-        t!(s: "\\\\server\\share", "\\\\server\\share\\foo", true);
-        t!(s: "\\\\server\\share\\foo", "\\\\server\\share", false);
-        t!(s: "C:\\foo", "\\\\server\\share\\foo", false);
-        t!(s: "\\\\server\\share\\foo", "C:\\foo", false);
-        t!(s: "\\\\?\\foo\\bar", "\\\\?\\foo\\bar\\baz", true);
-        t!(s: "\\\\?\\foo\\bar\\baz", "\\\\?\\foo\\bar", false);
-        t!(s: "\\\\?\\foo\\bar", "\\foo\\bar\\baz", false);
-        t!(s: "\\foo\\bar", "\\\\?\\foo\\bar\\baz", false);
-        t!(s: "\\\\?\\C:\\foo\\bar", "\\\\?\\C:\\foo\\bar\\baz", true);
-        t!(s: "\\\\?\\C:\\foo\\bar\\baz", "\\\\?\\C:\\foo\\bar", false);
-        t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\foo", true);
-        t!(s: "\\\\?\\C:", "\\\\?\\C:\\", false); // this is a weird one
-        t!(s: "\\\\?\\C:\\", "\\\\?\\C:", false);
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\c:\\a\\b", true);
-        t!(s: "\\\\?\\c:\\a", "\\\\?\\C:\\a\\b", true);
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a\\b", false);
-        t!(s: "\\\\?\\foo", "\\\\?\\foobar", false);
-        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", true);
-        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\", true);
-        t!(s: "\\\\?\\a\\b\\", "\\\\?\\a\\b", true);
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", false);
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b\\", false);
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c\\d", true);
-        t!(s: "\\\\?\\UNC\\a\\b\\c\\d", "\\\\?\\UNC\\a\\b\\c", false);
-        t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", true);
-        t!(s: "\\\\.\\foo\\bar", "\\\\.\\foo\\bar\\baz", true);
-        t!(s: "\\\\.\\foo\\bar\\baz", "\\\\.\\foo\\bar", false);
-        t!(s: "\\\\.\\foo", "\\\\.\\foo\\bar", true);
-        t!(s: "\\\\.\\foo", "\\\\.\\foobar", false);
-
-        t!(s: "\\a\\b", "\\\\?\\a\\b", false);
-        t!(s: "\\\\?\\a\\b", "\\a\\b", false);
-        t!(s: "\\a\\b", "\\\\?\\C:\\a\\b", false);
-        t!(s: "\\\\?\\C:\\a\\b", "\\a\\b", false);
-        t!(s: "Z:\\a\\b", "\\\\?\\z:\\a\\b", true);
-        t!(s: "C:\\a\\b", "\\\\?\\D:\\a\\b", false);
-        t!(s: "a\\b", "\\\\?\\a\\b", false);
-        t!(s: "\\\\?\\a\\b", "a\\b", false);
-        t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b", true);
-        t!(s: "\\\\?\\C:\\a\\b", "C:\\a\\b", true);
-        t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", false);
-        t!(s: "C:a\\b", "\\\\?\\C:a\\b", false);
-        t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", false);
-        t!(s: "\\\\?\\C:a\\b", "C:a\\b", false);
-        t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b\\", true);
-        t!(s: "\\\\?\\C:\\a\\b\\", "C:\\a\\b", true);
-        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c", true);
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b\\c", true);
-    }
-
-    #[test]
-    fn test_ends_with_path() {
-        macro_rules! t {
-            (s: $path:expr, $child:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let child = Path::new($child);
-                    assert_eq!(path.ends_with_path(&child), $exp);
-                }
-            );
-        }
-
-        t!(s: "a\\b\\c", "c", true);
-        t!(s: "a\\b\\c", "d", false);
-        t!(s: "foo\\bar\\quux", "bar", false);
-        t!(s: "foo\\bar\\quux", "barquux", false);
-        t!(s: "a\\b\\c", "b\\c", true);
-        t!(s: "a\\b\\c", "a\\b\\c", true);
-        t!(s: "a\\b\\c", "foo\\a\\b\\c", false);
-        t!(s: "\\a\\b\\c", "a\\b\\c", true);
-        t!(s: "\\a\\b\\c", "\\a\\b\\c", false); // child must be relative
-        t!(s: "\\a\\b\\c", "foo\\a\\b\\c", false);
-        t!(s: "a\\b\\c", "", false);
-        t!(s: "", "", true);
-        t!(s: "\\a\\b\\c", "d\\e\\f", false);
-        t!(s: "a\\b\\c", "a\\b", false);
-        t!(s: "a\\b\\c", "b", false);
-        t!(s: "C:\\a\\b", "b", true);
-        t!(s: "C:\\a\\b", "C:b", false);
-        t!(s: "C:\\a\\b", "C:a\\b", false);
-    }
-
-    #[test]
-    fn test_path_relative_from() {
-        macro_rules! t {
-            (s: $path:expr, $other:expr, $exp:expr) => (
-                {
-                    assert_eq!(Path::new($path).path_relative_from(&Path::new($other))
-                              .as_ref().and_then(|x| x.as_str()), $exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", "a\\b", Some("c"));
-        t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c"));
-        t!(s: "a\\b\\c", "a\\b\\c\\d", Some(".."));
-        t!(s: "a\\b\\c", "a\\b\\c", Some("."));
-        t!(s: "a\\b\\c", "a\\b\\c\\d\\e", Some("..\\.."));
-        t!(s: "a\\b\\c", "a\\d\\e", Some("..\\..\\b\\c"));
-        t!(s: "a\\b\\c", "d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
-        t!(s: "a\\b\\c", "\\a\\b\\c", None);
-        t!(s: "\\a\\b\\c", "a\\b\\c", Some("\\a\\b\\c"));
-        t!(s: "\\a\\b\\c", "\\a\\b\\c\\d", Some(".."));
-        t!(s: "\\a\\b\\c", "\\a\\b", Some("c"));
-        t!(s: "\\a\\b\\c", "\\a\\b\\c\\d\\e", Some("..\\.."));
-        t!(s: "\\a\\b\\c", "\\a\\d\\e", Some("..\\..\\b\\c"));
-        t!(s: "\\a\\b\\c", "\\d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
-        t!(s: "hi\\there.txt", "hi\\there", Some("..\\there.txt"));
-        t!(s: ".", "a", Some(".."));
-        t!(s: ".", "a\\b", Some("..\\.."));
-        t!(s: ".", ".", Some("."));
-        t!(s: "a", ".", Some("a"));
-        t!(s: "a\\b", ".", Some("a\\b"));
-        t!(s: "..", ".", Some(".."));
-        t!(s: "a\\b\\c", "a\\b\\c", Some("."));
-        t!(s: "\\a\\b\\c", "\\a\\b\\c", Some("."));
-        t!(s: "\\", "\\", Some("."));
-        t!(s: "\\", ".", Some("\\"));
-        t!(s: "..\\..\\a", "b", Some("..\\..\\..\\a"));
-        t!(s: "a", "..\\..\\b", None);
-        t!(s: "..\\..\\a", "..\\..\\b", Some("..\\a"));
-        t!(s: "..\\..\\a", "..\\..\\a\\b", Some(".."));
-        t!(s: "..\\..\\a\\b", "..\\..\\a", Some("b"));
-
-        t!(s: "C:a\\b\\c", "C:a\\b", Some("c"));
-        t!(s: "C:a\\b", "C:a\\b\\c", Some(".."));
-        t!(s: "C:" ,"C:a\\b", Some("..\\.."));
-        t!(s: "C:a\\b", "C:c\\d", Some("..\\..\\a\\b"));
-        t!(s: "C:a\\b", "D:c\\d", Some("C:a\\b"));
-        t!(s: "C:a\\b", "C:..\\c", None);
-        t!(s: "C:..\\a", "C:b\\c", Some("..\\..\\..\\a"));
-        t!(s: "C:\\a\\b\\c", "C:\\a\\b", Some("c"));
-        t!(s: "C:\\a\\b", "C:\\a\\b\\c", Some(".."));
-        t!(s: "C:\\", "C:\\a\\b", Some("..\\.."));
-        t!(s: "C:\\a\\b", "C:\\c\\d", Some("..\\..\\a\\b"));
-        t!(s: "C:\\a\\b", "C:a\\b", Some("C:\\a\\b"));
-        t!(s: "C:a\\b", "C:\\a\\b", None);
-        t!(s: "\\a\\b", "C:\\a\\b", None);
-        t!(s: "\\a\\b", "C:a\\b", None);
-        t!(s: "a\\b", "C:\\a\\b", None);
-        t!(s: "a\\b", "C:a\\b", None);
-
-        t!(s: "\\\\a\\b\\c", "\\\\a\\b", Some("c"));
-        t!(s: "\\\\a\\b", "\\\\a\\b\\c", Some(".."));
-        t!(s: "\\\\a\\b\\c\\e", "\\\\a\\b\\c\\d", Some("..\\e"));
-        t!(s: "\\\\a\\c\\d", "\\\\a\\b\\d", Some("\\\\a\\c\\d"));
-        t!(s: "\\\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\b\\c\\d"));
-        t!(s: "\\\\a\\b\\c", "\\d\\e", Some("\\\\a\\b\\c"));
-        t!(s: "\\d\\e", "\\\\a\\b\\c", None);
-        t!(s: "d\\e", "\\\\a\\b\\c", None);
-        t!(s: "C:\\a\\b\\c", "\\\\a\\b\\c", Some("C:\\a\\b\\c"));
-        t!(s: "C:\\c", "\\\\a\\b\\c", Some("C:\\c"));
-
-        t!(s: "\\\\?\\a\\b", "\\a\\b", Some("\\\\?\\a\\b"));
-        t!(s: "\\\\?\\a\\b", "a\\b", Some("\\\\?\\a\\b"));
-        t!(s: "\\\\?\\a\\b", "\\b", Some("\\\\?\\a\\b"));
-        t!(s: "\\\\?\\a\\b", "b", Some("\\\\?\\a\\b"));
-        t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", Some(".."));
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", Some("c"));
-        t!(s: "\\\\?\\a\\b", "\\\\?\\c\\d", Some("\\\\?\\a\\b"));
-        t!(s: "\\\\?\\a", "\\\\?\\b", Some("\\\\?\\a"));
-
-        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\b", Some("..\\a"));
-        t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a", Some("\\\\?\\C:\\a"));
-        t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\c:\\a", Some("b"));
-        t!(s: "\\\\?\\C:\\a\\b", "C:\\a", Some("b"));
-        t!(s: "\\\\?\\C:\\a", "C:\\a\\b", Some(".."));
-        t!(s: "C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
-        t!(s: "C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
-        t!(s: "\\\\?\\C:\\a", "D:\\a", Some("\\\\?\\C:\\a"));
-        t!(s: "\\\\?\\c:\\a\\b", "C:\\a", Some("b"));
-        t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", Some("\\\\?\\C:\\a\\b"));
-        t!(s: "\\\\?\\C:\\a\\.\\b", "C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
-        t!(s: "\\\\?\\C:\\a\\b/c", "C:\\a", Some("\\\\?\\C:\\a\\b/c"));
-        t!(s: "\\\\?\\C:\\a\\..\\b", "C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
-        t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", None);
-        t!(s: "\\\\?\\C:\\a\\.\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
-        t!(s: "\\\\?\\C:\\a\\b/c", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\b/c"));
-        t!(s: "\\\\?\\C:\\a\\..\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
-        t!(s: "\\\\?\\C:\\a\\b\\", "\\\\?\\C:\\a", Some("b"));
-        t!(s: "\\\\?\\C:\\.\\b", "\\\\?\\C:\\.", Some("b"));
-        t!(s: "C:\\b", "\\\\?\\C:\\.", Some("..\\b"));
-        t!(s: "\\\\?\\a\\.\\b\\c", "\\\\?\\a\\.\\b", Some("c"));
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\.\\d", Some("..\\..\\b\\c"));
-        t!(s: "\\\\?\\a\\..\\b", "\\\\?\\a\\..", Some("b"));
-        t!(s: "\\\\?\\a\\b\\..", "\\\\?\\a\\b", Some("\\\\?\\a\\b\\.."));
-        t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\..\\b", Some("..\\..\\b\\c"));
-
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
-        t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", Some(".."));
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
-        t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\C:\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
-        t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
-        t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
-        t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b", Some("c"));
-        t!(s: "\\\\?\\UNC\\a\\b", "\\\\a\\b\\c", Some(".."));
-        t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
-        t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
-        t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
-        t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
-        t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
-        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
-        t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\a\\b\\c"));
-    }
-
-    #[test]
-    fn test_str_components() {
-        macro_rules! t {
-            (s: $path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let comps = path.str_components().map(|x|x.unwrap())
-                                .collect::<Vec<&str>>();
-                    let exp: &[&str] = &$exp;
-                    assert_eq!(comps, exp);
-                    let comps = path.str_components().rev().map(|x|x.unwrap())
-                                .collect::<Vec<&str>>();
-                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&str>>();
-                    assert_eq!(comps, exp);
-                }
-            );
-        }
-
-        t!(s: b"a\\b\\c", ["a", "b", "c"]);
-        t!(s: "a\\b\\c", ["a", "b", "c"]);
-        t!(s: "a\\b\\d", ["a", "b", "d"]);
-        t!(s: "a\\b\\cd", ["a", "b", "cd"]);
-        t!(s: "\\a\\b\\c", ["a", "b", "c"]);
-        t!(s: "a", ["a"]);
-        t!(s: "\\a", ["a"]);
-        t!(s: "\\", []);
-        t!(s: ".", ["."]);
-        t!(s: "..", [".."]);
-        t!(s: "..\\..", ["..", ".."]);
-        t!(s: "..\\..\\foo", ["..", "..", "foo"]);
-        t!(s: "C:foo\\bar", ["foo", "bar"]);
-        t!(s: "C:foo", ["foo"]);
-        t!(s: "C:", []);
-        t!(s: "C:\\foo\\bar", ["foo", "bar"]);
-        t!(s: "C:\\foo", ["foo"]);
-        t!(s: "C:\\", []);
-        t!(s: "\\\\server\\share\\foo\\bar", ["foo", "bar"]);
-        t!(s: "\\\\server\\share\\foo", ["foo"]);
-        t!(s: "\\\\server\\share", []);
-        t!(s: "\\\\?\\foo\\bar\\baz", ["bar", "baz"]);
-        t!(s: "\\\\?\\foo\\bar", ["bar"]);
-        t!(s: "\\\\?\\foo", []);
-        t!(s: "\\\\?\\", []);
-        t!(s: "\\\\?\\a\\b", ["b"]);
-        t!(s: "\\\\?\\a\\b\\", ["b"]);
-        t!(s: "\\\\?\\foo\\bar\\\\baz", ["bar", "", "baz"]);
-        t!(s: "\\\\?\\C:\\foo\\bar", ["foo", "bar"]);
-        t!(s: "\\\\?\\C:\\foo", ["foo"]);
-        t!(s: "\\\\?\\C:\\", []);
-        t!(s: "\\\\?\\C:\\foo\\", ["foo"]);
-        t!(s: "\\\\?\\UNC\\server\\share\\foo\\bar", ["foo", "bar"]);
-        t!(s: "\\\\?\\UNC\\server\\share\\foo", ["foo"]);
-        t!(s: "\\\\?\\UNC\\server\\share", []);
-        t!(s: "\\\\.\\foo\\bar\\baz", ["bar", "baz"]);
-        t!(s: "\\\\.\\foo\\bar", ["bar"]);
-        t!(s: "\\\\.\\foo", []);
-    }
-
-    #[test]
-    fn test_components_iter() {
-        macro_rules! t {
-            (s: $path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let comps = path.components().collect::<Vec<&[u8]>>();
-                    let exp: &[&[u8]] = &$exp;
-                    assert_eq!(comps, exp);
-                    let comps = path.components().rev().collect::<Vec<&[u8]>>();
-                    let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
-                    assert_eq!(comps, exp);
-                }
-            )
-        }
-
-        t!(s: "a\\b\\c", [b"a", b"b", b"c"]);
-        t!(s: ".", [b"."]);
-        // since this is really a wrapper around str_components, those tests suffice
-    }
-
-    #[test]
-    fn test_make_non_verbatim() {
-        macro_rules! t {
-            ($path:expr, $exp:expr) => (
-                {
-                    let path = Path::new($path);
-                    let exp: Option<&str> = $exp;
-                    let exp = exp.map(|s| Path::new(s));
-                    assert_eq!(make_non_verbatim(&path), exp);
-                }
-            )
-        }
-
-        t!(r"\a\b\c", Some(r"\a\b\c"));
-        t!(r"a\b\c", Some(r"a\b\c"));
-        t!(r"C:\a\b\c", Some(r"C:\a\b\c"));
-        t!(r"C:a\b\c", Some(r"C:a\b\c"));
-        t!(r"\\server\share\foo", Some(r"\\server\share\foo"));
-        t!(r"\\.\foo", None);
-        t!(r"\\?\foo", None);
-        t!(r"\\?\C:", None);
-        t!(r"\\?\C:foo", None);
-        t!(r"\\?\C:\", Some(r"C:\"));
-        t!(r"\\?\C:\foo", Some(r"C:\foo"));
-        t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz"));
-        t!(r"\\?\C:\foo\.\bar\baz", None);
-        t!(r"\\?\C:\foo\bar\..\baz", None);
-        t!(r"\\?\C:\foo\bar\..", None);
-        t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo"));
-        t!(r"\\?\UNC\server\share", Some(r"\\server\share"));
-        t!(r"\\?\UNC\server", None);
-        t!(r"\\?\UNC\server\", None);
-    }
-}
index 2398485afefb7ab481eaa38a0c18bd59ab941691..d2dc33451200f5f866973f03939eecf2523613c5 100644 (file)
@@ -56,7 +56,7 @@
 #[doc(no_inline)] pub use vec::Vec;
 
 // NB: remove when path reform lands
-#[doc(no_inline)] pub use path::{Path, GenericPath};
+#[doc(no_inline)] pub use old_path::{Path, GenericPath};
 // NB: remove when I/O reform lands
 #[doc(no_inline)] pub use old_io::{Buffer, Writer, Reader, Seek, BufferPrelude};
 // NB: remove when range syntax lands
index 4b45d5501c2351a2797c5d3f7c9ee86a913c1618..797b9332f17dc4cfa134e8f1ab48e02bf7cb1e58 100644 (file)
@@ -20,7 +20,7 @@ mod imp {
     use self::OsRngInner::*;
 
     use old_io::{IoResult, File};
-    use path::Path;
+    use old_path::Path;
     use rand::Rng;
     use rand::reader::ReaderRng;
     use result::Result::Ok;
index ae01586c7039effc671a3f1250f142b48238e26e..6f6b4c58717482522246ca8864b86d6855540871 100644 (file)
@@ -16,7 +16,7 @@
 use sys::{last_error, retry};
 use ffi::CString;
 use num::Int;
-use path::BytesContainer;
+use old_path::BytesContainer;
 use collections;
 
 pub mod backtrace;
index 3dd89ad07593a2c48a0dbf5a782fd1340288b343..a2c93dea6a4f504283da80a06635a9c99e88d343 100644 (file)
@@ -20,7 +20,7 @@
 use string::{String, CowString};
 use mem;
 
-#[derive(Clone)]
+#[derive(Clone, Hash)]
 pub struct Buf {
     pub inner: Vec<u8>
 }
index 7e117b10a347c5ed80ffe46edb465a78d2836ff7..20f86227e8eaf291d384ae40a0f34dbb39259e71 100644 (file)
@@ -20,7 +20,7 @@
 use libc::{self, pid_t, c_void, c_int};
 use mem;
 use os;
-use path::BytesContainer;
+use old_path::BytesContainer;
 use ptr;
 use sync::mpsc::{channel, Sender, Receiver};
 use sys::fs::FileDesc;
index 66712b9e3a1e6e6edfbd0bd50a0b3821b46fb555..92e309da34bef34029745a3618743be2d7227e0f 100644 (file)
@@ -32,7 +32,7 @@
 use mem;
 use ops::Drop;
 use option::Option::{Some};
-use path::Path;
+use old_path::Path;
 use ptr;
 use result::Result::{Ok, Err};
 use slice::SliceExt;
index aab2406cef92bd0a21aeb1dba5e9e2f0a56beaae..af94b56bf1f71aaf39433a4072093ca4ee64475e 100644 (file)
@@ -18,7 +18,7 @@
 use option::Option;
 use mem;
 
-#[derive(Clone)]
+#[derive(Clone, Hash)]
 pub struct Buf {
     pub inner: Wtf8Buf
 }
index 3ca735f7fdfd347bfba8c86d39b9afe345c35bd5..315c41e779a36c7abfce420642b2cebb1c357a99 100644 (file)
@@ -23,7 +23,7 @@
 use old_io::{IoResult, IoError};
 use old_io;
 use os;
-use path::BytesContainer;
+use old_path::BytesContainer;
 use ptr;
 use str;
 use sync::{StaticMutex, MUTEX_INIT};
index 483e5995298959368f263763ab9abe1bd56ecb03..76b8d736aad544dfcac4cee7c941362de4ec344e 100644 (file)
@@ -45,6 +45,7 @@ macro_rules! try_opt {
 
 /// ISO 8601 time duration with nanosecond precision.
 /// This also allows for the negative duration; see individual methods for details.
+#[unstable(feature = "std_misc")]
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
 pub struct Duration {
     secs: i64,
@@ -52,12 +53,14 @@ pub struct Duration {
 }
 
 /// The minimum possible `Duration`: `i64::MIN` milliseconds.
+#[unstable(feature = "std_misc")]
 pub const MIN: Duration = Duration {
     secs: i64::MIN / MILLIS_PER_SEC - 1,
     nanos: NANOS_PER_SEC + (i64::MIN % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
 };
 
 /// The maximum possible `Duration`: `i64::MAX` milliseconds.
+#[unstable(feature = "std_misc")]
 pub const MAX: Duration = Duration {
     secs: i64::MAX / MILLIS_PER_SEC,
     nanos: (i64::MAX % MILLIS_PER_SEC) as i32 * NANOS_PER_MILLI
@@ -68,6 +71,7 @@ impl Duration {
     /// Equivalent to `Duration::seconds(weeks * 7 * 24 * 60 * 60), with overflow checks.
     /// Panics when the duration is out of bounds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn weeks(weeks: i64) -> Duration {
         let secs = weeks.checked_mul(SECS_PER_WEEK).expect("Duration::weeks out of bounds");
         Duration::seconds(secs)
@@ -77,6 +81,7 @@ pub fn weeks(weeks: i64) -> Duration {
     /// Equivalent to `Duration::seconds(days * 24 * 60 * 60)` with overflow checks.
     /// Panics when the duration is out of bounds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn days(days: i64) -> Duration {
         let secs = days.checked_mul(SECS_PER_DAY).expect("Duration::days out of bounds");
         Duration::seconds(secs)
@@ -86,6 +91,7 @@ pub fn days(days: i64) -> Duration {
     /// Equivalent to `Duration::seconds(hours * 60 * 60)` with overflow checks.
     /// Panics when the duration is out of bounds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn hours(hours: i64) -> Duration {
         let secs = hours.checked_mul(SECS_PER_HOUR).expect("Duration::hours ouf of bounds");
         Duration::seconds(secs)
@@ -95,6 +101,7 @@ pub fn hours(hours: i64) -> Duration {
     /// Equivalent to `Duration::seconds(minutes * 60)` with overflow checks.
     /// Panics when the duration is out of bounds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn minutes(minutes: i64) -> Duration {
         let secs = minutes.checked_mul(SECS_PER_MINUTE).expect("Duration::minutes out of bounds");
         Duration::seconds(secs)
@@ -104,6 +111,7 @@ pub fn minutes(minutes: i64) -> Duration {
     /// Panics when the duration is more than `i64::MAX` milliseconds
     /// or less than `i64::MIN` milliseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn seconds(seconds: i64) -> Duration {
         let d = Duration { secs: seconds, nanos: 0 };
         if d < MIN || d > MAX {
@@ -114,6 +122,7 @@ pub fn seconds(seconds: i64) -> Duration {
 
     /// Makes a new `Duration` with given number of milliseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn milliseconds(milliseconds: i64) -> Duration {
         let (secs, millis) = div_mod_floor_64(milliseconds, MILLIS_PER_SEC);
         let nanos = millis as i32 * NANOS_PER_MILLI;
@@ -122,6 +131,7 @@ pub fn milliseconds(milliseconds: i64) -> Duration {
 
     /// Makes a new `Duration` with given number of microseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn microseconds(microseconds: i64) -> Duration {
         let (secs, micros) = div_mod_floor_64(microseconds, MICROS_PER_SEC);
         let nanos = micros as i32 * NANOS_PER_MICRO;
@@ -130,6 +140,7 @@ pub fn microseconds(microseconds: i64) -> Duration {
 
     /// Makes a new `Duration` with given number of nanoseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn nanoseconds(nanos: i64) -> Duration {
         let (secs, nanos) = div_mod_floor_64(nanos, NANOS_PER_SEC as i64);
         Duration { secs: secs, nanos: nanos as i32 }
@@ -137,6 +148,7 @@ pub fn nanoseconds(nanos: i64) -> Duration {
 
     /// Runs a closure, returning the duration of time it took to run the
     /// closure.
+    #[unstable(feature = "std_misc")]
     pub fn span<F>(f: F) -> Duration where F: FnOnce() {
         let before = super::precise_time_ns();
         f();
@@ -145,28 +157,33 @@ pub fn span<F>(f: F) -> Duration where F: FnOnce() {
 
     /// Returns the total number of whole weeks in the duration.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn num_weeks(&self) -> i64 {
         self.num_days() / 7
     }
 
     /// Returns the total number of whole days in the duration.
+    #[unstable(feature = "std_misc")]
     pub fn num_days(&self) -> i64 {
         self.num_seconds() / SECS_PER_DAY
     }
 
     /// Returns the total number of whole hours in the duration.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn num_hours(&self) -> i64 {
         self.num_seconds() / SECS_PER_HOUR
     }
 
     /// Returns the total number of whole minutes in the duration.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn num_minutes(&self) -> i64 {
         self.num_seconds() / SECS_PER_MINUTE
     }
 
     /// Returns the total number of whole seconds in the duration.
+    #[unstable(feature = "std_misc")]
     pub fn num_seconds(&self) -> i64 {
         // If secs is negative, nanos should be subtracted from the duration.
         if self.secs < 0 && self.nanos > 0 {
@@ -188,6 +205,7 @@ fn nanos_mod_sec(&self) -> i32 {
     }
 
     /// Returns the total number of whole milliseconds in the duration,
+    #[unstable(feature = "std_misc")]
     pub fn num_milliseconds(&self) -> i64 {
         // A proper Duration will not overflow, because MIN and MAX are defined
         // such that the range is exactly i64 milliseconds.
@@ -198,6 +216,7 @@ pub fn num_milliseconds(&self) -> i64 {
 
     /// Returns the total number of whole microseconds in the duration,
     /// or `None` on overflow (exceeding 2^63 microseconds in either direction).
+    #[unstable(feature = "std_misc")]
     pub fn num_microseconds(&self) -> Option<i64> {
         let secs_part = try_opt!(self.num_seconds().checked_mul(MICROS_PER_SEC));
         let nanos_part = self.nanos_mod_sec() / NANOS_PER_MICRO;
@@ -206,6 +225,7 @@ pub fn num_microseconds(&self) -> Option<i64> {
 
     /// Returns the total number of whole nanoseconds in the duration,
     /// or `None` on overflow (exceeding 2^63 nanoseconds in either direction).
+    #[unstable(feature = "std_misc")]
     pub fn num_nanoseconds(&self) -> Option<i64> {
         let secs_part = try_opt!(self.num_seconds().checked_mul(NANOS_PER_SEC as i64));
         let nanos_part = self.nanos_mod_sec();
@@ -213,6 +233,7 @@ pub fn num_nanoseconds(&self) -> Option<i64> {
     }
 
     /// Add two durations, returning `None` if overflow occured.
+    #[unstable(feature = "std_misc")]
     pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
         let mut secs = try_opt!(self.secs.checked_add(rhs.secs));
         let mut nanos = self.nanos + rhs.nanos;
@@ -227,6 +248,7 @@ pub fn checked_add(&self, rhs: &Duration) -> Option<Duration> {
     }
 
     /// Subtract two durations, returning `None` if overflow occured.
+    #[unstable(feature = "std_misc")]
     pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
         let mut secs = try_opt!(self.secs.checked_sub(rhs.secs));
         let mut nanos = self.nanos - rhs.nanos;
@@ -242,25 +264,30 @@ pub fn checked_sub(&self, rhs: &Duration) -> Option<Duration> {
 
     /// The minimum possible `Duration`: `i64::MIN` milliseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn min_value() -> Duration { MIN }
 
     /// The maximum possible `Duration`: `i64::MAX` milliseconds.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn max_value() -> Duration { MAX }
 
     /// A duration where the stored seconds and nanoseconds are equal to zero.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn zero() -> Duration {
         Duration { secs: 0, nanos: 0 }
     }
 
     /// Returns `true` if the duration equals `Duration::zero()`.
     #[inline]
+    #[unstable(feature = "std_misc")]
     pub fn is_zero(&self) -> bool {
         self.secs == 0 && self.nanos == 0
     }
 }
 
+#[unstable(feature = "std_misc")]
 impl Neg for Duration {
     type Output = Duration;
 
@@ -274,6 +301,7 @@ fn neg(self) -> Duration {
     }
 }
 
+#[unstable(feature = "std_misc")]
 impl Add for Duration {
     type Output = Duration;
 
@@ -288,6 +316,7 @@ fn add(self, rhs: Duration) -> Duration {
     }
 }
 
+#[unstable(feature = "std_misc")]
 impl Sub for Duration {
     type Output = Duration;
 
@@ -302,6 +331,7 @@ fn sub(self, rhs: Duration) -> Duration {
     }
 }
 
+#[unstable(feature = "std_misc")]
 impl Mul<i32> for Duration {
     type Output = Duration;
 
@@ -314,6 +344,7 @@ fn mul(self, rhs: i32) -> Duration {
     }
 }
 
+#[unstable(feature = "std_misc")]
 impl Div<i32> for Duration {
     type Output = Duration;
 
index f62571942a78df49cb3440306aeb5746d21d8df3..4d9bb8050d31ea83f4199aff715821d7110ef5b8 100644 (file)
@@ -10,6 +10,8 @@
 
 //! Temporal quantification.
 
+#![unstable(feature = "std_misc")]
+
 use sys::time::SteadyTime;
 
 pub use self::duration::Duration;
index 5c3892e49c0587543e02f334921741b971db5f39..129c1d20bc04c6ecde9bc9bcd8aafe246538688e 100644 (file)
@@ -25,7 +25,7 @@
 use std::fmt;
 use std::mem;
 use std::ops::Deref;
-use std::path::BytesContainer;
+use std::old_path::BytesContainer;
 use std::rc::Rc;
 
 #[allow(non_camel_case_types)]
index 0692d7e5faa83de2d9e5efc5b768ea1a715ec973..c369e354875b5be7367c14d9817fc4ebbca53f73 100644 (file)
@@ -464,14 +464,14 @@ pub fn new(opts: &TestOpts,
             out: out,
             log_out: log_out,
             use_color: use_color(opts),
-            total: 0u,
-            passed: 0u,
-            failed: 0u,
-            ignored: 0u,
-            measured: 0u,
+            total: 0,
+            passed: 0,
+            failed: 0,
+            ignored: 0,
+            measured: 0,
             metrics: MetricMap::new(),
             failures: Vec::new(),
-            max_name_len: 0u,
+            max_name_len: 0,
         })
     }
 
@@ -601,7 +601,7 @@ pub fn write_failures(&mut self) -> old_io::IoResult<()> {
     pub fn write_run_finish(&mut self) -> old_io::IoResult<bool> {
         assert!(self.passed + self.failed + self.ignored + self.measured == self.total);
 
-        let success = self.failed == 0u;
+        let success = self.failed == 0;
         if !success {
             try!(self.write_failures());
         }
@@ -679,7 +679,7 @@ fn callback<T: Writer>(event: &TestEvent,
     let mut st = try!(ConsoleTestState::new(opts, None::<StdWriter>));
     fn len_if_padded(t: &TestDescAndFn) -> uint {
         match t.testfn.padding() {
-            PadNone => 0u,
+            PadNone => 0,
             PadOnLeft | PadOnRight => t.desc.name.as_slice().len(),
         }
     }
@@ -712,12 +712,12 @@ fn should_sort_failures_before_printing_them() {
         log_out: None,
         out: Raw(Vec::new()),
         use_color: false,
-        total: 0u,
-        passed: 0u,
-        failed: 0u,
-        ignored: 0u,
-        measured: 0u,
-        max_name_len: 10u,
+        total: 0,
+        passed: 0,
+        failed: 0,
+        ignored: 0,
+        measured: 0,
+        max_name_len: 10,
         metrics: MetricMap::new(),
         failures: vec!((test_b, Vec::new()), (test_a, Vec::new()))
     };
index 0e3aacbc09a9afb6ed144a138ddc2c1d5ef3355e..ff8246a0e3f875023ab849f72790febd4a6bfd62 100644 (file)
@@ -153,7 +153,7 @@ impl<'a> Iterator for Graphemes<'a> {
     #[inline]
     fn size_hint(&self) -> (uint, Option<uint>) {
         let slen = self.string.len();
-        (cmp::min(slen, 1u), Some(slen))
+        (cmp::min(slen, 1), Some(slen))
     }
 
     #[inline]
index 328561495eef0a2efafd011611c14e1b7120b1a3..20cebb9be1746e027ac155dcd6da3b5cf4898960 100644 (file)
@@ -10,6 +10,9 @@
 
 pub use reexport::Reexported;
 
+pub struct Foo;
+pub enum Bar { X }
+
 pub mod foo {
     pub trait PubPub {
         fn method(&self) {}
index 627fc6f0b05fb16536e95c5b1831b7ccb39053b5..e807d2b9448d32438624feb1695713add482d12a 100644 (file)
@@ -10,7 +10,9 @@
 
 // issue #21405
 
-fn foo<F>(f: F) where F: FnMut(usize) {}
+struct Foo;
+
+fn foo<F>(f: F) where F: FnMut(Foo) {}
 
 fn main() {
     foo(|s| s.is_empty());
index ba8121eb5cc35883be6c409cbc72de4d3a8bc783..2c14dfad3b858ae352cef9cf901b0ffdb7f9d37e 100644 (file)
@@ -12,6 +12,9 @@
 
 extern crate no_method_suggested_traits;
 
+struct Foo;
+enum Bar { X }
+
 mod foo {
     trait Bar {
         fn method(&self) {}
@@ -25,23 +28,48 @@ impl Bar for char {}
 }
 
 fn main() {
+    // test the values themselves, and autoderef.
+
+
     1u32.method();
     //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
     //~^^ ERROR does not implement
     //~^^^ HELP `foo::Bar`
     //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&1u32)).method();
+    //~^ HELP following traits are implemented but not in scope, perhaps add a `use` for one of them
+    //~^^ ERROR does not implement
+    //~^^^ HELP `foo::Bar`
+    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
 
     'a'.method();
     //~^ ERROR does not implement
     //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
     //~^^^ HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&'a')).method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~^^^ HELP `foo::Bar`
 
     1i32.method();
     //~^ ERROR does not implement
     //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
     //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&1i32)).method();
+    //~^ ERROR does not implement
+    //~^^ HELP the following trait is implemented but not in scope, perhaps add a `use` for it:
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
 
-    1u64.method();
+    Foo.method();
+    //~^ ERROR does not implement
+    //~^^ HELP following traits define a method `method`, perhaps you need to implement one of them
+    //~^^^ HELP `foo::Bar`
+    //~^^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    //~^^^^^ HELP `no_method_suggested_traits::reexport::Reexported`
+    //~^^^^^^ HELP `no_method_suggested_traits::bar::PubPriv`
+    //~^^^^^^^ HELP `no_method_suggested_traits::qux::PrivPub`
+    //~^^^^^^^^ HELP `no_method_suggested_traits::quz::PrivPriv`
+    std::rc::Rc::new(&mut Box::new(&Foo)).method();
     //~^ ERROR does not implement
     //~^^ HELP following traits define a method `method`, perhaps you need to implement one of them
     //~^^^ HELP `foo::Bar`
@@ -55,8 +83,52 @@ fn main() {
     //~^ ERROR does not implement
     //~^^ HELP the following trait defines a method `method2`, perhaps you need to implement it
     //~^^^ HELP `foo::Bar`
-    1u64.method3();
+    std::rc::Rc::new(&mut Box::new(&1u64)).method2();
     //~^ ERROR does not implement
-    //~^^ HELP the following trait defines a method `method3`, perhaps you need to implement it
+    //~^^ HELP the following trait defines a method `method2`, perhaps you need to implement it
+    //~^^^ HELP `foo::Bar`
+
+    no_method_suggested_traits::Foo.method2();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it
+    //~^^^ HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it
+    //~^^^ HELP `foo::Bar`
+    no_method_suggested_traits::Bar::X.method2();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it
+    //~^^^ HELP `foo::Bar`
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method2`, perhaps you need to implement it
+    //~^^^ HELP `foo::Bar`
+
+    Foo.method3();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&Foo)).method3();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    Bar::X.method3();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it
     //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+    std::rc::Rc::new(&mut Box::new(&Bar::X)).method3();
+    //~^ ERROR does not implement
+    //~^^ HELP following trait defines a method `method3`, perhaps you need to implement it
+    //~^^^ HELP `no_method_suggested_traits::foo::PubPub`
+
+    // should have no help:
+    1us.method3(); //~ ERROR does not implement
+    std::rc::Rc::new(&mut Box::new(&1us)).method3(); //~ ERROR does not implement
+    no_method_suggested_traits::Foo.method3();  //~ ERROR does not implement
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3();
+    //~^ ERROR does not implement
+    no_method_suggested_traits::Bar::X.method3();  //~ ERROR does not implement
+    std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3();
+    //~^ ERROR does not implement
 }
index fe79165236f8bbfa5b9332cdabd928ba2e1221b9..78c575d33bad0a932285d3389d7377bf35933bbf 100644 (file)
@@ -13,4 +13,4 @@
 pub fn main() {
     let r = 1..2..3;
     //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
-}
\ No newline at end of file
+}
index bbd6ae289cce9452592c158a6e214df246bb9f6c..a3e27fbbe9aa39938935897dd49df88f17858d99 100644 (file)
@@ -13,4 +13,4 @@
 pub fn main() {
     let r = ..1..2;
     //~^ ERROR expected one of `.`, `;`, or an operator, found `..`
-}
\ No newline at end of file
+}
index 6a624e39e326775c93c0bf3d9a2522a3ad8984d4..0f6f0ac6ae7566b76fe5742209ae2876f5d95360 100644 (file)
@@ -149,4 +149,4 @@ fn main() {
     assoc_enum(Enum::Variant2(8i64, 9i32));
 }
 
-fn zzz() { () }
\ No newline at end of file
+fn zzz() { () }
index 1d18f33fd18eecf7c666f6d872e5040a51ee23aa..b37c71bc326270ba0d745fe883275e2fd44d9f4c 100644 (file)
@@ -11,7 +11,7 @@
 use std::slice::SliceExt;
 use std::old_io::{Command, fs, USER_RWX};
 use std::os;
-use std::path::BytesContainer;
+use std::old_path::BytesContainer;
 use std::rand::random;
 
 fn main() {
index 6647fbe2238ef60ed82868ea71af6cc87e048940..0d85f61e51350d7dbc3715882505ab855f3f3d6e 100644 (file)
@@ -1,4 +1,3 @@
-
 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
 // file at the top-level directory of this distribution and at
 // http://rust-lang.org/COPYRIGHT.
@@ -15,8 +14,8 @@
 #![feature(box_syntax)]
 #![feature(unboxed_closures)]
 
-use std::path::{Path};
-use std::path;
+use std::old_path::{Path};
+use std::old_path;
 use std::result;
 use std::thunk::Thunk;
 
@@ -28,7 +27,7 @@ fn tester()
         result::Result::Ok("more blah".to_string())
     };
 
-    let path = path::Path::new("blah");
+    let path = old_path::Path::new("blah");
     assert!(loader(&path).is_ok());
 }
 
index 5dcaa885e380c5aa46dad882789eb4a87773dde7..c6fd55272610957b83f1f05a1c11beb360f4f7f4 100644 (file)
@@ -20,7 +20,7 @@
 use std::old_io::fs;
 use std::old_io::Command;
 use std::os;
-use std::path::Path;
+use std::old_path::Path;
 
 fn main() {
     let my_args = os::args();