]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #21499 - P1start:issue-8706, r=huonw
authorbors <bors@rust-lang.org>
Wed, 4 Feb 2015 12:42:40 +0000 (12:42 +0000)
committerbors <bors@rust-lang.org>
Wed, 4 Feb 2015 12:42:40 +0000 (12:42 +0000)
Closes #8706.

151 files changed:
src/compiletest/header.rs
src/compiletest/runtest.rs
src/doc/reference.md
src/etc/generate-deriving-span-tests.py
src/liballoc/boxed.rs
src/libarena/lib.rs
src/libcollections/lib.rs
src/libcollections/vec_map.rs
src/libcore/error.rs
src/libcore/fmt/mod.rs
src/libcore/iter.rs
src/libcoretest/lib.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/middle/check_loop.rs
src/librustc/middle/liveness.rs
src/librustc/middle/mem_categorization.rs
src/librustc/middle/stability.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc_back/abi.rs
src/librustc_back/sha2.rs
src/librustc_back/svh.rs
src/librustc_back/target/mod.rs
src/librustc_borrowck/borrowck/mod.rs
src/librustc_driver/driver.rs
src/librustc_driver/lib.rs
src/librustc_driver/pretty.rs
src/librustc_driver/test.rs
src/librustc_resolve/lib.rs
src/librustc_trans/save/mod.rs
src/librustc_trans/trans/base.rs
src/librustc_trans/trans/debuginfo.rs
src/librustc_trans/trans/expr.rs
src/librustc_typeck/check/closure.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/librustc_typeck/check/upvar.rs
src/librustc_typeck/check/writeback.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/io/buffered.rs [new file with mode: 0644]
src/libstd/io/cursor.rs [new file with mode: 0644]
src/libstd/io/error.rs [new file with mode: 0644]
src/libstd/io/impls.rs [new file with mode: 0644]
src/libstd/io/mod.rs [new file with mode: 0644]
src/libstd/io/prelude.rs [new file with mode: 0644]
src/libstd/io/util.rs [new file with mode: 0644]
src/libstd/lib.rs
src/libstd/num/strconv.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/mod.rs
src/libstd/rand/os.rs
src/libstd/sync/rwlock.rs
src/libstd/sys/common/mod.rs
src/libstd/sys/unix/c.rs
src/libstd/sys/unix/mod.rs
src/libstd/sys/unix/os.rs
src/libstd/sys/unix/os_str.rs
src/libstd/sys/unix/process.rs
src/libstd/sys/windows/backtrace.rs
src/libstd/sys/windows/mod.rs
src/libstd/sys/windows/os_str.rs
src/libstd/sys/windows/process.rs
src/libstd/thread_local/mod.rs
src/libstd/time/duration.rs
src/libstd/time/mod.rs
src/libsyntax/ast.rs
src/libsyntax/ast_map/blocks.rs
src/libsyntax/ext/build.rs
src/libsyntax/ext/deriving/rand.rs
src/libsyntax/ext/expand.rs
src/libsyntax/feature_gate.rs
src/libsyntax/fold.rs
src/libsyntax/parse/obsolete.rs
src/libsyntax/parse/parser.rs
src/libsyntax/parse/token.rs
src/libsyntax/print/pprust.rs
src/libsyntax/visit.rs
src/libtest/lib.rs
src/libunicode/u_str.rs
src/test/auxiliary/lint_stability.rs
src/test/auxiliary/no_method_suggested_traits.rs
src/test/compile-fail/borrow-immutable-upvar-mutation.rs
src/test/compile-fail/borrowck-move-by-capture.rs
src/test/compile-fail/cannot-mutate-captured-non-mut-var.rs
src/test/compile-fail/deriving-span-Rand-enum-struct-variant.rs [deleted file]
src/test/compile-fail/deriving-span-Rand-enum.rs [deleted file]
src/test/compile-fail/deriving-span-Rand-struct.rs [deleted file]
src/test/compile-fail/deriving-span-Rand-tuple-struct.rs [deleted file]
src/test/compile-fail/issue-11925.rs
src/test/compile-fail/issue-12127.rs
src/test/compile-fail/lint-stability.rs
src/test/compile-fail/lint-unused-extern-crate.rs
src/test/compile-fail/macros-nonfatal-errors.rs
src/test/compile-fail/method-suggestion-no-duplication.rs
src/test/compile-fail/missing-stability.rs [new file with mode: 0644]
src/test/compile-fail/moves-based-on-type-move-out-of-closure-env-issue-1965.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/compile-fail/unboxed-closer-non-implicit-copyable.rs
src/test/compile-fail/unboxed-closure-illegal-move.rs
src/test/compile-fail/unboxed-closures-mutate-upvar.rs
src/test/compile-fail/unboxed-closures-static-call-wrong-trait.rs
src/test/compile-fail/unboxed-closures-vtable-mismatch.rs
src/test/compile-fail/unboxed-closures-wrong-trait.rs [deleted file]
src/test/debuginfo/associated-types.rs
src/test/run-pass/closure-inference.rs
src/test/run-pass/issue-15149.rs
src/test/run-pass/issue-3424.rs
src/test/run-pass/last-use-in-cap-clause.rs
src/test/run-pass/process-spawn-with-unicode-params.rs
src/test/run-pass/unboxed-closures-zero-args.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 64ddb3ffdd39ffa5fbe1e706f26e99d5ccd8db0c..326946837bf661ee0c158a212832a00cbd303525 100644 (file)
@@ -2432,6 +2432,8 @@ The currently implemented features of the reference compiler are:
 * `simd` - Allows use of the `#[simd]` attribute, which is overly simple and
            not the SIMD interface we want to expose in the long term.
 
+* `staged_api` - Allows usage of stability markers and `#![staged_api]` in a crate
+
 * `struct_inherit` - Allows using struct inheritance, which is barely
                      implemented and will probably be removed. Don't use this.
 
@@ -2459,6 +2461,11 @@ The currently implemented features of the reference compiler are:
                         which is considered wildly unsafe and will be
                         obsoleted by language improvements.
 
+* `unmarked_api` - Allows use of items within a `#![staged_api]` crate
+                   which have not been marked with a stability marker.
+                   Such items should not be allowed by the compiler to exist,
+                   so if you need this there probably is a compiler bug.
+
 * `associated_types` - Allows type aliases in traits. Experimental.
 
 If a feature is promoted to a language feature, then all existing programs will
index eeb1b89472b3d36c82c14413fc2aa7d3804d1c04..a8a62358d3afe41f578c2a7ca2701a7db295f717 100755 (executable)
@@ -114,8 +114,7 @@ traits = {
     'Encodable': (0, [], 0), # FIXME: quoting gives horrible spans
 }
 
-for (trait, supers, errs) in [('Rand', [], 1),
-                              ('Clone', [], 1),
+for (trait, supers, errs) in [('Clone', [], 1),
                               ('PartialEq', [], 2),
                               ('PartialOrd', ['PartialEq'], 8),
                               ('Eq', ['PartialEq'], 1),
index 504b58d8ad1058886fee5672cc9925e5bbd36c9c..340a8d59612f21af31e685b6f5e40fb824b234cf 100644 (file)
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
+use core::prelude::*;
+
 use core::any::Any;
-use core::clone::Clone;
-use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
+use core::cmp::Ordering;
 use core::default::Default;
 use core::error::{Error, FromError};
 use core::fmt;
 use core::hash::{self, Hash};
-use core::iter::Iterator;
-use core::marker::Sized;
 use core::mem;
 use core::ops::{Deref, DerefMut};
-use core::option::Option;
 use core::ptr::Unique;
 use core::raw::TraitObject;
-use core::result::Result::{Ok, Err};
-use core::result::Result;
 
 /// A value that represents the heap. This is the default place that the `box` keyword allocates
 /// into when no place is supplied.
@@ -296,18 +292,20 @@ impl<T: ?Sized> DerefMut for Box<T> {
     fn deref_mut(&mut self) -> &mut T { &mut **self }
 }
 
-impl<'a, T> Iterator for Box<Iterator<Item=T> + 'a> {
-    type Item = T;
-
-    fn next(&mut self) -> Option<T> {
-        (**self).next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (**self).size_hint()
-    }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: Iterator + ?Sized> Iterator for Box<I> {
+    type Item = I::Item;
+    fn next(&mut self) -> Option<I::Item> { (**self).next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for Box<I> {
+    fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
 }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<I: ExactSizeIterator + ?Sized> ExactSizeIterator for Box<I> {}
 
+#[stable(feature = "rust1", since = "1.0.0")]
 impl<'a, E: Error + 'a> FromError<E> for Box<Error + 'a> {
     fn from_error(err: E) -> Box<Error + 'a> {
         Box::new(err)
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 102dfb3df9d0319b4e221ca4863bb07c49cfc618..f44141fe0f49370eccac5a83ed995b62ed3e416d 100644 (file)
@@ -32,6 +32,7 @@
 #![feature(unicode)]
 #![feature(unsafe_destructor, slicing_syntax)]
 #![cfg_attr(test, feature(test))]
+#![cfg_attr(test, allow(deprecated))] // rand
 
 #![no_std]
 
index c74c870eef5d5cfa707c8b8fa40488a5c40b4617..abcf358a1926c00baee9db9d8f8d8042da941603 100644 (file)
@@ -13,6 +13,8 @@
 
 #![allow(missing_docs)]
 
+pub use self::Entry::*;
+
 use core::prelude::*;
 
 use core::cmp::Ordering;
@@ -66,6 +68,32 @@ pub struct VecMap<V> {
     v: Vec<Option<V>>,
 }
 
+/// A view into a single entry in a map, which may either be vacant or occupied.
+#[unstable(feature = "collections",
+           reason = "precise API still under development")]
+pub enum Entry<'a, V:'a> {
+    /// A vacant Entry
+    Vacant(VacantEntry<'a, V>),
+    /// An occupied Entry
+    Occupied(OccupiedEntry<'a, V>),
+}
+
+/// A vacant Entry.
+#[unstable(feature = "collections",
+           reason = "precise API still under development")]
+pub struct VacantEntry<'a, V:'a> {
+    map: &'a mut VecMap<V>,
+    index: usize,
+}
+
+/// An occupied Entry.
+#[unstable(feature = "collections",
+           reason = "precise API still under development")]
+pub struct OccupiedEntry<'a, V:'a> {
+    map: &'a mut VecMap<V>,
+    index: usize,
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl<V> Default for VecMap<V> {
     #[stable(feature = "rust1", since = "1.0.0")]
@@ -485,6 +513,119 @@ pub fn remove(&mut self, key: &uint) -> Option<V> {
         let result = &mut self.v[*key];
         result.take()
     }
+
+    /// Gets the given key's corresponding entry in the map for in-place manipulation.
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::collections::VecMap;
+    /// use std::collections::vec_map::Entry;
+    ///
+    /// let mut count: VecMap<u32> = VecMap::new();
+    ///
+    /// // count the number of occurrences of numbers in the vec
+    /// for x in vec![1, 2, 1, 2, 3, 4, 1, 2, 4].iter() {
+    ///     match count.entry(*x) {
+    ///         Entry::Vacant(view) => {
+    ///             view.insert(1);
+    ///         },
+    ///         Entry::Occupied(mut view) => {
+    ///             let v = view.get_mut();
+    ///             *v += 1;
+    ///         },
+    ///     }
+    /// }
+    ///
+    /// assert_eq!(count[1], 3);
+    /// ```
+    #[unstable(feature = "collections",
+               reason = "precise API still under development")]
+    pub fn entry(&mut self, key: usize) -> Entry<V> {
+        // FIXME(Gankro): this is basically the dumbest implementation of
+        // entry possible, because weird non-lexical borrows issues make it
+        // completely insane to do any other way. That said, Entry is a border-line
+        // useless construct on VecMap, so it's hardly a big loss.
+        if self.contains_key(&key) {
+            Occupied(OccupiedEntry {
+                map: self,
+                index: key,
+            })
+        } else {
+            Vacant(VacantEntry {
+                map: self,
+                index: key,
+            })
+        }
+    }
+}
+
+
+impl<'a, V> Entry<'a, V> {
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    /// Returns a mutable reference to the entry if occupied, or the VacantEntry if vacant
+    pub fn get(self) -> Result<&'a mut V, VacantEntry<'a, V>> {
+        match self {
+            Occupied(entry) => Ok(entry.into_mut()),
+            Vacant(entry) => Err(entry),
+        }
+    }
+}
+
+impl<'a, V> VacantEntry<'a, V> {
+    /// Sets the value of the entry with the VacantEntry's key,
+    /// and returns a mutable reference to it.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn insert(self, value: V) -> &'a mut V {
+        let index = self.index;
+        self.map.insert(index, value);
+        &mut self.map[index]
+    }
+}
+
+impl<'a, V> OccupiedEntry<'a, V> {
+    /// Gets a reference to the value in the entry.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn get(&self) -> &V {
+        let index = self.index;
+        &self.map[index]
+    }
+
+    /// Gets a mutable reference to the value in the entry.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn get_mut(&mut self) -> &mut V {
+        let index = self.index;
+        &mut self.map[index]
+    }
+
+    /// Converts the entry into a mutable reference to its value.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn into_mut(self) -> &'a mut V {
+        let index = self.index;
+        &mut self.map[index]
+    }
+
+    /// Sets the value of the entry with the OccupiedEntry's key,
+    /// and returns the entry's old value.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn insert(&mut self, value: V) -> V {
+        let index = self.index;
+        self.map.insert(index, value).unwrap()
+    }
+
+    /// Takes the value of the entry out of the map, and returns it.
+    #[unstable(feature = "collections",
+               reason = "matches collection reform v2 specification, waiting for dust to settle")]
+    pub fn remove(self) -> V {
+        let index = self.index;
+        self.map.remove(&index).unwrap()
+    }
 }
 
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -783,7 +924,7 @@ mod test_map {
     use prelude::*;
     use core::hash::{hash, SipHasher};
 
-    use super::VecMap;
+    use super::{VecMap, Occupied, Vacant};
 
     #[test]
     fn test_get_mut() {
@@ -1135,6 +1276,57 @@ fn test_index_nonexistent() {
 
         map[4];
     }
+
+    #[test]
+    fn test_entry(){
+        let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)];
+
+        let mut map: VecMap<i32> = xs.iter().map(|&x| x).collect();
+
+        // Existing key (insert)
+        match map.entry(1) {
+            Vacant(_) => unreachable!(),
+            Occupied(mut view) => {
+                assert_eq!(view.get(), &10);
+                assert_eq!(view.insert(100), 10);
+            }
+        }
+        assert_eq!(map.get(&1).unwrap(), &100);
+        assert_eq!(map.len(), 6);
+
+
+        // Existing key (update)
+        match map.entry(2) {
+            Vacant(_) => unreachable!(),
+            Occupied(mut view) => {
+                let v = view.get_mut();
+                *v *= 10;
+            }
+        }
+        assert_eq!(map.get(&2).unwrap(), &200);
+        assert_eq!(map.len(), 6);
+
+        // Existing key (take)
+        match map.entry(3) {
+            Vacant(_) => unreachable!(),
+            Occupied(view) => {
+                assert_eq!(view.remove(), 30);
+            }
+        }
+        assert_eq!(map.get(&3), None);
+        assert_eq!(map.len(), 5);
+
+
+        // Inexistent key (insert)
+        match map.entry(10) {
+            Occupied(_) => unreachable!(),
+            Vacant(view) => {
+                assert_eq!(*view.insert(1000), 1000);
+            }
+        }
+        assert_eq!(map.get(&10).unwrap(), &1000);
+        assert_eq!(map.len(), 6);
+    }
 }
 
 #[cfg(test)]
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 551277bae5c6bd061bc29ba482ba27ee5af79379..60262857765e26854a24012b825df22eb3f06ae9 100644 (file)
@@ -264,6 +264,7 @@ pub trait Show {
 #[lang = "debug_trait"]
 pub trait Debug {
     /// Formats the value using the given formatter.
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, &mut Formatter) -> Result;
 }
 
@@ -290,6 +291,7 @@ pub trait String {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait Display {
     /// Formats the value using the given formatter.
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn fmt(&self, &mut Formatter) -> Result;
 }
 
index d0734f9c0395faec4b2713420651137cf4a3e4ec..23157072d536b554e14e47d01207755a4120665b 100644 (file)
@@ -101,16 +101,11 @@ pub trait Iterator {
     fn size_hint(&self) -> (usize, Option<usize>) { (0, None) }
 }
 
-impl<'a, T> Iterator for &'a mut (Iterator<Item=T> + 'a) {
-    type Item = T;
-
-    fn next(&mut self) -> Option<T> {
-        (**self).next()
-    }
-
-    fn size_hint(&self) -> (usize, Option<usize>) {
-        (**self).size_hint()
-    }
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, I: Iterator + ?Sized> Iterator for &'a mut I {
+    type Item = I::Item;
+    fn next(&mut self) -> Option<I::Item> { (**self).next() }
+    fn size_hint(&self) -> (usize, Option<usize>) { (**self).size_hint() }
 }
 
 /// Conversion from an `Iterator`
@@ -119,6 +114,7 @@ fn size_hint(&self) -> (usize, Option<usize>) {
                           built from an iterator over elements of type `{A}`"]
 pub trait FromIterator<A> {
     /// Build a container with elements from an external iterator.
+    #[stable(feature = "rust1", since = "1.0.0")]
     fn from_iter<T: Iterator<Item=A>>(iterator: T) -> Self;
 }
 
@@ -548,9 +544,7 @@ fn inspect<F>(self, f: F) -> Inspect<Self, F> where
     /// assert!(it.next() == Some(5));
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
-    fn by_ref<'r>(&'r mut self) -> ByRef<'r, Self> {
-        ByRef{iter: self}
-    }
+    fn by_ref(&mut self) -> &mut Self { self }
 
     /// Loops through the entire iterator, collecting all of the elements into
     /// a container implementing `FromIterator`.
@@ -723,11 +717,12 @@ fn rposition<P>(&mut self, mut predicate: P) -> Option<usize> where
         P: FnMut(Self::Item) -> bool,
         Self: ExactSizeIterator + DoubleEndedIterator
     {
-        let len = self.len();
-        for i in (0..len).rev() {
-            if predicate(self.next_back().expect("rposition: incorrect ExactSizeIterator")) {
+        let mut i = self.len() - 1;
+        while let Some(v) = self.next_back() {
+            if predicate(v) {
                 return Some(i);
             }
+            i -= 1;
         }
         None
     }
@@ -1017,15 +1012,22 @@ impl<I> IteratorExt for I where I: Iterator {}
 
 /// A range iterator able to yield elements from both ends
 ///
-/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and `next_back()` exhaust
-/// elements from the *same* range, and do not work independently of each other.
+/// A `DoubleEndedIterator` can be thought of as a deque in that `next()` and
+/// `next_back()` exhaust elements from the *same* range, and do not work
+/// independently of each other.
 #[stable(feature = "rust1", since = "1.0.0")]
 pub trait DoubleEndedIterator: Iterator {
-    /// Yield an element from the end of the range, returning `None` if the range is empty.
+    /// Yield an element from the end of the range, returning `None` if the
+    /// range is empty.
     #[stable(feature = "rust1", since = "1.0.0")]
     fn next_back(&mut self) -> Option<Self::Item>;
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I {
+    fn next_back(&mut self) -> Option<I::Item> { (**self).next_back() }
+}
+
 /// An object implementing random access indexing by `usize`
 ///
 /// A `RandomAccessIterator` should be either infinite or a `DoubleEndedIterator`.
@@ -1065,6 +1067,9 @@ fn len(&self) -> usize {
     }
 }
 
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<'a, I: ExactSizeIterator + ?Sized> ExactSizeIterator for &'a mut I {}
+
 // All adaptors that preserve the size of the wrapped iterator are fine
 // Adaptors that may overflow in `size_hint` are not, i.e. `Chain`.
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -1117,32 +1122,6 @@ fn idx(&mut self, index: usize) -> Option<<I as Iterator>::Item> {
     }
 }
 
-/// A mutable reference to an iterator
-#[must_use = "iterator adaptors are lazy and do nothing unless consumed"]
-#[stable(feature = "rust1", since = "1.0.0")]
-pub struct ByRef<'a, I:'a> {
-    iter: &'a mut I,
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, I> Iterator for ByRef<'a, I> where I: 'a + Iterator {
-    type Item = <I as Iterator>::Item;
-
-    #[inline]
-    fn next(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next() }
-    #[inline]
-    fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, I> DoubleEndedIterator for ByRef<'a, I> where I: 'a + DoubleEndedIterator {
-    #[inline]
-    fn next_back(&mut self) -> Option<<I as Iterator>::Item> { self.iter.next_back() }
-}
-
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<'a, I> ExactSizeIterator for ByRef<'a, I> where I: 'a + ExactSizeIterator {}
-
 /// A trait for iterators over elements which can be added together
 #[unstable(feature = "core",
            reason = "needs to be re-evaluated as part of numerics reform")]
@@ -1821,6 +1800,7 @@ impl<I: Iterator> Peekable<I> {
     /// Return a reference to the next element of the iterator with out
     /// advancing it, or None if the iterator is exhausted.
     #[inline]
+    #[stable(feature = "rust1", since = "1.0.0")]
     pub fn peek(&mut self) -> Option<&I::Item> {
         if self.peeked.is_none() {
             self.peeked = self.iter.next();
index c26d3e7bb8a7dd6b6ff0f72e094b9018b5594f98..50066ab07f555f2f53864584bfce48e9d7fff010 100644 (file)
@@ -12,6 +12,7 @@
 #![feature(int_uint)]
 #![feature(unboxed_closures)]
 #![feature(unsafe_destructor, slicing_syntax)]
+#![allow(deprecated)] // rand
 
 extern crate core;
 extern crate test;
index e7fb2ba56ab358c37651fb03e43a563bc958b41f..a3bbba6d7b432eb0f4ee48d541b50cd187cf9c45 100644 (file)
@@ -130,6 +130,7 @@ pub fn inflate_bytes_zlib(bytes: &[u8]) -> Option<Bytes> {
 
 #[cfg(test)]
 mod tests {
+    #![allow(deprecated)]
     use super::{inflate_bytes, deflate_bytes};
     use std::rand;
     use std::rand::Rng;
@@ -138,14 +139,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..0627b461fdb0c2bec691da0c28f460cbae6161f2 100644 (file)
 #![feature(staged_api)]
 #![staged_api]
 #![feature(core)]
+#![deprecated(reason = "use the crates.io `rand` library instead",
+              since = "1.0.0-alpha")]
+
+#![allow(deprecated)]
 
 #[macro_use]
 extern crate core;
@@ -222,7 +226,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 +282,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 +302,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 41ef55933cda2e841f14d54f9af249fdf29b0fa8..ea584407944abeaa89d657e1cf47953fa62700ef 100644 (file)
@@ -45,7 +45,7 @@ fn visit_expr(&mut self, e: &ast::Expr) {
             ast::ExprLoop(ref b, _) => {
                 self.with_context(Loop, |v| v.visit_block(&**b));
             }
-            ast::ExprClosure(_, _, _, ref b) => {
+            ast::ExprClosure(_, _, ref b) => {
                 self.with_context(Closure, |v| v.visit_block(&**b));
             }
             ast::ExprBreak(_) => self.require_loop("break", e.span),
index e40e04bdee86acc308e66d45cf80fccbea0b78c7..c0fabb2a3481d7c622145e6ec939388e7f49ee40 100644 (file)
@@ -959,7 +959,7 @@ fn propagate_through_expr(&mut self, expr: &Expr, succ: LiveNode)
               self.propagate_through_expr(&**e, succ)
           }
 
-          ast::ExprClosure(_, _, _, ref blk) => {
+          ast::ExprClosure(_, _, ref blk) => {
               debug!("{} is an ExprClosure",
                      expr_to_string(expr));
 
index 1ae483be2696d83a93183a58d73da756e7ada219..156ff43e2bab3c690e1e491c6d33ace9dfef276f 100644 (file)
@@ -739,7 +739,7 @@ fn env_deref(&self,
             };
 
             match fn_expr.node {
-                ast::ExprClosure(_, _, _, ref body) => body.id,
+                ast::ExprClosure(_, _, ref body) => body.id,
                 _ => unreachable!()
             }
         };
index 5028a1322cac1aaff0a6d369b72acef40883e531..3304bd4ae2952226f0fd3f0769280562e7a18300 100644 (file)
@@ -14,6 +14,7 @@
 use session::Session;
 use lint;
 use middle::ty;
+use middle::privacy::PublicItems;
 use metadata::csearch;
 use syntax::parse::token::InternedString;
 use syntax::codemap::{Span, DUMMY_SP};
@@ -44,15 +45,16 @@ pub struct Index {
 // A private tree-walker for producing an Index.
 struct Annotator<'a> {
     sess: &'a Session,
-    index: Index,
-    parent: Option<Stability>
+    index: &'a mut Index,
+    parent: Option<Stability>,
+    export_map: &'a PublicItems,
 }
 
 impl<'a> Annotator<'a> {
     // Determine the stability for a node based on its attributes and inherited
     // stability. The stability is recorded in the index and used as the parent.
     fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
-                   attrs: &Vec<Attribute>, item_sp: Span, f: F) where
+                   attrs: &Vec<Attribute>, item_sp: Span, f: F, required: bool) where
         F: FnOnce(&mut Annotator),
     {
         match attr::find_stability(self.sess.diagnostic(), attrs.as_slice(), item_sp) {
@@ -70,7 +72,14 @@ fn annotate<F>(&mut self, id: NodeId, use_parent: bool,
             }
             None => {
                 if use_parent {
-                    self.parent.clone().map(|stab| self.index.local.insert(id, stab));
+                    if let Some(stab) = self.parent.clone() {
+                        self.index.local.insert(id, stab);
+                    } else if self.index.staged_api && required
+                           && self.export_map.contains(&id)
+                           && !self.sess.opts.test {
+                        self.sess.span_err(item_sp,
+                                           "This node does not have a stability attribute");
+                    }
                 }
                 f(self);
             }
@@ -93,11 +102,19 @@ fn visit_item(&mut self, i: &Item) {
             _ => true,
         };
 
-        self.annotate(i.id, use_parent, &i.attrs, i.span, |v| visit::walk_item(v, i));
+        // In case of a `pub use <mod>;`, we should not error since the stability
+        // is inherited from the module itself
+        let required = match i.node {
+            ast::ItemUse(_) => i.vis != ast::Public,
+            _ => true
+        };
+
+        self.annotate(i.id, use_parent, &i.attrs, i.span,
+                      |v| visit::walk_item(v, i), required);
 
         if let ast::ItemStruct(ref sd, _) = i.node {
             sd.ctor_id.map(|id| {
-                self.annotate(id, true, &i.attrs, i.span, |_| {})
+                self.annotate(id, true, &i.attrs, i.span, |_| {}, true)
             });
         }
     }
@@ -106,7 +123,7 @@ fn visit_fn(&mut self, fk: FnKind<'v>, _: &'v FnDecl,
                 _: &'v Block, sp: Span, _: NodeId) {
         if let FkMethod(_, _, meth) = fk {
             // Methods are not already annotated, so we annotate it
-            self.annotate(meth.id, true, &meth.attrs, sp, |_| {});
+            self.annotate(meth.id, true, &meth.attrs, sp, |_| {}, true);
         }
         // Items defined in a function body have no reason to have
         // a stability attribute, so we don't recurse.
@@ -126,27 +143,41 @@ fn visit_trait_item(&mut self, t: &TraitItem) {
             TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs,
                                            typedef.ty_param.span),
         };
-        self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t));
+        self.annotate(id, true, attrs, sp, |v| visit::walk_trait_item(v, t), true);
     }
 
     fn visit_variant(&mut self, var: &Variant, g: &'v Generics) {
         self.annotate(var.node.id, true, &var.node.attrs, var.span,
-                      |v| visit::walk_variant(v, var, g))
+                      |v| visit::walk_variant(v, var, g), true)
     }
 
     fn visit_struct_field(&mut self, s: &StructField) {
         self.annotate(s.node.id, true, &s.node.attrs, s.span,
-                      |v| visit::walk_struct_field(v, s));
+                      |v| visit::walk_struct_field(v, s), true);
     }
 
     fn visit_foreign_item(&mut self, i: &ast::ForeignItem) {
-        self.annotate(i.id, true, &i.attrs, i.span, |_| {});
+        self.annotate(i.id, true, &i.attrs, i.span, |_| {}, true);
     }
 }
 
 impl Index {
     /// Construct the stability index for a crate being compiled.
-    pub fn build(sess: &Session, krate: &Crate) -> Index {
+    pub fn build(&mut self, sess: &Session, krate: &Crate, export_map: &PublicItems) {
+        if !self.staged_api {
+            return;
+        }
+        let mut annotator = Annotator {
+            sess: sess,
+            index: self,
+            parent: None,
+            export_map: export_map,
+        };
+        annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
+                           |v| visit::walk_crate(v, krate), true);
+    }
+
+    pub fn new(krate: &Crate) -> Index {
         let mut staged_api = false;
         for attr in &krate.attrs {
             if attr.name().get() == "staged_api" {
@@ -159,22 +190,11 @@ pub fn build(sess: &Session, krate: &Crate) -> Index {
                 }
             }
         }
-        let index = Index {
+        Index {
             staged_api: staged_api,
             local: NodeMap(),
             extern_cache: DefIdMap()
-        };
-        if !staged_api {
-            return index;
         }
-        let mut annotator = Annotator {
-            sess: sess,
-            index: index,
-            parent: None
-        };
-        annotator.annotate(ast::CRATE_NODE_ID, true, &krate.attrs, krate.span,
-                           |v| visit::walk_crate(v, krate));
-        annotator.index
     }
 }
 
@@ -234,10 +254,19 @@ fn check(&mut self, id: ast::DefId, span: Span, stab: &Option<Stability>) {
             None => {
                 // This is an 'unmarked' API, which should not exist
                 // in the standard library.
-                self.tcx.sess.span_err(span, "use of unmarked library feature");
-                self.tcx.sess.span_note(span, "this is either a bug in the library you are \
-                                               using or a bug in the compiler - there is \
-                                               no way to use this feature");
+                if self.tcx.sess.features.borrow().unmarked_api {
+                    self.tcx.sess.span_warn(span, "use of unmarked library feature");
+                    self.tcx.sess.span_note(span, "this is either a bug in the library you are \
+                                                   using and a bug in the compiler - please \
+                                                   report it in both places");
+                } else {
+                    self.tcx.sess.span_err(span, "use of unmarked library feature");
+                    self.tcx.sess.span_note(span, "this is either a bug in the library you are \
+                                                   using and a bug in the compiler - please \
+                                                   report it in both places");
+                    self.tcx.sess.span_note(span, "use #![feature(unmarked_api)] in the \
+                                                   crate attributes to override this");
+                }
             }
         }
     }
index 3ede6bbb965ef4f823f2dd5056db4b1e6ff2d639..c2a451b405bb5008018d635a94662460178a746c 100644 (file)
@@ -80,37 +80,23 @@ pub fn poly_project_and_unify_type<'cx,'tcx>(
            obligation.repr(selcx.tcx()));
 
     let infcx = selcx.infcx();
-    let result = infcx.try(|snapshot| {
+    infcx.try(|snapshot| {
         let (skol_predicate, skol_map) =
             infcx.skolemize_late_bound_regions(&obligation.predicate, snapshot);
 
         let skol_obligation = obligation.with(skol_predicate);
         match project_and_unify_type(selcx, &skol_obligation) {
-            Ok(Some(obligations)) => {
+            Ok(result) => {
                 match infcx.leak_check(&skol_map, snapshot) {
-                    Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &obligations)),
-                    Err(e) => Err(Some(MismatchedProjectionTypes { err: e })),
+                    Ok(()) => Ok(infcx.plug_leaks(skol_map, snapshot, &result)),
+                    Err(e) => Err(MismatchedProjectionTypes { err: e }),
                 }
             }
-            Ok(None) => {
-                // Signal ambiguity using Err just so that infcx.try()
-                // rolls back the snapshot. We adapt below.
-                Err(None)
-            }
             Err(e) => {
-                Err(Some(e))
+                Err(e)
             }
         }
-    });
-
-    // Above, we use Err(None) to signal ambiguity so that the
-    // snapshot will be rolled back. But here, we want to translate to
-    // Ok(None). Kind of weird.
-    match result {
-        Ok(obligations) => Ok(Some(obligations)),
-        Err(None) => Ok(None),
-        Err(Some(e)) => Err(e),
-    }
+    })
 }
 
 /// Evaluates constraints of the form:
@@ -132,7 +118,10 @@ fn project_and_unify_type<'cx,'tcx>(
                                             obligation.cause.clone(),
                                             obligation.recursion_depth) {
             Some(n) => n,
-            None => { return Ok(None); }
+            None => {
+                consider_unification_despite_ambiguity(selcx, obligation);
+                return Ok(None);
+            }
         };
 
     debug!("project_and_unify_type: normalized_ty={} obligations={}",
@@ -147,6 +136,50 @@ fn project_and_unify_type<'cx,'tcx>(
     }
 }
 
+fn consider_unification_despite_ambiguity<'cx,'tcx>(selcx: &mut SelectionContext<'cx,'tcx>,
+                                                    obligation: &ProjectionObligation<'tcx>) {
+    debug!("consider_unification_despite_ambiguity(obligation={})",
+           obligation.repr(selcx.tcx()));
+
+    let def_id = obligation.predicate.projection_ty.trait_ref.def_id;
+    match selcx.tcx().lang_items.fn_trait_kind(def_id) {
+        Some(_) => { }
+        None => { return; }
+    }
+
+    let infcx = selcx.infcx();
+    let self_ty = obligation.predicate.projection_ty.trait_ref.self_ty();
+    let self_ty = infcx.shallow_resolve(self_ty);
+    debug!("consider_unification_despite_ambiguity: self_ty.sty={:?}",
+           self_ty.sty);
+    match self_ty.sty {
+        ty::ty_closure(closure_def_id, _, substs) => {
+            let closure_typer = selcx.closure_typer();
+            let closure_type = closure_typer.closure_type(closure_def_id, substs);
+            let ty::Binder((_, ret_type)) =
+                util::closure_trait_ref_and_return_type(infcx.tcx,
+                                                        def_id,
+                                                        self_ty,
+                                                        &closure_type.sig,
+                                                        util::TupleArgumentsFlag::No);
+            let (ret_type, _) =
+                infcx.replace_late_bound_regions_with_fresh_var(
+                    obligation.cause.span,
+                    infer::AssocTypeProjection(obligation.predicate.projection_ty.item_name),
+                    &ty::Binder(ret_type));
+            debug!("consider_unification_despite_ambiguity: ret_type={:?}",
+                   ret_type.repr(selcx.tcx()));
+            let origin = infer::RelateOutputImplTypes(obligation.cause.span);
+            let obligation_ty = obligation.predicate.ty;
+            match infer::mk_eqty(infcx, true, origin, obligation_ty, ret_type) {
+                Ok(()) => { }
+                Err(_) => { /* ignore errors */ }
+            }
+        }
+        _ => { }
+    }
+}
+
 /// Normalizes any associated type projections in `value`, replacing
 /// them with a fully resolved type where possible. The return value
 /// combines the normalized result and any additional obligations that
index 000572cdd40a34f10c3edad3f8e7cca3d07fd022..b8af91add9efb56d6485cfcf145d88b39e873d85 100644 (file)
@@ -233,9 +233,8 @@ pub fn closure_typer(&self) -> &'cx (ty::ClosureTyper<'tcx>+'cx) {
     //    is `Vec<Foo>:Iterable<Bar>`, but the impl specifies
     //    `impl<T> Iterable<T> for Vec<T>`, than an error would result.
 
-    /// Evaluates whether the obligation can be satisfied. Returns an indication of whether the
-    /// obligation can be satisfied and, if so, by what means. Never affects surrounding typing
-    /// environment.
+    /// Attempts to satisfy the obligation. If successful, this will affect the surrounding
+    /// type environment by performing unification.
     pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
                   -> SelectionResult<'tcx, Selection<'tcx>> {
         debug!("select({})", obligation.repr(self.tcx()));
@@ -243,11 +242,68 @@ pub fn select(&mut self, obligation: &TraitObligation<'tcx>)
 
         let stack = self.push_stack(None, obligation);
         match try!(self.candidate_from_obligation(&stack)) {
-            None => Ok(None),
+            None => {
+                self.consider_unification_despite_ambiguity(obligation);
+                Ok(None)
+            }
             Some(candidate) => Ok(Some(try!(self.confirm_candidate(obligation, candidate)))),
         }
     }
 
+    /// In the particular case of unboxed closure obligations, we can
+    /// sometimes do some amount of unification for the
+    /// argument/return types even though we can't yet fully match obligation.
+    /// The particular case we are interesting in is an obligation of the form:
+    ///
+    ///    C : FnFoo<A>
+    ///
+    /// where `C` is an unboxed closure type and `FnFoo` is one of the
+    /// `Fn` traits. Because we know that users cannot write impls for closure types
+    /// themselves, the only way that `C : FnFoo` can fail to match is under two
+    /// conditions:
+    ///
+    /// 1. The closure kind for `C` is not yet known, because inference isn't complete.
+    /// 2. The closure kind for `C` *is* known, but doesn't match what is needed.
+    ///    For example, `C` may be a `FnOnce` closure, but a `Fn` closure is needed.
+    ///
+    /// In either case, we always know what argument types are
+    /// expected by `C`, no matter what kind of `Fn` trait it
+    /// eventually matches. So we can go ahead and unify the argument
+    /// types, even though the end result is ambiguous.
+    ///
+    /// Note that this is safe *even if* the trait would never be
+    /// matched (case 2 above). After all, in that case, an error will
+    /// result, so it kind of doesn't matter what we do --- unifying
+    /// the argument types can only be helpful to the user, because
+    /// once they patch up the kind of closure that is expected, the
+    /// argment types won't really change.
+    fn consider_unification_despite_ambiguity(&mut self, obligation: &TraitObligation<'tcx>) {
+        // Is this a `C : FnFoo(...)` trait reference for some trait binding `FnFoo`?
+        match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
+            Some(_) => { }
+            None => { return; }
+        }
+
+        // Is the self-type a closure type? We ignore bindings here
+        // because if it is a closure type, it must be a closure type from
+        // within this current fn, and hence none of the higher-ranked
+        // lifetimes can appear inside the self-type.
+        let self_ty = self.infcx.shallow_resolve(obligation.self_ty());
+        let (closure_def_id, substs) = match self_ty.sty {
+            ty::ty_closure(id, _, ref substs) => (id, substs.clone()),
+            _ => { return; }
+        };
+        assert!(!substs.has_escaping_regions());
+
+        let closure_trait_ref = self.closure_trait_ref(obligation, closure_def_id, substs);
+        match self.confirm_poly_trait_refs(obligation.cause.clone(),
+                                           obligation.predicate.to_poly_trait_ref(),
+                                           closure_trait_ref) {
+            Ok(()) => { }
+            Err(_) => { /* Silently ignore errors. */ }
+        }
+    }
+
     ///////////////////////////////////////////////////////////////////////////
     // EVALUATION
     //
@@ -1003,7 +1059,7 @@ fn assemble_closure_candidates(&mut self,
                                    candidates: &mut SelectionCandidateSet<'tcx>)
                                    -> Result<(),SelectionError<'tcx>>
     {
-        let kind = match self.fn_family_trait_kind(obligation.predicate.0.def_id()) {
+        let kind = match self.tcx().lang_items.fn_trait_kind(obligation.predicate.0.def_id()) {
             Some(k) => k,
             None => { return Ok(()); }
         };
@@ -2303,22 +2359,6 @@ fn impl_obligations(&mut self,
         impl_obligations
     }
 
-    fn fn_family_trait_kind(&self,
-                            trait_def_id: ast::DefId)
-                            -> Option<ty::ClosureKind>
-    {
-        let tcx = self.tcx();
-        if Some(trait_def_id) == tcx.lang_items.fn_trait() {
-            Some(ty::FnClosureKind)
-        } else if Some(trait_def_id) == tcx.lang_items.fn_mut_trait() {
-            Some(ty::FnMutClosureKind)
-        } else if Some(trait_def_id) == tcx.lang_items.fn_once_trait() {
-            Some(ty::FnOnceClosureKind)
-        } else {
-            None
-        }
-    }
-
     #[allow(unused_comparisons)]
     fn derived_cause(&self,
                      obligation: &TraitObligation<'tcx>,
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..286a3936314a5540500550f99dd8087432f2bf8c 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);
@@ -528,6 +528,7 @@ fn output_bits(&self) -> uint { 256 }
 
 #[cfg(test)]
 mod tests {
+    #![allow(deprecated)]
     extern crate rand;
 
     use self::rand::Rng;
@@ -569,8 +570,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 e5271cfde5a447f63063c74076afef3d430c07cf..b9d2b9ec263ab450480bf3fa02db5c5505a6dd28 100644 (file)
@@ -324,7 +324,7 @@ pub fn closure_to_block(closure_id: ast::NodeId,
                         tcx: &ty::ctxt) -> ast::NodeId {
     match tcx.map.get(closure_id) {
         ast_map::NodeExpr(expr) => match expr.node {
-            ast::ExprClosure(_, _, _, ref block) => {
+            ast::ExprClosure(_, _, ref block) => {
                 block.id
             }
             _ => {
index 9b9cc14c4761510dd53634732a23eb4a2a9513ae..8ede037594a007557d57fae70632df52507d9313 100644 (file)
@@ -594,9 +594,6 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
     time(time_passes, "loop checking", (), |_|
          middle::check_loop::check_crate(&sess, krate));
 
-    let stability_index = time(time_passes, "stability index", (), |_|
-                               stability::Index::build(&sess, krate));
-
     time(time_passes, "static item recursion checking", (), |_|
          middle::check_static_recursion::check_crate(&sess, krate, &def_map, &ast_map));
 
@@ -608,7 +605,7 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
                             freevars,
                             region_map,
                             lang_items,
-                            stability_index);
+                            stability::Index::new(krate));
 
     // passes are timed inside typeck
     typeck::check_crate(&ty_cx, trait_map);
@@ -628,6 +625,10 @@ pub fn phase_3_run_analysis_passes<'tcx>(sess: Session,
             time(time_passes, "privacy checking", maps, |(a, b)|
                  rustc_privacy::check_crate(&ty_cx, &export_map, a, b));
 
+    // Do not move this check past lint
+    time(time_passes, "stability index", (), |_|
+         ty_cx.stability.borrow_mut().build(&ty_cx.sess, krate, &public_items));
+
     time(time_passes, "intrinsic checking", (), |_|
          middle::intrinsicck::check_crate(&ty_cx));
 
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 20bf77190be720b5ede3d834f7c08f411f98f702..7dc0d9be53924f9103e1872dc4cf023bbc723dea 100644 (file)
@@ -125,7 +125,6 @@ fn test_env<F>(source_string: &str,
         resolve::resolve_crate(&sess, &ast_map, &lang_items, krate, resolve::MakeGlobMap::No);
     let named_region_map = resolve_lifetime::krate(&sess, krate, &def_map);
     let region_map = region::resolve_crate(&sess, krate);
-    let stability_index = stability::Index::build(&sess, krate);
     let tcx = ty::mk_ctxt(sess,
                           &arenas,
                           def_map,
@@ -134,7 +133,7 @@ fn test_env<F>(source_string: &str,
                           freevars,
                           region_map,
                           lang_items,
-                          stability_index);
+                          stability::Index::new(krate));
     let infcx = infer::new_infer_ctxt(&tcx);
     body(Env { infcx: &infcx });
     infcx.resolve_regions_and_report_errors(ast::CRATE_NODE_ID);
index a5fb57eadc41d0901d6d4f77043c8292b5ee9f39..dd739059ed0ddf13c10d19ea06ce7a9aab9a90bb 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",
@@ -4521,7 +4521,7 @@ fn resolve_expr(&mut self, expr: &Expr) {
                 visit::walk_expr(self, expr);
             }
 
-            ExprClosure(_, _, ref fn_decl, ref block) => {
+            ExprClosure(_, ref fn_decl, ref block) => {
                 self.resolve_function(ClosureRibKind(expr.id),
                                       Some(&**fn_decl), NoTypeParameters,
                                       &**block);
index 7758039e40a418ddbf2a522ee0c55ad68f53f75a..b0ce9641cf440e8a658e9bcb314d129720692fbe 100644 (file)
@@ -1394,7 +1394,7 @@ fn visit_expr(&mut self, ex: &ast::Expr) {
                                                       type, found {:?}", ty)[]),
                 }
             },
-            ast::ExprClosure(_, _, ref decl, ref body) => {
+            ast::ExprClosure(_, ref decl, ref body) => {
                 if generated_code(body.span) {
                     return
                 }
index 9e561fc883bb043366e5c7de7198d9863b5e3323..6901eb25b31feb1dda95147af59f7ec977ba1b13 100644 (file)
@@ -1340,7 +1340,7 @@ fn build_cfg(tcx: &ty::ctxt, id: ast::NodeId) -> (ast::NodeId, Option<cfg::CFG>)
         }
         Some(ast_map::NodeExpr(e)) => {
             match e.node {
-                ast::ExprClosure(_, _, _, ref blk) => {
+                ast::ExprClosure(_, _, ref blk) => {
                     blk
                 }
                 _ => tcx.sess.bug("unexpected expr variant in has_nested_returns")
index 66bb299273d9f86aa7aa4861f7468f3eddf783b0..c6b70e1a1abc354a47b187b628d4d94b93c584ce 100644 (file)
@@ -1283,7 +1283,7 @@ pub fn create_function_debug_context<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         }
         ast_map::NodeExpr(ref expr) => {
             match expr.node {
-                ast::ExprClosure(_, _, ref fn_decl, ref top_level_block) => {
+                ast::ExprClosure(_, ref fn_decl, ref top_level_block) => {
                     let name = format!("fn{}", token::gensym("fn"));
                     let name = token::str_to_ident(&name[]);
                     (name, &**fn_decl,
@@ -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 &&
@@ -3595,7 +3595,7 @@ fn walk_expr(cx: &CrateContext,
                 })
             }
 
-            ast::ExprClosure(_, _, ref decl, ref block) => {
+            ast::ExprClosure(_, ref decl, ref block) => {
                 with_new_scope(cx,
                                block.span,
                                scope_stack,
index bed43a5c838823e36f062f1faeab10063ab48344..44eb5b190e1a65666aafad1f46abd1cb44ac9793 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(..) => {
@@ -1094,7 +1095,7 @@ fn make_field(field_name: &str, expr: P<ast::Expr>) -> ast::Field {
         ast::ExprVec(..) | ast::ExprRepeat(..) => {
             tvec::trans_fixed_vstore(bcx, expr, dest)
         }
-        ast::ExprClosure(_, _, ref decl, ref body) => {
+        ast::ExprClosure(_, ref decl, ref body) => {
             closure::trans_closure_expr(bcx, &**decl, &**body, expr.id, dest)
         }
         ast::ExprCall(ref f, ref args) => {
index 808dbd4b319109d331678b40c15b71b1ca451d21..b2a676e878e6302e556e8aab29e462d8942da6fb 100644 (file)
@@ -25,7 +25,6 @@
 pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
                                    expr: &ast::Expr,
                                    _capture: ast::CaptureClause,
-                                   opt_kind: Option<ast::ClosureKind>,
                                    decl: &'tcx ast::FnDecl,
                                    body: &'tcx ast::Block,
                                    expected: Expectation<'tcx>) {
@@ -33,38 +32,14 @@ pub fn check_expr_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
            expr.repr(fcx.tcx()),
            expected.repr(fcx.tcx()));
 
-    let expected_sig_and_kind = expected.to_option(fcx).and_then(|ty| {
-        deduce_expectations_from_expected_type(fcx, ty)
-    });
-
-    match opt_kind {
-        None => {
-            // If users didn't specify what sort of closure they want,
-            // examine the expected type. For now, if we see explicit
-            // evidence than an unboxed closure is desired, we'll use
-            // that. Otherwise, we leave it unspecified, to be filled
-            // in by upvar inference.
-            match expected_sig_and_kind {
-                None => { // don't have information about the kind, request explicit annotation
-                    check_closure(fcx, expr, None, decl, body, None);
-                },
-                Some((sig, kind)) => {
-                    check_closure(fcx, expr, Some(kind), decl, body, Some(sig));
-                }
-            }
-        }
-
-        Some(kind) => {
-            let kind = match kind {
-                ast::FnClosureKind => ty::FnClosureKind,
-                ast::FnMutClosureKind => ty::FnMutClosureKind,
-                ast::FnOnceClosureKind => ty::FnOnceClosureKind,
-            };
-
-            let expected_sig = expected_sig_and_kind.map(|t| t.0);
-            check_closure(fcx, expr, Some(kind), decl, body, expected_sig);
-        }
-    }
+    // It's always helpful for inference if we know the kind of
+    // closure sooner rather than later, so first examine the expected
+    // type, and see if can glean a closure kind from there.
+    let (expected_sig,expected_kind) = match expected.to_option(fcx) {
+        Some(ty) => deduce_expectations_from_expected_type(fcx, ty),
+        None => (None, None)
+    };
+    check_closure(fcx, expr, expected_kind, decl, body, expected_sig)
 }
 
 fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
@@ -133,21 +108,30 @@ fn check_closure<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
 fn deduce_expectations_from_expected_type<'a,'tcx>(
     fcx: &FnCtxt<'a,'tcx>,
     expected_ty: Ty<'tcx>)
-    -> Option<(ty::FnSig<'tcx>,ty::ClosureKind)>
+    -> (Option<ty::FnSig<'tcx>>,Option<ty::ClosureKind>)
 {
+    debug!("deduce_expectations_from_expected_type(expected_ty={})",
+           expected_ty.repr(fcx.tcx()));
+
     match expected_ty.sty {
         ty::ty_trait(ref object_type) => {
             let proj_bounds = object_type.projection_bounds_with_self_ty(fcx.tcx(),
                                                                          fcx.tcx().types.err);
-            proj_bounds.iter()
-                       .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
-                       .next()
+            let expectations =
+                proj_bounds.iter()
+                           .filter_map(|pb| deduce_expectations_from_projection(fcx, pb))
+                           .next();
+
+            match expectations {
+                Some((sig, kind)) => (Some(sig), Some(kind)),
+                None => (None, None)
+            }
         }
         ty::ty_infer(ty::TyVar(vid)) => {
             deduce_expectations_from_obligations(fcx, vid)
         }
         _ => {
-            None
+            (None, None)
         }
     }
 }
@@ -155,33 +139,61 @@ fn deduce_expectations_from_expected_type<'a,'tcx>(
 fn deduce_expectations_from_obligations<'a,'tcx>(
     fcx: &FnCtxt<'a,'tcx>,
     expected_vid: ty::TyVid)
-    -> Option<(ty::FnSig<'tcx>, ty::ClosureKind)>
+    -> (Option<ty::FnSig<'tcx>>, Option<ty::ClosureKind>)
 {
     let fulfillment_cx = fcx.inh.fulfillment_cx.borrow();
     // Here `expected_ty` is known to be a type inference variable.
 
-    fulfillment_cx.pending_obligations()
-                  .iter()
-                  .filter_map(|obligation| {
-                      match obligation.predicate {
-                          ty::Predicate::Projection(ref proj_predicate) => {
-                              let trait_ref = proj_predicate.to_poly_trait_ref();
-                              let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
-                              match self_ty.sty {
-                                  ty::ty_infer(ty::TyVar(v)) if expected_vid == v => {
-                                      deduce_expectations_from_projection(fcx, proj_predicate)
-                                  }
-                                  _ => {
-                                      None
-                                  }
-                              }
-                          }
-                          _ => {
-                              None
-                          }
-                      }
-                  })
-                  .next()
+    let expected_sig_and_kind =
+        fulfillment_cx
+        .pending_obligations()
+        .iter()
+        .filter_map(|obligation| {
+            debug!("deduce_expectations_from_obligations: obligation.predicate={}",
+                   obligation.predicate.repr(fcx.tcx()));
+
+            match obligation.predicate {
+                // Given a Projection predicate, we can potentially infer
+                // the complete signature.
+                ty::Predicate::Projection(ref proj_predicate) => {
+                    let trait_ref = proj_predicate.to_poly_trait_ref();
+                    self_type_matches_expected_vid(fcx, trait_ref, expected_vid)
+                        .and_then(|_| deduce_expectations_from_projection(fcx, proj_predicate))
+                }
+                _ => {
+                    None
+                }
+            }
+        })
+        .next();
+
+    match expected_sig_and_kind {
+        Some((sig, kind)) => { return (Some(sig), Some(kind)); }
+        None => { }
+    }
+
+    // Even if we can't infer the full signature, we may be able to
+    // infer the kind. This can occur if there is a trait-reference
+    // like `F : Fn<A>`.
+    let expected_kind =
+        fulfillment_cx
+        .pending_obligations()
+        .iter()
+        .filter_map(|obligation| {
+            let opt_trait_ref = match obligation.predicate {
+                ty::Predicate::Projection(ref data) => Some(data.to_poly_trait_ref()),
+                ty::Predicate::Trait(ref data) => Some(data.to_poly_trait_ref()),
+                ty::Predicate::Equate(..) => None,
+                ty::Predicate::RegionOutlives(..) => None,
+                ty::Predicate::TypeOutlives(..) => None,
+            };
+            opt_trait_ref
+                .and_then(|trait_ref| self_type_matches_expected_vid(fcx, trait_ref, expected_vid))
+                .and_then(|trait_ref| fcx.tcx().lang_items.fn_trait_kind(trait_ref.def_id()))
+        })
+        .next();
+
+    (None, expected_kind)
 }
 
 /// Given a projection like "<F as Fn(X)>::Result == Y", we can deduce
@@ -229,3 +241,20 @@ fn deduce_expectations_from_projection<'a,'tcx>(
     return Some((fn_sig, kind));
 }
 
+fn self_type_matches_expected_vid<'a,'tcx>(
+    fcx: &FnCtxt<'a,'tcx>,
+    trait_ref: ty::PolyTraitRef<'tcx>,
+    expected_vid: ty::TyVid)
+    -> Option<ty::PolyTraitRef<'tcx>>
+{
+    let self_ty = fcx.infcx().shallow_resolve(trait_ref.self_ty());
+    debug!("self_type_matches_expected_vid(trait_ref={}, self_ty={})",
+           trait_ref.repr(fcx.tcx()),
+           self_ty.repr(fcx.tcx()));
+    match self_ty.sty {
+        ty::ty_infer(ty::TyVar(v)) if expected_vid == v => Some(trait_ref),
+        _ => None,
+    }
+}
+
+
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..adf15fbf28a8f040708e9e9aaea3b371558fdd9a 100644 (file)
@@ -3736,8 +3736,8 @@ fn check_struct_fields_on_error<'a,'tcx>(fcx: &FnCtxt<'a,'tcx>,
       ast::ExprMatch(ref discrim, ref arms, match_src) => {
         _match::check_match(fcx, expr, &**discrim, arms.as_slice(), expected, match_src);
       }
-      ast::ExprClosure(capture, opt_kind, ref decl, ref body) => {
-          closure::check_expr_closure(fcx, expr, capture, opt_kind, &**decl, &**body, expected);
+      ast::ExprClosure(capture, ref decl, ref body) => {
+          closure::check_expr_closure(fcx, expr, capture, &**decl, &**body, expected);
       }
       ast::ExprBlock(ref b) => {
         check_block_with_expected(fcx, &**b, expected);
@@ -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..9df0403794d7c8e8bd03087dda0a33a387ab2a47 100644 (file)
@@ -638,7 +638,7 @@ fn visit_expr(rcx: &mut Rcx, expr: &ast::Expr) {
             visit::walk_expr(rcx, expr);
         }
 
-        ast::ExprClosure(_, _, _, ref body) => {
+        ast::ExprClosure(_, _, ref body) => {
             check_expr_fn_block(rcx, expr, &**body);
         }
 
@@ -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 b52e01f9a7a7684dd39b362ccac0d3c91aaeb7b6..f452c8488ce1c7eb2fe900db03205d06889460ac 100644 (file)
@@ -83,7 +83,7 @@ struct SeedBorrowKind<'a,'tcx:'a> {
 impl<'a, 'tcx, 'v> Visitor<'v> for SeedBorrowKind<'a, 'tcx> {
     fn visit_expr(&mut self, expr: &ast::Expr) {
         match expr.node {
-            ast::ExprClosure(cc, _, _, ref body) => {
+            ast::ExprClosure(cc, _, ref body) => {
                 self.check_closure(expr, cc, &**body);
             }
 
index 52b1eb490cc257c23204268dc6f581b41bbeff28..f047a36c56095fcc3433b872c2edb9480f1addb7 100644 (file)
@@ -118,7 +118,7 @@ fn visit_expr(&mut self, e: &ast::Expr) {
                                     MethodCall::expr(e.id));
 
         match e.node {
-            ast::ExprClosure(_, _, ref decl, _) => {
+            ast::ExprClosure(_, ref decl, _) => {
                 for input in &decl.inputs {
                     let _ = self.visit_node_id(ResolvingExpr(e.span),
                                                input.id);
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..63270610472485cc708a04200fd758aa3f180919 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%.
@@ -1592,6 +1593,7 @@ pub struct RandomState {
 impl RandomState {
     /// Construct a new `RandomState` that is initialized with random keys.
     #[inline]
+    #[allow(deprecated)]
     pub fn new() -> RandomState {
         let mut r = rand::thread_rng();
         RandomState { k0: r.gen(), k1: r.gen() }
@@ -1622,6 +1624,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};
diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs
new file mode 100644 (file)
index 0000000..2fd6631
--- /dev/null
@@ -0,0 +1,676 @@
+// 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.
+//
+// ignore-lexer-test FIXME #15883
+
+//! Buffering wrappers for I/O traits
+
+use prelude::v1::*;
+use io::prelude::*;
+
+use cmp;
+use error::Error as StdError;
+use error::FromError;
+use fmt;
+use io::{self, Cursor, DEFAULT_BUF_SIZE, Error, ErrorKind};
+use ptr;
+
+/// Wraps a `Read` and buffers input from it
+///
+/// It can be excessively inefficient to work directly with a `Read` instance.
+/// For example, every call to `read` on `TcpStream` results in a system call.
+/// A `BufReader` performs large, infrequent reads on the underlying `Read`
+/// and maintains an in-memory buffer of the results.
+pub struct BufReader<R> {
+    inner: R,
+    buf: Cursor<Vec<u8>>,
+}
+
+impl<R: Read> BufReader<R> {
+    /// Creates a new `BufReader` with a default buffer capacity
+    pub fn new(inner: R) -> BufReader<R> {
+        BufReader::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufReader` with the specified buffer capacity
+    pub fn with_capacity(cap: usize, inner: R) -> BufReader<R> {
+        BufReader {
+            inner: inner,
+            buf: Cursor::new(Vec::with_capacity(cap)),
+        }
+    }
+
+    /// Gets a reference to the underlying reader.
+    pub fn get_ref<'a>(&self) -> &R { &self.inner }
+
+    /// Gets a mutable reference to the underlying reader.
+    ///
+    /// # Warning
+    ///
+    /// It is inadvisable to directly read from the underlying reader.
+    pub fn get_mut(&mut self) -> &mut R { &mut self.inner }
+
+    /// Unwraps this `BufReader`, returning the underlying reader.
+    ///
+    /// Note that any leftover data in the internal buffer is lost.
+    pub fn into_inner(self) -> R { self.inner }
+}
+
+impl<R: Read> Read for BufReader<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        // If we don't have any buffered data and we're doing a massive read
+        // (larger than our internal buffer), bypass our internal buffer
+        // entirely.
+        if self.buf.get_ref().len() == self.buf.position() as usize &&
+            buf.len() >= self.buf.get_ref().capacity() {
+            return self.inner.read(buf);
+        }
+        try!(self.fill_buf());
+        self.buf.read(buf)
+    }
+}
+
+impl<R: Read> BufRead for BufReader<R> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> {
+        // If we've reached the end of our internal buffer then we need to fetch
+        // some more data from the underlying reader.
+        if self.buf.position() as usize == self.buf.get_ref().len() {
+            self.buf.set_position(0);
+            let v = self.buf.get_mut();
+            v.truncate(0);
+            let inner = &mut self.inner;
+            try!(super::with_end_to_cap(v, |b| inner.read(b)));
+        }
+        self.buf.fill_buf()
+    }
+
+    fn consume(&mut self, amt: uint) {
+        self.buf.consume(amt)
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<R> fmt::Debug for BufReader<R> where R: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "BufReader {{ reader: {:?}, buffer: {}/{} }}",
+               self.inner, self.buf.position(), self.buf.get_ref().len())
+    }
+}
+
+/// Wraps a Writer and buffers output to it
+///
+/// It can be excessively inefficient to work directly with a `Write`. For
+/// example, every call to `write` on `TcpStream` results in a system call. A
+/// `BufWriter` keeps an in memory buffer of data and writes it to the
+/// underlying `Write` in large, infrequent batches.
+///
+/// This writer will be flushed when it is dropped.
+pub struct BufWriter<W> {
+    inner: Option<W>,
+    buf: Vec<u8>,
+}
+
+/// An error returned by `into_inner` which indicates whether a flush error
+/// happened or not.
+#[derive(Debug)]
+pub struct IntoInnerError<W>(W, Error);
+
+impl<W: Write> BufWriter<W> {
+    /// Creates a new `BufWriter` with a default buffer capacity
+    pub fn new(inner: W) -> BufWriter<W> {
+        BufWriter::with_capacity(DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Creates a new `BufWriter` with the specified buffer capacity
+    pub fn with_capacity(cap: usize, inner: W) -> BufWriter<W> {
+        BufWriter {
+            inner: Some(inner),
+            buf: Vec::with_capacity(cap),
+        }
+    }
+
+    fn flush_buf(&mut self) -> io::Result<()> {
+        let mut written = 0;
+        let len = self.buf.len();
+        let mut ret = Ok(());
+        while written < len {
+            match self.inner.as_mut().unwrap().write(&self.buf[written..]) {
+                Ok(0) => {
+                    ret = Err(Error::new(ErrorKind::WriteZero,
+                                         "failed to flush", None));
+                    break;
+                }
+                Ok(n) => written += n,
+                Err(e) => { ret = Err(e); break }
+
+            }
+        }
+        if written > 0 {
+            // NB: would be better expressed as .remove(0..n) if it existed
+            unsafe {
+                ptr::copy_memory(self.buf.as_mut_ptr(),
+                                 self.buf.as_ptr().offset(written as isize),
+                                 len - written);
+            }
+        }
+        self.buf.truncate(len - written);
+        ret
+    }
+
+    /// Gets a reference to the underlying writer.
+    pub fn get_ref(&self) -> &W { self.inner.as_ref().unwrap() }
+
+    /// Gets a mutable reference to the underlying write.
+    ///
+    /// # Warning
+    ///
+    /// It is inadvisable to directly read from the underlying writer.
+    pub fn get_mut(&mut self) -> &mut W { self.inner.as_mut().unwrap() }
+
+    /// Unwraps this `BufWriter`, returning the underlying writer.
+    ///
+    /// The buffer is flushed before returning the writer.
+    pub fn into_inner(mut self) -> Result<W, IntoInnerError<BufWriter<W>>> {
+        match self.flush_buf() {
+            Err(e) => Err(IntoInnerError(self, e)),
+            Ok(()) => Ok(self.inner.take().unwrap())
+        }
+    }
+}
+
+impl<W: Write> Write for BufWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        if self.buf.len() + buf.len() > self.buf.capacity() {
+            try!(self.flush_buf());
+        }
+        if buf.len() >= self.buf.capacity() {
+            self.inner.as_mut().unwrap().write(buf)
+        } else {
+            let amt = cmp::min(buf.len(), self.buf.capacity());
+            Write::write(&mut self.buf, &buf[..amt])
+        }
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        self.flush_buf().and_then(|()| self.get_mut().flush())
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> fmt::Debug for BufWriter<W> where W: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "BufWriter {{ writer: {:?}, buffer: {}/{} }}",
+               self.inner.as_ref().unwrap(), self.buf.len(), self.buf.capacity())
+    }
+}
+
+#[unsafe_destructor]
+impl<W: Write> Drop for BufWriter<W> {
+    fn drop(&mut self) {
+        if self.inner.is_some() {
+            // dtors should not panic, so we ignore a failed flush
+            let _r = self.flush_buf();
+        }
+    }
+}
+
+impl<W> IntoInnerError<W> {
+    /// Returns the error which caused the call to `into_inner` to fail.
+    ///
+    /// This error was returned when attempting to flush the internal buffer.
+    pub fn error(&self) -> &Error { &self.1 }
+
+    /// Returns the underlying `BufWriter` instance which generated the error.
+    ///
+    /// The returned object can be used to retry a flush or re-inspect the
+    /// buffer.
+    pub fn into_inner(self) -> W { self.0 }
+}
+
+impl<W> FromError<IntoInnerError<W>> for Error {
+    fn from_error(iie: IntoInnerError<W>) -> Error { iie.1 }
+}
+
+impl<W> StdError for IntoInnerError<W> {
+    fn description(&self) -> &str { self.error().description() }
+}
+
+impl<W> fmt::Display for IntoInnerError<W> {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        self.error().fmt(f)
+    }
+}
+
+/// Wraps a Writer and buffers output to it, flushing whenever a newline
+/// (`0x0a`, `'\n'`) is detected.
+///
+/// This writer will be flushed when it is dropped.
+pub struct LineWriter<W> {
+    inner: BufWriter<W>,
+}
+
+impl<W: Write> LineWriter<W> {
+    /// Creates a new `LineWriter`
+    pub fn new(inner: W) -> LineWriter<W> {
+        // Lines typically aren't that long, don't use a giant buffer
+        LineWriter { inner: BufWriter::with_capacity(1024, inner) }
+    }
+
+    /// Gets a reference to the underlying writer.
+    ///
+    /// This type does not expose the ability to get a mutable reference to the
+    /// underlying reader because that could possibly corrupt the buffer.
+    pub fn get_ref<'a>(&'a self) -> &'a W { self.inner.get_ref() }
+
+    /// Unwraps this `LineWriter`, returning the underlying writer.
+    ///
+    /// The internal buffer is flushed before returning the writer.
+    pub fn into_inner(self) -> Result<W, IntoInnerError<LineWriter<W>>> {
+        self.inner.into_inner().map_err(|IntoInnerError(buf, e)| {
+            IntoInnerError(LineWriter { inner: buf }, e)
+        })
+    }
+}
+
+impl<W: Write> Write for LineWriter<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        match buf.rposition_elem(&b'\n') {
+            Some(i) => {
+                let n = try!(self.inner.write(&buf[..i + 1]));
+                if n != i + 1 { return Ok(n) }
+                try!(self.inner.flush());
+                self.inner.write(&buf[i + 1..]).map(|i| n + i)
+            }
+            None => self.inner.write(buf),
+        }
+    }
+
+    fn flush(&mut self) -> io::Result<()> { self.inner.flush() }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<W> fmt::Debug for LineWriter<W> where W: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        write!(fmt, "LineWriter {{ writer: {:?}, buffer: {}/{} }}",
+               self.inner.inner, self.inner.buf.len(),
+               self.inner.buf.capacity())
+    }
+}
+
+struct InternalBufWriter<W>(BufWriter<W>);
+
+impl<W> InternalBufWriter<W> {
+    fn get_mut(&mut self) -> &mut BufWriter<W> {
+        let InternalBufWriter(ref mut w) = *self;
+        return w;
+    }
+}
+
+impl<W: Read> Read for InternalBufWriter<W> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.get_mut().inner.as_mut().unwrap().read(buf)
+    }
+}
+
+/// Wraps a Stream and buffers input and output to and from it.
+///
+/// It can be excessively inefficient to work directly with a `Stream`. For
+/// example, every call to `read` or `write` on `TcpStream` results in a system
+/// call. A `BufStream` keeps in memory buffers of data, making large,
+/// infrequent calls to `read` and `write` on the underlying `Stream`.
+///
+/// The output half will be flushed when this stream is dropped.
+pub struct BufStream<S> {
+    inner: BufReader<InternalBufWriter<S>>
+}
+
+impl<S: Read + Write> BufStream<S> {
+    /// Creates a new buffered stream with explicitly listed capacities for the
+    /// reader/writer buffer.
+    pub fn with_capacities(reader_cap: usize, writer_cap: usize, inner: S)
+                           -> BufStream<S> {
+        let writer = BufWriter::with_capacity(writer_cap, inner);
+        let internal_writer = InternalBufWriter(writer);
+        let reader = BufReader::with_capacity(reader_cap, internal_writer);
+        BufStream { inner: reader }
+    }
+
+    /// Creates a new buffered stream with the default reader/writer buffer
+    /// capacities.
+    pub fn new(inner: S) -> BufStream<S> {
+        BufStream::with_capacities(DEFAULT_BUF_SIZE, DEFAULT_BUF_SIZE, inner)
+    }
+
+    /// Gets a reference to the underlying stream.
+    pub fn get_ref(&self) -> &S {
+        let InternalBufWriter(ref w) = self.inner.inner;
+        w.get_ref()
+    }
+
+    /// Gets a mutable reference to the underlying stream.
+    ///
+    /// # Warning
+    ///
+    /// It is inadvisable to read directly from or write directly to the
+    /// underlying stream.
+    pub fn get_mut(&mut self) -> &mut S {
+        let InternalBufWriter(ref mut w) = self.inner.inner;
+        w.get_mut()
+    }
+
+    /// Unwraps this `BufStream`, returning the underlying stream.
+    ///
+    /// The internal buffer is flushed before returning the stream. Any leftover
+    /// data in the read buffer is lost.
+    pub fn into_inner(self) -> Result<S, IntoInnerError<BufStream<S>>> {
+        let BufReader { inner: InternalBufWriter(w), buf } = self.inner;
+        w.into_inner().map_err(|IntoInnerError(w, e)| {
+            IntoInnerError(BufStream {
+                inner: BufReader { inner: InternalBufWriter(w), buf: buf },
+            }, e)
+        })
+    }
+}
+
+impl<S: Read + Write> BufRead for BufStream<S> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { self.inner.fill_buf() }
+    fn consume(&mut self, amt: uint) { self.inner.consume(amt) }
+}
+
+impl<S: Read + Write> Read for BufStream<S> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        self.inner.read(buf)
+    }
+}
+
+impl<S: Read + Write> Write for BufStream<S> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.inner.inner.get_mut().write(buf)
+    }
+    fn flush(&mut self) -> io::Result<()> {
+        self.inner.inner.get_mut().flush()
+    }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl<S> fmt::Debug for BufStream<S> where S: fmt::Debug {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        let reader = &self.inner;
+        let writer = &self.inner.inner.0;
+        write!(fmt, "BufStream {{ stream: {:?}, write_buffer: {}/{}, read_buffer: {}/{} }}",
+               writer.inner,
+               writer.buf.len(), writer.buf.capacity(),
+               reader.buf.position(), reader.buf.get_ref().len())
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+    use io::prelude::*;
+    use io::{self, BufReader, BufWriter, BufStream, Cursor, LineWriter};
+    use test;
+
+    /// A dummy reader intended at testing short-reads propagation.
+    pub struct ShortReader {
+        lengths: Vec<usize>,
+    }
+
+    impl Read for ShortReader {
+        fn read(&mut self, _: &mut [u8]) -> io::Result<usize> {
+            if self.lengths.is_empty() {
+                Ok(0)
+            } else {
+                Ok(self.lengths.remove(0))
+            }
+        }
+    }
+
+    #[test]
+    fn test_buffered_reader() {
+        let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4];
+        let mut reader = BufReader::with_capacity(2, inner);
+
+        let mut buf = [0, 0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(Ok(3), nread);
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(buf, b);
+
+        let mut buf = [0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(Ok(2), nread);
+        let b: &[_] = &[0, 1];
+        assert_eq!(buf, b);
+
+        let mut buf = [0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(Ok(1), nread);
+        let b: &[_] = &[2];
+        assert_eq!(buf, b);
+
+        let mut buf = [0, 0, 0];
+        let nread = reader.read(&mut buf);
+        assert_eq!(Ok(1), nread);
+        let b: &[_] = &[3, 0, 0];
+        assert_eq!(buf, b);
+
+        let nread = reader.read(&mut buf);
+        assert_eq!(Ok(1), nread);
+        let b: &[_] = &[4, 0, 0];
+        assert_eq!(buf, b);
+
+        assert_eq!(reader.read(&mut buf), Ok(0));
+    }
+
+    #[test]
+    fn test_buffered_writer() {
+        let inner = Vec::new();
+        let mut writer = BufWriter::with_capacity(2, inner);
+
+        writer.write(&[0, 1]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.write(&[2]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.write(&[3]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+        writer.write(&[4]).unwrap();
+        writer.write(&[5]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3]);
+
+        writer.write(&[6]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]);
+
+        writer.write(&[7, 8]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]);
+
+        writer.write(&[9, 10, 11]).unwrap();
+        let a: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]);
+    }
+
+    #[test]
+    fn test_buffered_writer_inner_flushes() {
+        let mut w = BufWriter::with_capacity(3, Vec::new());
+        w.write(&[0, 1]).unwrap();
+        assert_eq!(*w.get_ref(), []);
+        let w = w.into_inner().unwrap();
+        assert_eq!(w, [0, 1]);
+    }
+
+    // This is just here to make sure that we don't infinite loop in the
+    // newtype struct autoderef weirdness
+    #[test]
+    fn test_buffered_stream() {
+        struct S;
+
+        impl Write for S {
+            fn write(&mut self, b: &[u8]) -> io::Result<usize> { Ok(b.len()) }
+            fn flush(&mut self) -> io::Result<()> { Ok(()) }
+        }
+
+        impl Read for S {
+            fn read(&mut self, _: &mut [u8]) -> io::Result<usize> { Ok(0) }
+        }
+
+        let mut stream = BufStream::new(S);
+        assert_eq!(stream.read(&mut [0; 10]), Ok(0));
+        stream.write(&[0; 10]).unwrap();
+        stream.flush().unwrap();
+    }
+
+    #[test]
+    fn test_read_until() {
+        let inner: &[u8] = &[0, 1, 2, 1, 0];
+        let mut reader = BufReader::with_capacity(2, inner);
+        let mut v = Vec::new();
+        reader.read_until(0, &mut v).unwrap();
+        assert_eq!(v, [0]);
+        v.truncate(0);
+        reader.read_until(2, &mut v).unwrap();
+        assert_eq!(v, [1, 2]);
+        v.truncate(0);
+        reader.read_until(1, &mut v).unwrap();
+        assert_eq!(v, [1]);
+        v.truncate(0);
+        reader.read_until(8, &mut v).unwrap();
+        assert_eq!(v, [0]);
+        v.truncate(0);
+        reader.read_until(9, &mut v).unwrap();
+        assert_eq!(v, []);
+    }
+
+    #[test]
+    fn test_line_buffer() {
+        let mut writer = LineWriter::new(Vec::new());
+        writer.write(&[0]).unwrap();
+        assert_eq!(*writer.get_ref(), []);
+        writer.write(&[1]).unwrap();
+        assert_eq!(*writer.get_ref(), []);
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1]);
+        writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']);
+        writer.flush().unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]);
+        writer.write(&[3, b'\n']).unwrap();
+        assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']);
+    }
+
+    #[test]
+    fn test_read_line() {
+        let in_buf = b"a\nb\nc";
+        let mut reader = BufReader::with_capacity(2, in_buf);
+        let mut s = String::new();
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "a\n");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "b\n");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "c");
+        s.truncate(0);
+        reader.read_line(&mut s).unwrap();
+        assert_eq!(s, "");
+    }
+
+    #[test]
+    fn test_lines() {
+        let in_buf = b"a\nb\nc";
+        let mut reader = BufReader::with_capacity(2, in_buf);
+        let mut it = reader.lines();
+        assert_eq!(it.next(), Some(Ok("a".to_string())));
+        assert_eq!(it.next(), Some(Ok("b".to_string())));
+        assert_eq!(it.next(), Some(Ok("c".to_string())));
+        assert_eq!(it.next(), None);
+    }
+
+    #[test]
+    fn test_short_reads() {
+        let inner = ShortReader{lengths: vec![0, 1, 2, 0, 1, 0]};
+        let mut reader = BufReader::new(inner);
+        let mut buf = [0, 0];
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        assert_eq!(reader.read(&mut buf), Ok(1));
+        assert_eq!(reader.read(&mut buf), Ok(2));
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        assert_eq!(reader.read(&mut buf), Ok(1));
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        assert_eq!(reader.read(&mut buf), Ok(0));
+    }
+
+    #[test]
+    fn read_char_buffered() {
+        let buf = [195u8, 159u8];
+        let mut reader = BufReader::with_capacity(1, &buf[]);
+        assert_eq!(reader.chars().next(), Some(Ok('ß')));
+    }
+
+    #[test]
+    fn test_chars() {
+        let buf = [195u8, 159u8, b'a'];
+        let mut reader = BufReader::with_capacity(1, &buf[]);
+        let mut it = reader.chars();
+        assert_eq!(it.next(), Some(Ok('ß')));
+        assert_eq!(it.next(), Some(Ok('a')));
+        assert_eq!(it.next(), None);
+    }
+
+    #[test]
+    #[should_fail]
+    fn dont_panic_in_drop_on_panicked_flush() {
+        struct FailFlushWriter;
+
+        impl Write for FailFlushWriter {
+            fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+            fn flush(&mut self) -> io::Result<()> {
+                Err(io::Error::last_os_error())
+            }
+        }
+
+        let writer = FailFlushWriter;
+        let _writer = BufWriter::new(writer);
+
+        // If writer panics *again* due to the flush error then the process will
+        // abort.
+        panic!();
+    }
+
+    #[bench]
+    fn bench_buffered_reader(b: &mut test::Bencher) {
+        b.iter(|| {
+            BufReader::new(io::empty())
+        });
+    }
+
+    #[bench]
+    fn bench_buffered_writer(b: &mut test::Bencher) {
+        b.iter(|| {
+            BufWriter::new(io::sink())
+        });
+    }
+
+    #[bench]
+    fn bench_buffered_stream(b: &mut test::Bencher) {
+        let mut buf = Cursor::new(Vec::new());
+        b.iter(|| {
+            BufStream::new(&mut buf);
+        });
+    }
+}
diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs
new file mode 100644 (file)
index 0000000..9f3655d
--- /dev/null
@@ -0,0 +1,408 @@
+// 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.
+
+#![allow(missing_copy_implementations)]
+
+use prelude::v1::*;
+use io::prelude::*;
+
+use cmp;
+use io::{self, SeekFrom, Error, ErrorKind};
+use iter::repeat;
+use num::Int;
+use slice;
+
+/// A `Cursor` is a type which wraps another I/O object to provide a `Seek`
+/// implementation.
+///
+/// Cursors are currently typically used with memory buffer objects in order to
+/// allow `Seek` plus `Read` and `Write` implementations. For example, common
+/// cursor types include:
+///
+/// * `Cursor<Vec<u8>>`
+/// * `Cursor<&[u8]>`
+///
+/// Implementations of the I/O traits for `Cursor<T>` are not currently generic
+/// over `T` itself. Instead, specific implementations are provided for various
+/// in-memory buffer types like `Vec<u8>` and `&[u8]`.
+pub struct Cursor<T> {
+    inner: T,
+    pos: u64,
+}
+
+impl<T> Cursor<T> {
+    /// Create a new cursor wrapping the provided underlying I/O object.
+    pub fn new(inner: T) -> Cursor<T> {
+        Cursor { pos: 0, inner: inner }
+    }
+
+    /// Consume this cursor, returning the underlying value.
+    pub fn into_inner(self) -> T { self.inner }
+
+    /// Get a reference to the underlying value in this cursor.
+    pub fn get_ref(&self) -> &T { &self.inner }
+
+    /// Get a mutable reference to the underlying value in this cursor.
+    ///
+    /// Care should be taken to avoid modifying the internal I/O state of the
+    /// underlying value as it may corrupt this cursor's position.
+    pub fn get_mut(&mut self) -> &mut T { &mut self.inner }
+
+    /// Returns the current value of this cursor
+    pub fn position(&self) -> u64 { self.pos }
+
+    /// Sets the value of this cursor
+    pub fn set_position(&mut self, pos: u64) { self.pos = pos; }
+}
+
+macro_rules! seek {
+    () => {
+        fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
+            let pos = match style {
+                SeekFrom::Start(n) => { self.pos = n; return Ok(n) }
+                SeekFrom::End(n) => self.inner.len() as i64 + n,
+                SeekFrom::Current(n) => self.pos as i64 + n,
+            };
+
+            if pos < 0 {
+                Err(Error::new(ErrorKind::InvalidInput,
+                               "invalid seek to a negative position",
+                               None))
+            } else {
+                self.pos = pos as u64;
+                Ok(self.pos)
+            }
+        }
+    }
+}
+
+impl<'a> io::Seek for Cursor<&'a [u8]> { seek!(); }
+impl<'a> io::Seek for Cursor<&'a mut [u8]> { seek!(); }
+impl io::Seek for Cursor<Vec<u8>> { seek!(); }
+
+macro_rules! read {
+    () => {
+        fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+            let n = try!(Read::read(&mut try!(self.fill_buf()), buf));
+            self.pos += n as u64;
+            Ok(n)
+        }
+    }
+}
+
+impl<'a> Read for Cursor<&'a [u8]> { read!(); }
+impl<'a> Read for Cursor<&'a mut [u8]> { read!(); }
+impl Read for Cursor<Vec<u8>> { read!(); }
+
+macro_rules! buffer {
+    () => {
+        fn fill_buf(&mut self) -> io::Result<&[u8]> {
+            let amt = cmp::min(self.pos, self.inner.len() as u64);
+            Ok(&self.inner[(amt as usize)..])
+        }
+        fn consume(&mut self, amt: usize) { self.pos += amt as u64; }
+    }
+}
+
+impl<'a> BufRead for Cursor<&'a [u8]> { buffer!(); }
+impl<'a> BufRead for Cursor<&'a mut [u8]> { buffer!(); }
+impl<'a> BufRead for Cursor<Vec<u8>> { buffer!(); }
+
+impl<'a> Write for Cursor<&'a mut [u8]> {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        let pos = cmp::min(self.pos, self.inner.len() as u64);
+        let amt = try!((&mut self.inner[(pos as usize)..]).write(data));
+        self.pos += amt as u64;
+        Ok(amt)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl Write for Cursor<Vec<u8>> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        // Make sure the internal buffer is as least as big as where we
+        // currently are
+        let pos = self.position();
+        let amt = pos.saturating_sub(self.inner.len() as u64);
+        self.inner.extend(repeat(0).take(amt as usize));
+
+        // Figure out what bytes will be used to overwrite what's currently
+        // there (left), and what will be appended on the end (right)
+        let space = self.inner.len() - pos as usize;
+        let (left, right) = buf.split_at(cmp::min(space, buf.len()));
+        slice::bytes::copy_memory(&mut self.inner[(pos as usize)..], left);
+        self.inner.push_all(right);
+
+        // Bump us forward
+        self.set_position(pos + buf.len() as u64);
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+
+#[cfg(test)]
+mod tests {
+    use core::prelude::*;
+
+    use io::prelude::*;
+    use io::{Cursor, SeekFrom};
+    use vec::Vec;
+
+    #[test]
+    fn test_vec_writer() {
+        let mut writer = Vec::new();
+        assert_eq!(writer.write(&[0]), Ok(1));
+        assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
+        assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(writer, b);
+    }
+
+    #[test]
+    fn test_mem_writer() {
+        let mut writer = Cursor::new(Vec::new());
+        assert_eq!(writer.write(&[0]), Ok(1));
+        assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
+        assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[], b);
+    }
+
+    #[test]
+    fn test_buf_writer() {
+        let mut buf = [0 as u8; 9];
+        {
+            let mut writer = Cursor::new(&mut buf[]);
+            assert_eq!(writer.position(), 0);
+            assert_eq!(writer.write(&[0]), Ok(1));
+            assert_eq!(writer.position(), 1);
+            assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
+            assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+            assert_eq!(writer.position(), 8);
+            assert_eq!(writer.write(&[]), Ok(0));
+            assert_eq!(writer.position(), 8);
+
+            assert_eq!(writer.write(&[8, 9]), Ok(1));
+            assert_eq!(writer.write(&[10]), Ok(0));
+        }
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
+        assert_eq!(buf, b);
+    }
+
+    #[test]
+    fn test_buf_writer_seek() {
+        let mut buf = [0 as u8; 8];
+        {
+            let mut writer = Cursor::new(&mut buf[]);
+            assert_eq!(writer.position(), 0);
+            assert_eq!(writer.write(&[1]), Ok(1));
+            assert_eq!(writer.position(), 1);
+
+            assert_eq!(writer.seek(SeekFrom::Start(2)), Ok(2));
+            assert_eq!(writer.position(), 2);
+            assert_eq!(writer.write(&[2]), Ok(1));
+            assert_eq!(writer.position(), 3);
+
+            assert_eq!(writer.seek(SeekFrom::Current(-2)), Ok(1));
+            assert_eq!(writer.position(), 1);
+            assert_eq!(writer.write(&[3]), Ok(1));
+            assert_eq!(writer.position(), 2);
+
+            assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
+            assert_eq!(writer.position(), 7);
+            assert_eq!(writer.write(&[4]), Ok(1));
+            assert_eq!(writer.position(), 8);
+
+        }
+        let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4];
+        assert_eq!(buf, b);
+    }
+
+    #[test]
+    fn test_buf_writer_error() {
+        let mut buf = [0 as u8; 2];
+        let mut writer = Cursor::new(&mut buf[]);
+        assert_eq!(writer.write(&[0]), Ok(1));
+        assert_eq!(writer.write(&[0, 0]), Ok(1));
+        assert_eq!(writer.write(&[0, 0]), Ok(0));
+    }
+
+    #[test]
+    fn test_mem_reader() {
+        let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7));
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        assert_eq!(reader.position(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf), Ok(1));
+        assert_eq!(reader.position(), 1);
+        let b: &[_] = &[0];
+        assert_eq!(buf, b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf), Ok(4));
+        assert_eq!(reader.position(), 5);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf, b);
+        assert_eq!(reader.read(&mut buf), Ok(3));
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf), Ok(0));
+    }
+
+    #[test]
+    fn read_to_end() {
+        let mut reader = Cursor::new(vec!(0u8, 1, 2, 3, 4, 5, 6, 7));
+        let mut v = Vec::new();
+        reader.read_to_end(&mut v).ok().unwrap();
+        assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]);
+    }
+
+    #[test]
+    fn test_slice_reader() {
+        let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
+        let mut reader = &mut in_buf.as_slice();
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf), Ok(1));
+        assert_eq!(reader.len(), 7);
+        let b: &[_] = &[0];
+        assert_eq!(buf.as_slice(), b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf), Ok(4));
+        assert_eq!(reader.len(), 3);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf.as_slice(), b);
+        assert_eq!(reader.read(&mut buf), Ok(3));
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf), Ok(0));
+    }
+
+    #[test]
+    fn test_buf_reader() {
+        let in_buf = vec![0u8, 1, 2, 3, 4, 5, 6, 7];
+        let mut reader = Cursor::new(in_buf.as_slice());
+        let mut buf = [];
+        assert_eq!(reader.read(&mut buf), Ok(0));
+        assert_eq!(reader.position(), 0);
+        let mut buf = [0];
+        assert_eq!(reader.read(&mut buf), Ok(1));
+        assert_eq!(reader.position(), 1);
+        let b: &[_] = &[0];
+        assert_eq!(buf, b);
+        let mut buf = [0; 4];
+        assert_eq!(reader.read(&mut buf), Ok(4));
+        assert_eq!(reader.position(), 5);
+        let b: &[_] = &[1, 2, 3, 4];
+        assert_eq!(buf, b);
+        assert_eq!(reader.read(&mut buf), Ok(3));
+        let b: &[_] = &[5, 6, 7];
+        assert_eq!(&buf[..3], b);
+        assert_eq!(reader.read(&mut buf), Ok(0));
+    }
+
+    #[test]
+    fn test_read_char() {
+        let b = b"Vi\xE1\xBB\x87t";
+        let mut c = Cursor::new(b).chars();
+        assert_eq!(c.next(), Some(Ok('V')));
+        assert_eq!(c.next(), Some(Ok('i')));
+        assert_eq!(c.next(), Some(Ok('ệ')));
+        assert_eq!(c.next(), Some(Ok('t')));
+        assert_eq!(c.next(), None);
+    }
+
+    #[test]
+    fn test_read_bad_char() {
+        let b = b"\x80";
+        let mut c = Cursor::new(b).chars();
+        assert!(c.next().unwrap().is_err());
+    }
+
+    #[test]
+    fn seek_past_end() {
+        let buf = [0xff];
+        let mut r = Cursor::new(&buf[]);
+        assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
+        assert_eq!(r.read(&mut [0]), Ok(0));
+
+        let mut r = Cursor::new(vec!(10u8));
+        assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
+        assert_eq!(r.read(&mut [0]), Ok(0));
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[]);
+        assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
+        assert_eq!(r.write(&[3]), Ok(0));
+    }
+
+    #[test]
+    fn seek_before_0() {
+        let buf = [0xff_u8];
+        let mut r = Cursor::new(&buf[]);
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+        let mut r = Cursor::new(vec!(10u8));
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+
+        let mut buf = [0];
+        let mut r = Cursor::new(&mut buf[]);
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+    }
+
+    #[test]
+    fn test_seekable_mem_writer() {
+        let mut writer = Cursor::new(Vec::<u8>::new());
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[0]), Ok(1));
+        assert_eq!(writer.position(), 1);
+        assert_eq!(writer.write(&[1, 2, 3]), Ok(3));
+        assert_eq!(writer.write(&[4, 5, 6, 7]), Ok(4));
+        assert_eq!(writer.position(), 8);
+        let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[], b);
+
+        assert_eq!(writer.seek(SeekFrom::Start(0)), Ok(0));
+        assert_eq!(writer.position(), 0);
+        assert_eq!(writer.write(&[3, 4]), Ok(2));
+        let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[], b);
+
+        assert_eq!(writer.seek(SeekFrom::Current(1)), Ok(3));
+        assert_eq!(writer.write(&[0, 1]), Ok(2));
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7];
+        assert_eq!(&writer.get_ref()[], b);
+
+        assert_eq!(writer.seek(SeekFrom::End(-1)), Ok(7));
+        assert_eq!(writer.write(&[1, 2]), Ok(2));
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2];
+        assert_eq!(&writer.get_ref()[], b);
+
+        assert_eq!(writer.seek(SeekFrom::End(1)), Ok(10));
+        assert_eq!(writer.write(&[1]), Ok(1));
+        let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1];
+        assert_eq!(&writer.get_ref()[], b);
+    }
+
+    #[test]
+    fn vec_seek_past_end() {
+        let mut r = Cursor::new(Vec::new());
+        assert_eq!(r.seek(SeekFrom::Start(10)), Ok(10));
+        assert_eq!(r.write(&[3]), Ok(1));
+    }
+
+    #[test]
+    fn vec_seek_before_0() {
+        let mut r = Cursor::new(Vec::new());
+        assert!(r.seek(SeekFrom::End(-2)).is_err());
+    }
+}
diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs
new file mode 100644 (file)
index 0000000..9f3cd8c
--- /dev/null
@@ -0,0 +1,183 @@
+// 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.
+
+use boxed::Box;
+use clone::Clone;
+use error::Error as StdError;
+use fmt;
+use option::Option::{self, Some, None};
+use result;
+use string::String;
+use sys;
+
+/// A type for results generated by I/O related functions where the `Err` type
+/// is hard-wired to `io::Error`.
+///
+/// This typedef is generally used to avoid writing out `io::Error` directly and
+/// is otherwise a direct mapping to `std::result::Result`.
+pub type Result<T> = result::Result<T, Error>;
+
+/// The error type for I/O operations of the `Read`, `Write`, `Seek`, and
+/// associated traits.
+///
+/// Errors mostly originate from the underlying OS, but custom instances of
+/// `Error` can be created with crafted error messages and a particular value of
+/// `ErrorKind`.
+#[derive(PartialEq, Eq, Clone, Debug)]
+pub struct Error {
+    repr: Repr,
+}
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+enum Repr {
+    Os(i32),
+    Custom(Box<Custom>),
+}
+
+#[derive(PartialEq, Eq, Clone, Debug)]
+struct Custom {
+    kind: ErrorKind,
+    desc: &'static str,
+    detail: Option<String>
+}
+
+/// A list specifying general categories of I/O error.
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+pub enum ErrorKind {
+    /// The file was not found.
+    FileNotFound,
+    /// The file permissions disallowed access to this file.
+    PermissionDenied,
+    /// The connection was refused by the remote server.
+    ConnectionRefused,
+    /// The connection was reset by the remote server.
+    ConnectionReset,
+    /// The connection was aborted (terminated) by the remote server.
+    ConnectionAborted,
+    /// The network operation failed because it was not connected yet.
+    NotConnected,
+    /// The operation failed because a pipe was closed.
+    BrokenPipe,
+    /// A file already existed with that name.
+    PathAlreadyExists,
+    /// No file exists at that location.
+    PathDoesntExist,
+    /// The path did not specify the type of file that this operation required.
+    /// For example, attempting to copy a directory with the `fs::copy()`
+    /// operation will fail with this error.
+    MismatchedFileTypeForOperation,
+    /// The operation temporarily failed (for example, because a signal was
+    /// received), and retrying may succeed.
+    ResourceUnavailable,
+    /// A parameter was incorrect in a way that caused an I/O error not part of
+    /// this list.
+    InvalidInput,
+    /// The I/O operation's timeout expired, causing it to be canceled.
+    TimedOut,
+    /// An error returned when an operation could not be completed because a
+    /// call to `write` returned `Ok(0)`.
+    ///
+    /// This typically means that an operation could only succeed if it wrote a
+    /// particular number of bytes but only a smaller number of bytes could be
+    /// written.
+    WriteZero,
+    /// This operation was interrupted
+    Interrupted,
+    /// Any I/O error not part of this list.
+    Other,
+}
+
+impl Error {
+    /// Creates a new custom error from a specified kind/description/detail.
+    pub fn new(kind: ErrorKind,
+               description: &'static str,
+               detail: Option<String>) -> Error {
+        Error {
+            repr: Repr::Custom(Box::new(Custom {
+                kind: kind,
+                desc: description,
+                detail: detail,
+            }))
+        }
+    }
+
+    /// Returns an error representing the last OS error which occurred.
+    ///
+    /// This function reads the value of `errno` for the target platform (e.g.
+    /// `GetLastError` on Windows) and will return a corresponding instance of
+    /// `Error` for the error code.
+    pub fn last_os_error() -> Error {
+        Error::from_os_error(sys::os::errno() as i32)
+    }
+
+    /// Creates a new instance of an `Error` from a particular OS error code.
+    pub fn from_os_error(code: i32) -> Error {
+        Error { repr: Repr::Os(code) }
+    }
+
+    /// Return the corresponding `ErrorKind` for this error.
+    pub fn kind(&self) -> ErrorKind {
+        match self.repr {
+            Repr::Os(code) => sys::decode_error_kind(code),
+            Repr::Custom(ref c) => c.kind,
+        }
+    }
+
+    /// Returns a short description for this error message
+    pub fn description(&self) -> &str {
+        match self.repr {
+            Repr::Os(..) => "os error",
+            Repr::Custom(ref c) => c.desc,
+        }
+    }
+
+    /// Returns a detailed error message for this error (if one is available)
+    pub fn detail(&self) -> Option<String> {
+        match self.repr {
+            Repr::Os(code) => Some(sys::os::error_string(code)),
+            Repr::Custom(ref s) => s.detail.clone(),
+        }
+    }
+}
+
+impl fmt::Display for Error {
+    fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+        match self.repr {
+            Repr::Os(code) => {
+                let detail = sys::os::error_string(code);
+                write!(fmt, "{} (os error {})", detail, code)
+            }
+            Repr::Custom(ref c) => {
+                match **c {
+                    Custom {
+                        kind: ErrorKind::Other,
+                        desc: "unknown error",
+                        detail: Some(ref detail)
+                    } => {
+                        write!(fmt, "{}", detail)
+                    }
+                    Custom { detail: None, desc, .. } =>
+                        write!(fmt, "{}", desc),
+                    Custom { detail: Some(ref detail), desc, .. } =>
+                        write!(fmt, "{} ({})", desc, detail)
+                }
+            }
+        }
+    }
+}
+
+impl StdError for Error {
+    fn description(&self) -> &str {
+        match self.repr {
+            Repr::Os(..) => "os error",
+            Repr::Custom(ref c) => c.desc,
+        }
+    }
+}
diff --git a/src/libstd/io/impls.rs b/src/libstd/io/impls.rs
new file mode 100644 (file)
index 0000000..7f3ce79
--- /dev/null
@@ -0,0 +1,88 @@
+// 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.
+
+use core::prelude::*;
+
+use boxed::Box;
+use cmp;
+use io::{self, SeekFrom, Read, Write, Seek, BufRead};
+use mem;
+use slice;
+use vec::Vec;
+
+// =============================================================================
+// Forwarding implementations
+
+impl<'a, R: Read + ?Sized> Read for &'a mut R {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) }
+}
+impl<'a, W: Write + ?Sized> Write for &'a mut W {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+}
+impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+}
+
+impl<R: Read + ?Sized> Read for Box<R> {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { (**self).read(buf) }
+}
+impl<W: Write + ?Sized> Write for Box<W> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }
+    fn flush(&mut self) -> io::Result<()> { (**self).flush() }
+}
+impl<S: Seek + ?Sized> Seek for Box<S> {
+    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
+}
+impl<B: BufRead + ?Sized> BufRead for Box<B> {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }
+    fn consume(&mut self, amt: usize) { (**self).consume(amt) }
+}
+
+// =============================================================================
+// In-memory buffer implementations
+
+impl<'a> Read for &'a [u8] {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        let amt = cmp::min(buf.len(), self.len());
+        let (a, b) = self.split_at(amt);
+        slice::bytes::copy_memory(buf, a);
+        *self = b;
+        Ok(amt)
+    }
+}
+
+impl<'a> BufRead for &'a [u8] {
+    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }
+    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
+}
+
+impl<'a> Write for &'a mut [u8] {
+    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+        let amt = cmp::min(data.len(), self.len());
+        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
+        slice::bytes::copy_memory(a, &data[..amt]);
+        *self = b;
+        Ok(amt)
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+impl Write for Vec<u8> {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+        self.push_all(buf);
+        Ok(buf.len())
+    }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs
new file mode 100644 (file)
index 0000000..0832206
--- /dev/null
@@ -0,0 +1,948 @@
+// 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.
+
+//! Traits, helpers, and type definitions for core I/O functionality.
+//!
+//! > **NOTE**: This module is very much a work in progress and is under active
+//! > development. At this time it is still recommended to use the `old_io`
+//! > module while the details of this module shake out.
+
+#![unstable(feature = "io",
+            reason = "this new I/O module is still under active deveopment and \
+                      APIs are subject to tweaks fairly regularly")]
+
+use cmp;
+use unicode::str as core_str;
+use error::Error as StdError;
+use fmt;
+use iter::Iterator;
+use marker::Sized;
+use mem;
+use ops::{Drop, FnOnce};
+use option::Option::{self, Some, None};
+use ptr::PtrExt;
+use result::Result::{Ok, Err};
+use result;
+use slice::{self, SliceExt};
+use string::String;
+use str::{self, StrExt};
+use vec::Vec;
+
+pub use self::buffered::{BufReader, BufWriter, BufStream, LineWriter};
+pub use self::buffered::IntoInnerError;
+pub use self::cursor::Cursor;
+pub use self::error::{Result, Error, ErrorKind};
+pub use self::util::{copy, sink, Sink, empty, Empty, repeat, Repeat};
+
+pub mod prelude;
+mod buffered;
+mod cursor;
+mod error;
+mod impls;
+mod util;
+
+const DEFAULT_BUF_SIZE: usize = 64 * 1024;
+
+// Acquires a slice of the vector `v` from its length to its capacity
+// (uninitialized data), reads into it, and then updates the length.
+//
+// This function is leveraged to efficiently read some bytes into a destination
+// vector without extra copying and taking advantage of the space that's already
+// in `v`.
+//
+// The buffer we're passing down, however, is pointing at uninitialized data
+// (the end of a `Vec`), and many operations will be *much* faster if we don't
+// have to zero it out. In order to prevent LLVM from generating an `undef`
+// value when reads happen from this uninitialized memory, we force LLVM to
+// think it's initialized by sending it through a black box. This should prevent
+// actual undefined behavior after optimizations.
+fn with_end_to_cap<F>(v: &mut Vec<u8>, f: F) -> Result<usize>
+    where F: FnOnce(&mut [u8]) -> Result<usize>
+{
+    unsafe {
+        let n = try!(f({
+            let base = v.as_mut_ptr().offset(v.len() as isize);
+            black_box(slice::from_raw_mut_buf(mem::copy_lifetime(v, &base),
+                                              v.capacity() - v.len()))
+        }));
+
+        // If the closure (typically a `read` implementation) reported that it
+        // read a larger number of bytes than the vector actually has, we need
+        // to be sure to clamp the vector to at most its capacity.
+        let new_len = cmp::min(v.capacity(), v.len() + n);
+        v.set_len(new_len);
+        return Ok(n);
+    }
+
+    // Semi-hack used to prevent LLVM from retaining any assumptions about
+    // `dummy` over this function call
+    unsafe fn black_box<T>(mut dummy: T) -> T {
+        asm!("" :: "r"(&mut dummy) : "memory");
+        dummy
+    }
+}
+
+// A few methods below (read_to_string, read_line) will append data into a
+// `String` buffer, but we need to be pretty careful when doing this. The
+// implementation will just call `.as_mut_vec()` and then delegate to a
+// byte-oriented reading method, but we must ensure that when returning we never
+// leave `buf` in a state such that it contains invalid UTF-8 in its bounds.
+//
+// To this end, we use an RAII guard (to protect against panics) which updates
+// the length of the string when it is dropped. This guard initially truncates
+// the string to the prior length and only afer we've validated that the
+// new contents are valid UTF-8 do we allow it to set a longer length.
+//
+// The unsafety in this function is twofold:
+//
+// 1. We're looking at the raw bytes of `buf`, so we take on the burden of UTF-8
+//    checks.
+// 2. We're passing a raw buffer to the function `f`, and it is expected that
+//    the function only *appends* bytes to the buffer. We'll get undefined
+//    behavior if existing bytes are overwritten to have non-UTF-8 data.
+fn append_to_string<F>(buf: &mut String, f: F) -> Result<()>
+    where F: FnOnce(&mut Vec<u8>) -> Result<()>
+{
+    struct Guard<'a> { s: &'a mut Vec<u8>, len: usize }
+    #[unsafe_destructor]
+    impl<'a> Drop for Guard<'a> {
+        fn drop(&mut self) {
+            unsafe { self.s.set_len(self.len); }
+        }
+    }
+
+    unsafe {
+        let mut g = Guard { len: buf.len(), s: buf.as_mut_vec() };
+        let ret = f(g.s);
+        if str::from_utf8(&g.s[g.len..]).is_err() {
+            ret.and_then(|()| {
+                Err(Error::new(ErrorKind::InvalidInput,
+                               "stream did not contain valid UTF-8", None))
+            })
+        } else {
+            g.len = g.s.len();
+            ret
+        }
+    }
+}
+
+fn read_to_end<R: Read + ?Sized>(r: &mut R, buf: &mut Vec<u8>) -> Result<()> {
+    loop {
+        if buf.capacity() == buf.len() {
+            buf.reserve(DEFAULT_BUF_SIZE);
+        }
+        match with_end_to_cap(buf, |b| r.read(b)) {
+            Ok(0) => return Ok(()),
+            Ok(_) => {}
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+            Err(e) => return Err(e),
+        }
+    }
+}
+
+/// A trait for objects which are byte-oriented sources.
+///
+/// Readers are defined by one method, `read`. Each call to `read` will attempt
+/// to pull bytes from this source into a provided buffer.
+///
+/// Readers are intended to be composable with one another. Many objects
+/// throughout the I/O and related libraries take and provide types which
+/// implement the `Read` trait.
+pub trait Read {
+    /// Pull some bytes from this source into the specified buffer, returning
+    /// how many bytes were read.
+    ///
+    /// This function does not provide any guarantees about whether it blocks
+    /// waiting for data, but if an object needs to block for a read but cannot
+    /// it will typically signal this via an `Err` return value.
+    ///
+    /// If the return value of this method is `Ok(n)`, then it must be
+    /// guaranteed that `0 <= n <= buf.len()`. A nonzero `n` value indicates
+    /// that the buffer `buf` has ben filled in with `n` bytes of data from this
+    /// source. If `n` is `0`, then it can indicate one of two scenarios:
+    ///
+    /// 1. This reader has reached its "end of file" and will likely no longer
+    ///    be able to produce bytes. Note that this does not mean that the
+    ///    reader will *always* no longer be able to produce bytes.
+    /// 2. The buffer specified was 0 bytes in length.
+    ///
+    /// No guarantees are provided about the contents of `buf` when this
+    /// function is called, implementations cannot rely on any property of the
+    /// contents of `buf` being true. It is recommended that implementations
+    /// only write data to `buf` instead of reading its contents.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters any form of I/O or other error, an error
+    /// variant will be returned. If an error is returned then it must be
+    /// guaranteed that no bytes were read.
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
+
+    /// Read all bytes until EOF in this source, placing them into `buf`.
+    ///
+    /// All bytes read from this source will be appended to the specified buffer
+    /// `buf`. This function will return a call to `read` either:
+    ///
+    /// 1. Returns `Ok(0)`.
+    /// 2. Returns an error which is not of the kind `ErrorKind::Interrupted`.
+    ///
+    /// Until one of these conditions is met the function will continuously
+    /// invoke `read` to append more data to `buf`.
+    ///
+    /// # Errors
+    ///
+    /// If this function encounters an error of the kind
+    /// `ErrorKind::Interrupted` then the error is ignored and the operation
+    /// will continue.
+    ///
+    /// If any other read error is encountered then this function immediately
+    /// returns. Any bytes which have already been read will be appended to
+    /// `buf`.
+    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> Result<()> {
+        read_to_end(self, buf)
+    }
+
+    /// Read all bytes until EOF in this source, placing them into `buf`.
+    ///
+    /// # Errors
+    ///
+    /// If the data in this stream is *not* valid UTF-8 then an error is
+    /// returned and `buf` is unchanged.
+    ///
+    /// See `read_to_end` for other error semantics.
+    fn read_to_string(&mut self, buf: &mut String) -> Result<()> {
+        // Note that we do *not* call `.read_to_end()` here. We are passing
+        // `&mut Vec<u8>` (the raw contents of `buf`) into the `read_to_end`
+        // method to fill it up. An arbitrary implementation could overwrite the
+        // entire contents of the vector, not just append to it (which is what
+        // we are expecting).
+        //
+        // To prevent extraneously checking the UTF-8-ness of the entire buffer
+        // we pass it to our hardcoded `read_to_end` implementation which we
+        // know is guaranteed to only read data into the end of the buffer.
+        append_to_string(buf, |b| read_to_end(self, b))
+    }
+}
+
+/// Extension methods for all instances of `Read`, typically imported through
+/// `std::io::prelude::*`.
+pub trait ReadExt: Read + Sized {
+    /// Create a "by reference" adaptor for this instance of `Read`.
+    ///
+    /// The returned adaptor also implements `Read` and will simply borrow this
+    /// current reader.
+    fn by_ref(&mut self) -> &mut Self { self }
+
+    /// Transform this `Read` instance to an `Iterator` over its bytes.
+    ///
+    /// The returned type implements `Iterator` where the `Item` is `Result<u8,
+    /// R::Err>`.  The yielded item is `Ok` if a byte was successfully read and
+    /// `Err` otherwise for I/O errors. EOF is mapped to returning `None` from
+    /// this iterator.
+    fn bytes(self) -> Bytes<Self> {
+        Bytes { inner: self }
+    }
+
+    /// Transform this `Read` instance to an `Iterator` over `char`s.
+    ///
+    /// This adaptor will attempt to interpret this reader as an UTF-8 encoded
+    /// sequence of characters. The returned iterator will return `None` once
+    /// EOF is reached for this reader. Otherwise each element yielded will be a
+    /// `Result<char, E>` where `E` may contain information about what I/O error
+    /// occurred or where decoding failed.
+    ///
+    /// Currently this adaptor will discard intermediate data read, and should
+    /// be avoided if this is not desired.
+    fn chars(self) -> Chars<Self> {
+        Chars { inner: self }
+    }
+
+    /// Create an adaptor which will chain this stream with another.
+    ///
+    /// The returned `Read` instance will first read all bytes from this object
+    /// until EOF is encountered. Afterwards the output is equivalent to the
+    /// output of `next`.
+    fn chain<R: Read>(self, next: R) -> Chain<Self, R> {
+        Chain { first: self, second: next, done_first: false }
+    }
+
+    /// Create an adaptor which will read at most `limit` bytes from it.
+    ///
+    /// This function returns a new instance of `Read` which will read at most
+    /// `limit` bytes, after which it will always return EOF (`Ok(0)`). Any
+    /// read errors will not count towards the number of bytes read and future
+    /// calls to `read` may succeed.
+    fn take(self, limit: u64) -> Take<Self> {
+        Take { inner: self, limit: limit }
+    }
+
+    /// Creates a reader adaptor which will write all read data into the given
+    /// output stream.
+    ///
+    /// Whenever the returned `Read` instance is read it will write the read
+    /// data to `out`. The current semantics of this implementation imply that
+    /// a `write` error will not report how much data was initially read.
+    fn tee<W: Write>(self, out: W) -> Tee<Self, W> {
+        Tee { reader: self, writer: out }
+    }
+}
+
+impl<T: Read> ReadExt for T {}
+
+/// A trait for objects which are byte-oriented sinks.
+///
+/// The `write` method will attempt to write some data into the object,
+/// returning how many bytes were successfully written.
+///
+/// The `flush` method is useful for adaptors and explicit buffers themselves
+/// for ensuring that all buffered data has been pushed out to the "true sink".
+///
+/// Writers are intended to be composable with one another. Many objects
+/// throughout the I/O and related libraries take and provide types which
+/// implement the `Write` trait.
+pub trait Write {
+    /// Write a buffer into this object, returning how many bytes were written.
+    ///
+    /// This function will attempt to write the entire contents of `buf`, but
+    /// the entire write may not succeed, or the write may also generate an
+    /// error. A call to `write` represents *at most one* attempt to write to
+    /// any wrapped object.
+    ///
+    /// Calls to `write` are not guaranteed to block waiting for data to be
+    /// written, and a write which would otherwise block can indicated through
+    /// an `Err` variant.
+    ///
+    /// If the return value is `Ok(n)` then it must be guaranteed that
+    /// `0 <= n <= buf.len()`. A return value of `0` typically means that the
+    /// underlying object is no longer able to accept bytes and will likely not
+    /// be able to in the future as well, or that the buffer provided is empty.
+    ///
+    /// # Errors
+    ///
+    /// Each call to `write` may generate an I/O error indicating that the
+    /// operation could not be completed. If an error is returned then no bytes
+    /// in the buffer were written to this writer.
+    ///
+    /// It is **not** considered an error if the entire buffer could not be
+    /// written to this writer.
+    fn write(&mut self, buf: &[u8]) -> Result<usize>;
+
+    /// Flush this output stream, ensuring that all intermediately buffered
+    /// contents reach their destination.
+    ///
+    /// # Errors
+    ///
+    /// It is considered an error if not all bytes could be written due to
+    /// I/O errors or EOF being reached.
+    fn flush(&mut self) -> Result<()>;
+
+    /// Attempts to write an entire buffer into this write.
+    ///
+    /// This method will continuously call `write` while there is more data to
+    /// write. This method will not return until the entire buffer has been
+    /// successfully written or an error occurs. The first error generated from
+    /// this method will be returned.
+    ///
+    /// # Errors
+    ///
+    /// This function will return the first error that `write` returns.
+    fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
+        while buf.len() > 0 {
+            match self.write(buf) {
+                Ok(0) => return Err(Error::new(ErrorKind::WriteZero,
+                                               "failed to write whole buffer",
+                                               None)),
+                Ok(n) => buf = &buf[n..],
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+                Err(e) => return Err(e),
+            }
+        }
+        Ok(())
+    }
+
+    /// Writes a formatted string into this writer, returning any error
+    /// encountered.
+    ///
+    /// This method is primarily used to interface with the `format_args!`
+    /// macro, but it is rare that this should explicitly be called. The
+    /// `write!` macro should be favored to invoke this method instead.
+    ///
+    /// This function internally uses the `write_all` method on this trait and
+    /// hence will continuously write data so long as no errors are received.
+    /// This also means that partial writes are not indicated in this signature.
+    ///
+    /// # Errors
+    ///
+    /// This function will return any I/O error reported while formatting.
+    fn write_fmt(&mut self, fmt: fmt::Arguments) -> Result<()> {
+        // Create a shim which translates a Writer to a fmt::Writer and saves
+        // off I/O errors. instead of discarding them
+        struct Adaptor<'a, T: ?Sized + 'a> {
+            inner: &'a mut T,
+            error: Result<()>,
+        }
+
+        impl<'a, T: Write + ?Sized> fmt::Writer for Adaptor<'a, T> {
+            fn write_str(&mut self, s: &str) -> fmt::Result {
+                match self.inner.write_all(s.as_bytes()) {
+                    Ok(()) => Ok(()),
+                    Err(e) => {
+                        self.error = Err(e);
+                        Err(fmt::Error)
+                    }
+                }
+            }
+        }
+
+        let mut output = Adaptor { inner: self, error: Ok(()) };
+        match fmt::write(&mut output, fmt) {
+            Ok(()) => Ok(()),
+            Err(..) => output.error
+        }
+    }
+}
+
+/// Extension methods for all instances of `Write`, typically imported through
+/// `std::io::prelude::*`.
+pub trait WriteExt: Write + Sized {
+    /// Create a "by reference" adaptor for this instance of `Write`.
+    ///
+    /// The returned adaptor also implements `Write` and will simply borrow this
+    /// current writer.
+    fn by_ref(&mut self) -> &mut Self { self }
+
+    /// Creates a new writer which will write all data to both this writer and
+    /// another writer.
+    ///
+    /// All data written to the returned writer will both be written to `self`
+    /// as well as `other`. Note that the error semantics of the current
+    /// implementation do not precisely track where errors happen. For example
+    /// an error on the second call to `write` will not report that the first
+    /// call to `write` succeeded.
+    fn broadcast<W: Write>(self, other: W) -> Broadcast<Self, W> {
+        Broadcast { first: self, second: other }
+    }
+}
+
+impl<T: Write> WriteExt for T {}
+
+/// An object implementing `Seek` internally has some form of cursor which can
+/// be moved within a stream of bytes.
+///
+/// The stream typically has a fixed size, allowing seeking relative to either
+/// end or the current offset.
+pub trait Seek {
+    /// Seek to an offset, in bytes, in a stream
+    ///
+    /// A seek beyond the end of a stream is allowed, but seeking before offset
+    /// 0 is an error.
+    ///
+    /// Seeking past the end of the stream does not modify the underlying
+    /// stream, but the next write may cause the previous data to be filled in
+    /// with a bit pattern.
+    ///
+    /// This method returns the new position within the stream if the seek
+    /// operation completed successfully.
+    ///
+    /// # Errors
+    ///
+    /// Seeking to a negative offset is considered an error
+    fn seek(&mut self, pos: SeekFrom) -> Result<u64>;
+}
+
+/// Enumeration of possible methods to seek within an I/O object.
+#[derive(Copy, PartialEq, Eq, Clone, Debug)]
+pub enum SeekFrom {
+    /// Set the offset to the provided number of bytes.
+    Start(u64),
+
+    /// Set the offset to the size of this object plus the specified number of
+    /// bytes.
+    ///
+    /// It is possible to seek beyond the end of an object, but is an error to
+    /// seek before byte 0.
+    End(i64),
+
+    /// Set the offset to the current position plus the specified number of
+    /// bytes.
+    ///
+    /// It is possible to seek beyond the end of an object, but is an error to
+    /// seek before byte 0.
+    Current(i64),
+}
+
+fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>)
+                                   -> Result<()> {
+    loop {
+        let (done, used) = {
+            let available = match r.fill_buf() {
+                Ok(n) => n,
+                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+                Err(e) => return Err(e)
+            };
+            match available.position_elem(&delim) {
+                Some(i) => {
+                    buf.push_all(&available[..i + 1]);
+                    (true, i + 1)
+                }
+                None => {
+                    buf.push_all(available);
+                    (false, available.len())
+                }
+            }
+        };
+        r.consume(used);
+        if done || used == 0 {
+            return Ok(());
+        }
+    }
+}
+
+/// A Buffer is a type of reader which has some form of internal buffering to
+/// allow certain kinds of reading operations to be more optimized than others.
+///
+/// This type extends the `Read` trait with a few methods that are not
+/// possible to reasonably implement with purely a read interface.
+pub trait BufRead: Read {
+    /// Fills the internal buffer of this object, returning the buffer contents.
+    ///
+    /// None of the contents will be "read" in the sense that later calling
+    /// `read` may return the same contents.
+    ///
+    /// The `consume` function must be called with the number of bytes that are
+    /// consumed from this buffer returned to ensure that the bytes are never
+    /// returned twice.
+    ///
+    /// An empty buffer returned indicates that the stream has reached EOF.
+    ///
+    /// # Errors
+    ///
+    /// This function will return an I/O error if the underlying reader was
+    /// read, but returned an error.
+    fn fill_buf(&mut self) -> Result<&[u8]>;
+
+    /// Tells this buffer that `amt` bytes have been consumed from the buffer,
+    /// so they should no longer be returned in calls to `read`.
+    fn consume(&mut self, amt: usize);
+
+    /// Read all bytes until the delimiter `byte` is reached.
+    ///
+    /// This function will continue to read (and buffer) bytes from the
+    /// underlying stream until the delimiter or EOF is found. Once found, all
+    /// bytes up to, and including, the delimiter (if found) will be appended to
+    /// `buf`.
+    ///
+    /// If this buffered reader is currently at EOF, then this function will not
+    /// place any more bytes into `buf` and will return `Ok(())`.
+    ///
+    /// # Errors
+    ///
+    /// This function will ignore all instances of `ErrorKind::Interrupted` and
+    /// will otherwise return any errors returned by `fill_buf`.
+    ///
+    /// If an I/O error is encountered then all bytes read so far will be
+    /// present in `buf` and its length will have been adjusted appropriately.
+    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> Result<()> {
+        read_until(self, byte, buf)
+    }
+
+    /// Read all bytes until a newline byte (the 0xA byte) is reached.
+    ///
+    /// This function will continue to read (and buffer) bytes from the
+    /// underlying stream until the newline delimiter (the 0xA byte) or EOF is
+    /// found. Once found, all bytes up to, and including, the delimiter (if
+    /// found) will be appended to `buf`.
+    ///
+    /// If this reader is currently at EOF then this function will not modify
+    /// `buf` and will return `Ok(())`.
+    ///
+    /// # Errors
+    ///
+    /// This function has the same error semantics as `read_until` and will also
+    /// return an error if the read bytes are not valid UTF-8. If an I/O error
+    /// is encountered then `buf` may contain some bytes already read in the
+    /// event that all data read so far was valid UTF-8.
+    fn read_line(&mut self, buf: &mut String) -> Result<()> {
+        // Note that we are not calling the `.read_until` method here, but
+        // rather our hardcoded implementation. For more details as to why, see
+        // the comments in `read_to_end`.
+        append_to_string(buf, |b| read_until(self, b'\n', b))
+    }
+}
+
+/// Extension methods for all instances of `BufRead`, typically imported through
+/// `std::io::prelude::*`.
+pub trait BufReadExt: BufRead + Sized {
+    /// Returns an iterator over the contents of this reader split on the byte
+    /// `byte`.
+    ///
+    /// The iterator returned from this function will return instances of
+    /// `io::Result<Vec<u8>>`. Each vector returned will *not* have the
+    /// delimiter byte at the end.
+    ///
+    /// This function will yield errors whenever `read_until` would have also
+    /// yielded an error.
+    fn split(self, byte: u8) -> Split<Self> {
+        Split { buf: self, delim: byte }
+    }
+
+    /// Returns an iterator over the lines of this reader.
+    ///
+    /// The iterator returned from this function will yield instances of
+    /// `io::Result<String>`. Each string returned will *not* have a newline
+    /// byte (the 0xA byte) at the end.
+    ///
+    /// This function will yield errors whenever `read_string` would have also
+    /// yielded an error.
+    fn lines(self) -> Lines<Self> {
+        Lines { buf: self }
+    }
+}
+
+impl<T: BufRead> BufReadExt for T {}
+
+/// A `Write` adaptor which will write data to multiple locations.
+///
+/// For more information, see `WriteExt::broadcast`.
+pub struct Broadcast<T, U> {
+    first: T,
+    second: U,
+}
+
+impl<T: Write, U: Write> Write for Broadcast<T, U> {
+    fn write(&mut self, data: &[u8]) -> Result<usize> {
+        let n = try!(self.first.write(data));
+        // FIXME: what if the write fails? (we wrote something)
+        try!(self.second.write_all(&data[..n]));
+        Ok(n)
+    }
+
+    fn flush(&mut self) -> Result<()> {
+        self.first.flush().and(self.second.flush())
+    }
+}
+
+/// Adaptor to chain together two instances of `Read`.
+///
+/// For more information, see `ReadExt::chain`.
+pub struct Chain<T, U> {
+    first: T,
+    second: U,
+    done_first: bool,
+}
+
+impl<T: Read, U: Read> Read for Chain<T, U> {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        if !self.done_first {
+            match try!(self.first.read(buf)) {
+                0 => { self.done_first = true; }
+                n => return Ok(n),
+            }
+        }
+        self.second.read(buf)
+    }
+}
+
+/// Reader adaptor which limits the bytes read from an underlying reader.
+///
+/// For more information, see `ReadExt::take`.
+pub struct Take<T> {
+    inner: T,
+    limit: u64,
+}
+
+impl<T> Take<T> {
+    /// Returns the number of bytes that can be read before this instance will
+    /// return EOF.
+    ///
+    /// # Note
+    ///
+    /// This instance may reach EOF after reading fewer bytes than indiccated by
+    /// this method if the underlying `Read` instance reaches EOF.
+    pub fn limit(&self) -> u64 { self.limit }
+}
+
+impl<T: Read> Read for Take<T> {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let max = cmp::min(buf.len() as u64, self.limit) as usize;
+        let n = try!(self.inner.read(&mut buf[..max]));
+        self.limit -= n as u64;
+        Ok(n)
+    }
+}
+
+/// An adaptor which will emit all read data to a specified writer as well.
+///
+/// For more information see `ReadExt::tee`
+pub struct Tee<R, W> {
+    reader: R,
+    writer: W,
+}
+
+impl<R: Read, W: Write> Read for Tee<R, W> {
+    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
+        let n = try!(self.reader.read(buf));
+        // FIXME: what if the write fails? (we read something)
+        try!(self.writer.write_all(&buf[..n]));
+        Ok(n)
+    }
+}
+
+/// A bridge from implementations of `Read` to an `Iterator` of `u8`.
+///
+/// See `ReadExt::bytes` for more information.
+pub struct Bytes<R> {
+    inner: R,
+}
+
+impl<R: Read> Iterator for Bytes<R> {
+    type Item = Result<u8>;
+
+    fn next(&mut self) -> Option<Result<u8>> {
+        let mut buf = [0];
+        match self.inner.read(&mut buf) {
+            Ok(0) => None,
+            Ok(..) => Some(Ok(buf[0])),
+            Err(e) => Some(Err(e)),
+        }
+    }
+}
+
+/// A bridge from implementations of `Read` to an `Iterator` of `char`.
+///
+/// See `ReadExt::chars` for more information.
+pub struct Chars<R> {
+    inner: R,
+}
+
+/// An enumeration of possible errors that can be generated from the `Chars`
+/// adapter.
+#[derive(PartialEq, Clone, Debug)]
+pub enum CharsError {
+    /// Variant representing that the underlying stream was read successfully
+    /// but it did not contain valid utf8 data.
+    NotUtf8,
+
+    /// Variant representing that an I/O error occurred.
+    Other(Error),
+}
+
+impl<R: Read> Iterator for Chars<R> {
+    type Item = result::Result<char, CharsError>;
+
+    fn next(&mut self) -> Option<result::Result<char, CharsError>> {
+        let mut buf = [0];
+        let first_byte = match self.inner.read(&mut buf) {
+            Ok(0) => return None,
+            Ok(..) => buf[0],
+            Err(e) => return Some(Err(CharsError::Other(e))),
+        };
+        let width = core_str::utf8_char_width(first_byte);
+        if width == 1 { return Some(Ok(first_byte as char)) }
+        if width == 0 { return Some(Err(CharsError::NotUtf8)) }
+        let mut buf = [first_byte, 0, 0, 0];
+        {
+            let mut start = 1;
+            while start < width {
+                match self.inner.read(&mut buf[start..width]) {
+                    Ok(0) => return Some(Err(CharsError::NotUtf8)),
+                    Ok(n) => start += n,
+                    Err(e) => return Some(Err(CharsError::Other(e))),
+                }
+            }
+        }
+        Some(match str::from_utf8(&buf[..width]).ok() {
+            Some(s) => Ok(s.char_at(0)),
+            None => Err(CharsError::NotUtf8),
+        })
+    }
+}
+
+impl StdError for CharsError {
+    fn description(&self) -> &str {
+        match *self {
+            CharsError::NotUtf8 => "invalid utf8 encoding",
+            CharsError::Other(ref e) => e.description(),
+        }
+    }
+    fn cause(&self) -> Option<&StdError> {
+        match *self {
+            CharsError::NotUtf8 => None,
+            CharsError::Other(ref e) => e.cause(),
+        }
+    }
+}
+
+impl fmt::Display for CharsError {
+    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+        match *self {
+            CharsError::NotUtf8 => {
+                "byte stream did not contain valid utf8".fmt(f)
+            }
+            CharsError::Other(ref e) => e.fmt(f),
+        }
+    }
+}
+
+/// An iterator over the contents of an instance of `BufRead` split on a
+/// particular byte.
+///
+/// See `BufReadExt::split` for more information.
+pub struct Split<B> {
+    buf: B,
+    delim: u8,
+}
+
+impl<B: BufRead> Iterator for Split<B> {
+    type Item = Result<Vec<u8>>;
+
+    fn next(&mut self) -> Option<Result<Vec<u8>>> {
+        let mut buf = Vec::new();
+        match self.buf.read_until(self.delim, &mut buf) {
+            Ok(()) if buf.len() == 0 => None,
+            Ok(()) => {
+                if buf[buf.len() - 1] == self.delim {
+                    buf.pop();
+                }
+                Some(Ok(buf))
+            }
+            Err(e) => Some(Err(e))
+        }
+    }
+}
+
+/// An iterator over the lines of an instance of `BufRead` split on a newline
+/// byte.
+///
+/// See `BufReadExt::lines` for more information.
+pub struct Lines<B> {
+    buf: B,
+}
+
+impl<B: BufRead> Iterator for Lines<B> {
+    type Item = Result<String>;
+
+    fn next(&mut self) -> Option<Result<String>> {
+        let mut buf = String::new();
+        match self.buf.read_line(&mut buf) {
+            Ok(()) if buf.len() == 0 => None,
+            Ok(()) => {
+                if buf.ends_with("\n") {
+                    buf.pop();
+                }
+                Some(Ok(buf))
+            }
+            Err(e) => Some(Err(e))
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use prelude::v1::*;
+    use io::prelude::*;
+    use super::Cursor;
+
+    #[test]
+    fn read_until() {
+        let mut buf = Cursor::new(b"12");
+        let mut v = Vec::new();
+        assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
+        assert_eq!(v, b"12");
+
+        let mut buf = Cursor::new(b"1233");
+        let mut v = Vec::new();
+        assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
+        assert_eq!(v, b"123");
+        v.truncate(0);
+        assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
+        assert_eq!(v, b"3");
+        v.truncate(0);
+        assert_eq!(buf.read_until(b'3', &mut v), Ok(()));
+        assert_eq!(v, []);
+    }
+
+    #[test]
+    fn split() {
+        let mut buf = Cursor::new(b"12");
+        let mut s = buf.split(b'3');
+        assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
+        assert_eq!(s.next(), None);
+
+        let mut buf = Cursor::new(b"1233");
+        let mut s = buf.split(b'3');
+        assert_eq!(s.next(), Some(Ok(vec![b'1', b'2'])));
+        assert_eq!(s.next(), Some(Ok(vec![])));
+        assert_eq!(s.next(), None);
+    }
+
+    #[test]
+    fn read_line() {
+        let mut buf = Cursor::new(b"12");
+        let mut v = String::new();
+        assert_eq!(buf.read_line(&mut v), Ok(()));
+        assert_eq!(v, "12");
+
+        let mut buf = Cursor::new(b"12\n\n");
+        let mut v = String::new();
+        assert_eq!(buf.read_line(&mut v), Ok(()));
+        assert_eq!(v, "12\n");
+        v.truncate(0);
+        assert_eq!(buf.read_line(&mut v), Ok(()));
+        assert_eq!(v, "\n");
+        v.truncate(0);
+        assert_eq!(buf.read_line(&mut v), Ok(()));
+        assert_eq!(v, "");
+    }
+
+    #[test]
+    fn lines() {
+        let mut buf = Cursor::new(b"12");
+        let mut s = buf.lines();
+        assert_eq!(s.next(), Some(Ok("12".to_string())));
+        assert_eq!(s.next(), None);
+
+        let mut buf = Cursor::new(b"12\n\n");
+        let mut s = buf.lines();
+        assert_eq!(s.next(), Some(Ok("12".to_string())));
+        assert_eq!(s.next(), Some(Ok(String::new())));
+        assert_eq!(s.next(), None);
+    }
+
+    #[test]
+    fn read_to_end() {
+        let mut c = Cursor::new(b"");
+        let mut v = Vec::new();
+        assert_eq!(c.read_to_end(&mut v), Ok(()));
+        assert_eq!(v, []);
+
+        let mut c = Cursor::new(b"1");
+        let mut v = Vec::new();
+        assert_eq!(c.read_to_end(&mut v), Ok(()));
+        assert_eq!(v, b"1");
+    }
+
+    #[test]
+    fn read_to_string() {
+        let mut c = Cursor::new(b"");
+        let mut v = String::new();
+        assert_eq!(c.read_to_string(&mut v), Ok(()));
+        assert_eq!(v, "");
+
+        let mut c = Cursor::new(b"1");
+        let mut v = String::new();
+        assert_eq!(c.read_to_string(&mut v), Ok(()));
+        assert_eq!(v, "1");
+
+        let mut c = Cursor::new(b"\xff");
+        let mut v = String::new();
+        assert!(c.read_to_string(&mut v).is_err());
+    }
+}
diff --git a/src/libstd/io/prelude.rs b/src/libstd/io/prelude.rs
new file mode 100644 (file)
index 0000000..475ada2
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.
+
+//! The I/O Prelude
+//!
+//! The purpose of this module is to alleviate imports of many common I/O traits
+//! by adding a glob import to the top of I/O heavy modules:
+//!
+//! ```
+//! use std::io::prelude::*;
+//! ```
+//!
+//! This module contains reexports of many core I/O traits such as `Read`,
+//! `Write`, `ReadExt`, and `WriteExt`. Structures and functions are not
+//! contained in this module.
+
+pub use super::{Read, ReadExt, Write, WriteExt, BufRead, BufReadExt};
+
+// FIXME: pub use as `Seek` when the name isn't in the actual prelude any more
+pub use super::Seek as NewSeek;
diff --git a/src/libstd/io/util.rs b/src/libstd/io/util.rs
new file mode 100644 (file)
index 0000000..3d34213
--- /dev/null
@@ -0,0 +1,153 @@
+// Copyright 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.
+
+#![allow(missing_copy_implementations)]
+
+use prelude::v1::*;
+
+use io::{self, Read, Write, ErrorKind};
+
+/// Copies the entire contents of a reader into a writer.
+///
+/// This function will continuously read data from `r` and then write it into
+/// `w` in a streaming fashion until `r` returns EOF.
+///
+/// On success the total number of bytes that were copied from `r` to `w` is
+/// returned.
+///
+/// # Errors
+///
+/// This function will return an error immediately if any call to `read` or
+/// `write` returns an error. All instances of `ErrorKind::Interrupted` are
+/// handled by this function and the underlying operation is retried.
+pub fn copy<R: Read, W: Write>(r: &mut R, w: &mut W) -> io::Result<u64> {
+    let mut buf = [0; super::DEFAULT_BUF_SIZE];
+    let mut written = 0;
+    loop {
+        let len = match r.read(&mut buf) {
+            Ok(0) => return Ok(written),
+            Ok(len) => len,
+            Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+            Err(e) => return Err(e),
+        };
+        try!(w.write_all(&buf[..len]));
+        written += len as u64;
+    }
+}
+
+/// A reader which is always at EOF.
+pub struct Empty { _priv: () }
+
+/// Creates an instance of an empty reader.
+///
+/// All reads from the returned reader will return `Ok(0)`.
+pub fn empty() -> Empty { Empty { _priv: () } }
+
+impl Read for Empty {
+    fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> { Ok(0) }
+}
+
+/// A reader which infinitely yields one byte.
+pub struct Repeat { byte: u8 }
+
+/// Creates an instance of a reader that infinitely repeats one byte.
+///
+/// All reads from this reader will succeed by filling the specified buffer with
+/// the given byte.
+pub fn repeat(byte: u8) -> Repeat { Repeat { byte: byte } }
+
+impl Read for Repeat {
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        for slot in buf.iter_mut() {
+            *slot = self.byte;
+        }
+        Ok(buf.len())
+    }
+}
+
+/// A writer which will move data into the void.
+pub struct Sink { _priv: () }
+
+/// Creates an instance of a writer which will successfully consume all data.
+///
+/// All calls to `write` on the returned instance will return `Ok(buf.len())`
+/// and the contents of the buffer will not be inspected.
+pub fn sink() -> Sink { Sink { _priv: () } }
+
+impl Write for Sink {
+    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { Ok(buf.len()) }
+    fn flush(&mut self) -> io::Result<()> { Ok(()) }
+}
+
+#[cfg(test)]
+mod test {
+    use prelude::v1::*;
+
+    use io::prelude::*;
+    use io::{sink, empty, repeat};
+
+    #[test]
+    fn sink_sinks() {
+        let mut s = sink();
+        assert_eq!(s.write(&[]), Ok(0));
+        assert_eq!(s.write(&[0]), Ok(1));
+        assert_eq!(s.write(&[0; 1024]), Ok(1024));
+        assert_eq!(s.by_ref().write(&[0; 1024]), Ok(1024));
+    }
+
+    #[test]
+    fn empty_reads() {
+        let mut e = empty();
+        assert_eq!(e.read(&mut []), Ok(0));
+        assert_eq!(e.read(&mut [0]), Ok(0));
+        assert_eq!(e.read(&mut [0; 1024]), Ok(0));
+        assert_eq!(e.by_ref().read(&mut [0; 1024]), Ok(0));
+    }
+
+    #[test]
+    fn repeat_repeats() {
+        let mut r = repeat(4);
+        let mut b = [0; 1024];
+        assert_eq!(r.read(&mut b), Ok(1024));
+        assert!(b.iter().all(|b| *b == 4));
+    }
+
+    #[test]
+    fn take_some_bytes() {
+        assert_eq!(repeat(4).take(100).bytes().count(), 100);
+        assert_eq!(repeat(4).take(100).bytes().next(), Some(Ok(4)));
+        assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20);
+    }
+
+    #[test]
+    fn tee() {
+        let mut buf = [0; 10];
+        {
+            let mut ptr: &mut [u8] = &mut buf;
+            assert_eq!(repeat(4).tee(&mut ptr).take(5).read(&mut [0; 10]), Ok(5));
+        }
+        assert_eq!(buf, [4, 4, 4, 4, 4, 0, 0, 0, 0, 0]);
+    }
+
+    #[test]
+    fn broadcast() {
+        let mut buf1 = [0; 10];
+        let mut buf2 = [0; 10];
+        {
+            let mut ptr1: &mut [u8] = &mut buf1;
+            let mut ptr2: &mut [u8] = &mut buf2;
+
+            assert_eq!((&mut ptr1).broadcast(&mut ptr2)
+                                  .write(&[1, 2, 3]), Ok(3));
+        }
+        assert_eq!(buf1, buf2);
+        assert_eq!(buf1, [1, 2, 3, 0, 0, 0, 0, 0, 0, 0]);
+    }
+}
index 839983d336d765e819cde518e8432b1c60731b4b..14e779f9c4a8edad733e408b7baa5a97a17af2df 100644 (file)
 
 #![deny(missing_docs)]
 
-#[cfg(test)]
-#[macro_use]
-extern crate log;
+#[cfg(test)] extern crate test;
+#[cfg(test)] #[macro_use] extern crate log;
 
 #[macro_use]
 #[macro_reexport(assert, assert_eq, debug_assert, debug_assert_eq,
 #[macro_reexport(vec)]
 extern crate "collections" as core_collections;
 
-extern crate "rand" as core_rand;
+#[allow(deprecated)] extern crate "rand" as core_rand;
 extern crate alloc;
 extern crate unicode;
 extern crate libc;
 pub mod ffi;
 pub mod fmt;
 pub mod old_io;
+pub mod io;
 pub mod os;
 pub mod env;
 pub mod path;
+pub mod old_path;
 pub mod rand;
 pub mod time;
 
index 1d3bf484edb9ab458150dbd6213b2884fb423da3..9c4741b3ce316f0eefa0e06343eda48fe8f223d5 100644 (file)
@@ -459,6 +459,7 @@ fn test_int_to_str_overflow() {
 
 #[cfg(test)]
 mod bench {
+    #![allow(deprecated)] // rand
     extern crate test;
 
     mod uint {
index abf215988bb4b859982967ee3dda5ceeb3294d65..67e3fddfd05a5401d10b0ea5b9a175e6dede52a2 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 {
@@ -822,6 +822,7 @@ fn access_string(access: FileAccess) -> &'static str {
 #[allow(unused_imports)]
 #[allow(unused_variables)]
 #[allow(unused_mut)]
+#[allow(deprecated)] // rand
 mod test {
     use prelude::v1::*;
     use old_io::{SeekSet, SeekCur, SeekEnd, Read, Open, ReadWrite, FileType};
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..42317c7a2d4316be452817d5b0988bc00a667cad 100644 (file)
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 //! Temporary files and directories
+#![allow(deprecated)] // rand
 
 use env;
 use iter::{IteratorExt};
@@ -17,7 +18,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..64f9e16aee4fd3392220bbaea6b13946d6d97644 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());
@@ -1422,6 +1422,8 @@ mod arch_consts {
 
 #[cfg(test)]
 mod tests {
+    #![allow(deprecated)] // rand
+
     use prelude::v1::*;
 
     use iter::repeat;
diff --git a/src/libstd/path.rs b/src/libstd/path.rs
new file mode 100755 (executable)
index 0000000..3f4f1ec
--- /dev/null
@@ -0,0 +1,2577 @@
+// 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, Debug, 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 char::CharExt as UnicodeCharExt;
+    use super::{os_str_as_u8_slice, u8_slice_as_os_str};
+    use ascii::*;
+    use ffi::OsStr;
+
+    #[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 {
+                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> 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), VerbatimUNC(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, Debug)]
+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, Debug)]
+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");
+        if cfg!(unix) {
+            tfn!(".", "foo", "./foo");
+            tfn!("foo/", "bar", "foo/bar");
+            tfn!("foo/.", "bar", "foo/./bar");
+            tfn!("..", "foo", "../foo");
+            tfn!("foo/..", "bar", "foo/../bar");
+            tfn!("/", "foo", "/foo");
+        } else {
+            tfn!(".", "foo", r".\foo");
+            tfn!(r"foo\", "bar", r"foo\bar");
+            tfn!(r"foo\.", "bar", r"foo\.\bar");
+            tfn!("..", "foo", r"..\foo");
+            tfn!(r"foo\..", "bar", r"foo\..\bar");
+            tfn!(r"\", "foo", r"\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 cc72c5bed99dc905102e3bffb0345abeb5f4676f..e52d5ada0ef092767896d0dbc53c6e79dd263196 100644 (file)
 //! ```
 
 #![unstable(feature = "rand")]
+#![deprecated(reason = "use the crates.io `rand` library instead",
+              since = "1.0.0-alpha")]
+#![allow(deprecated)]
 
 use cell::RefCell;
 use clone::Clone;
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 2dfc708e15bebdc7386d96469e0451551b651251..6efbcf894156e887b97264c16be78d9eece25578 100644 (file)
@@ -383,6 +383,8 @@ fn drop(&mut self) {
 
 #[cfg(test)]
 mod tests {
+    #![allow(deprecated)] // rand
+
     use prelude::v1::*;
 
     use rand::{self, Rng};
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 89bd9a2340652e550070abe0e2774fb101065863..50a8e6b73e3866ff2b8d66879f97d3d9bbc20de7 100644 (file)
@@ -143,6 +143,7 @@ pub fn sigaction(signum: libc::c_int,
     pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int;
     pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int;
 
+    #[cfg(not(target_os = "ios"))]
     pub fn getpwuid_r(uid: libc::uid_t,
                       pwd: *mut passwd,
                       buf: *mut libc::c_char,
index b03b9046966a02dc3dccc99307c8a9900cbb6750..427cf21ac70a9cc86021597c2b5570a755fa0875 100644 (file)
 use prelude::v1::*;
 
 use ffi;
-use old_io::{self, IoResult, IoError};
+use io::ErrorKind;
 use libc;
 use num::{Int, SignedInt};
 use num;
+use old_io::{self, IoResult, IoError};
 use str;
 use sys_common::mkerr_libc;
 
@@ -133,6 +134,35 @@ pub fn decode_error_detailed(errno: i32) -> IoError {
     err
 }
 
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    match errno as libc::c_int {
+        libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
+        libc::ECONNRESET => ErrorKind::ConnectionReset,
+        libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
+        libc::EPIPE => ErrorKind::BrokenPipe,
+        libc::ENOTCONN => ErrorKind::NotConnected,
+        libc::ECONNABORTED => ErrorKind::ConnectionAborted,
+        libc::EADDRNOTAVAIL => ErrorKind::ConnectionRefused,
+        libc::EADDRINUSE => ErrorKind::ConnectionRefused,
+        libc::ENOENT => ErrorKind::FileNotFound,
+        libc::EISDIR => ErrorKind::InvalidInput,
+        libc::EINTR => ErrorKind::Interrupted,
+        libc::EINVAL => ErrorKind::InvalidInput,
+        libc::ENOTTY => ErrorKind::MismatchedFileTypeForOperation,
+        libc::ETIMEDOUT => ErrorKind::TimedOut,
+        libc::ECANCELED => ErrorKind::TimedOut,
+        libc::consts::os::posix88::EEXIST => ErrorKind::PathAlreadyExists,
+
+        // These two constants can have the same value on some systems,
+        // but different values on others, so we can't use a match
+        // clause
+        x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
+            ErrorKind::ResourceUnavailable,
+
+        _ => ErrorKind::Other,
+    }
+}
+
 #[inline]
 pub fn retry<T, F> (mut f: F) -> T where
     T: SignedInt,
index b3f3796294580b1b1b8358be300672a8a318cf45..5004ff713c45f42ffa2d13f3db39194a8b9f8936 100644 (file)
@@ -307,23 +307,23 @@ pub fn args() -> Args {
     let mut res = Vec::new();
 
     unsafe {
-        let processInfoSel = sel_registerName("processInfo\0".as_ptr());
-        let argumentsSel = sel_registerName("arguments\0".as_ptr());
-        let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
-        let countSel = sel_registerName("count\0".as_ptr());
-        let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
+        let process_info_sel = sel_registerName("processInfo\0".as_ptr());
+        let arguments_sel = sel_registerName("arguments\0".as_ptr());
+        let utf8_sel = sel_registerName("UTF8String\0".as_ptr());
+        let count_sel = sel_registerName("count\0".as_ptr());
+        let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr());
 
         let klass = objc_getClass("NSProcessInfo\0".as_ptr());
-        let info = objc_msgSend(klass, processInfoSel);
-        let args = objc_msgSend(info, argumentsSel);
+        let info = objc_msgSend(klass, process_info_sel);
+        let args = objc_msgSend(info, arguments_sel);
 
-        let cnt: int = mem::transmute(objc_msgSend(args, countSel));
+        let cnt: int = mem::transmute(objc_msgSend(args, count_sel));
         for i in range(0, cnt) {
-            let tmp = objc_msgSend(args, objectAtSel, i);
+            let tmp = objc_msgSend(args, object_at_sel, i);
             let utf_c_str: *const libc::c_char =
-                mem::transmute(objc_msgSend(tmp, utf8Sel));
-            let bytes = ffi::c_str_to_bytes(&utf_c_str).to_vec();
-            res.push(OsString::from_vec(bytes))
+                mem::transmute(objc_msgSend(tmp, utf8_sel));
+            let bytes = ffi::c_str_to_bytes(&utf_c_str);
+            res.push(OsString::from_str(str::from_utf8(bytes).unwrap()))
         }
     }
 
@@ -455,9 +455,11 @@ pub fn home_dir() -> Option<Path> {
         Path::new(os.into_vec())
     });
 
-    #[cfg(target_os = "android")]
+    #[cfg(any(target_os = "android",
+              target_os = "ios"))]
     unsafe fn fallback() -> Option<OsString> { None }
-    #[cfg(not(target_os = "android"))]
+    #[cfg(not(any(target_os = "android",
+                  target_os = "ios")))]
     unsafe fn fallback() -> Option<OsString> {
         let mut amt = match libc::sysconf(c::_SC_GETPW_R_SIZE_MAX) {
             n if n < 0 => 512 as usize,
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 8dd467eba9e2a885e5ffff07ee34ec4d28d08e26..f1af70e2cf7d1eb341bc87ff5bee89d0133bbca1 100644 (file)
@@ -15,6 +15,7 @@
 use prelude::v1::*;
 
 use ffi::OsStr;
+use io::ErrorKind;
 use libc;
 use mem;
 use old_io::{self, IoResult, IoError};
@@ -143,6 +144,34 @@ pub fn decode_error_detailed(errno: i32) -> IoError {
     err
 }
 
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+    match errno as libc::c_int {
+        libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied,
+        libc::ERROR_ALREADY_EXISTS => ErrorKind::PathAlreadyExists,
+        libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe,
+        libc::ERROR_FILE_NOT_FOUND => ErrorKind::FileNotFound,
+        libc::ERROR_INVALID_FUNCTION => ErrorKind::InvalidInput,
+        libc::ERROR_INVALID_HANDLE => ErrorKind::MismatchedFileTypeForOperation,
+        libc::ERROR_INVALID_NAME => ErrorKind::InvalidInput,
+        libc::ERROR_NOTHING_TO_TERMINATE => ErrorKind::InvalidInput,
+        libc::ERROR_NO_DATA => ErrorKind::BrokenPipe,
+        libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut,
+
+        libc::WSAEACCES => ErrorKind::PermissionDenied,
+        libc::WSAEADDRINUSE => ErrorKind::ConnectionRefused,
+        libc::WSAEADDRNOTAVAIL => ErrorKind::ConnectionRefused,
+        libc::WSAECONNABORTED => ErrorKind::ConnectionAborted,
+        libc::WSAECONNREFUSED => ErrorKind::ConnectionRefused,
+        libc::WSAECONNRESET => ErrorKind::ConnectionReset,
+        libc::WSAEINVAL => ErrorKind::InvalidInput,
+        libc::WSAENOTCONN => ErrorKind::NotConnected,
+        libc::WSAEWOULDBLOCK => ErrorKind::ResourceUnavailable,
+
+        _ => ErrorKind::Other,
+    }
+}
+
+
 #[inline]
 pub fn retry<I, F>(f: F) -> I where F: FnOnce() -> I { f() } // PR rust-lang/rust/#17020
 
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 d4d777789dd5db204c8b45af81bb5f8e0f453de5..9de5fd1c770eccafd2d9d140ed67adba3da75aae 100644 (file)
@@ -45,6 +45,7 @@
 
 // Sure wish we had macro hygiene, no?
 #[doc(hidden)]
+#[stable(feature = "rust1", since = "1.0.0")]
 pub mod __impl {
     pub use super::imp::Key as KeyInner;
     pub use super::imp::destroy_value;
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 d7283db25a5f2eedc23e4347b721e79716b599ce..34eeedeaa7650bba3e232b1f6fe901982fb1071e 100644 (file)
@@ -48,7 +48,6 @@
 pub use self::Ty_::*;
 pub use self::TyParamBound::*;
 pub use self::UintTy::*;
-pub use self::ClosureKind::*;
 pub use self::UnOp::*;
 pub use self::UnsafeSource::*;
 pub use self::VariantKind::*;
@@ -736,7 +735,7 @@ pub enum Expr_ {
     // FIXME #6993: change to Option<Name> ... or not, if these are hygienic.
     ExprLoop(P<Block>, Option<Ident>),
     ExprMatch(P<Expr>, Vec<Arm>, MatchSource),
-    ExprClosure(CaptureClause, Option<ClosureKind>, P<FnDecl>, P<Block>),
+    ExprClosure(CaptureClause, P<FnDecl>, P<Block>),
     ExprBlock(P<Block>),
 
     ExprAssign(P<Expr>, P<Expr>),
@@ -1687,13 +1686,6 @@ pub fn descriptive_variant(&self) -> &str {
     }
 }
 
-#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
-pub enum ClosureKind {
-    FnClosureKind,
-    FnMutClosureKind,
-    FnOnceClosureKind,
-}
-
 /// The data we save and restore about an inlined item or method.  This is not
 /// part of the AST that we parse from a file, but it becomes part of the tree
 /// that we trans.
index 53787d71eef800c72d23d424bf1f95c145486ed5..a85b87f47d6ee0d1a9338f262a8344bed2624ff9 100644 (file)
@@ -218,7 +218,7 @@ fn handle<A, I, M, C>(self, item_fn: I, method: M, closure: C) -> A where
                 }
             }
             ast_map::NodeExpr(e) => match e.node {
-                ast::ExprClosure(_, _, ref decl, ref block) =>
+                ast::ExprClosure(_, ref decl, ref block) =>
                     closure(ClosureParts::new(&**decl, &**block, e.id, e.span)),
                 _ => panic!("expr FnLikeNode that is not fn-like"),
             },
index 2b3a72126831e7d8a3ae69def8692ade112586e5..53c35ef34cd0d4293ed2803b08a26af76a62f710 100644 (file)
@@ -876,14 +876,14 @@ fn expr_loop(&self, span: Span, block: P<ast::Block>) -> P<ast::Expr> {
 
     fn lambda_fn_decl(&self, span: Span,
                       fn_decl: P<ast::FnDecl>, blk: P<ast::Block>) -> P<ast::Expr> {
-        self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
+        self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
     }
     fn lambda(&self, span: Span, ids: Vec<ast::Ident>, blk: P<ast::Block>) -> P<ast::Expr> {
         let fn_decl = self.fn_decl(
             ids.iter().map(|id| self.arg(span, *id, self.ty_infer(span))).collect(),
             self.ty_infer(span));
 
-        self.expr(span, ast::ExprClosure(ast::CaptureByRef, None, fn_decl, blk))
+        self.expr(span, ast::ExprClosure(ast::CaptureByRef, fn_decl, blk))
     }
     fn lambda0(&self, span: Span, blk: P<ast::Block>) -> P<ast::Expr> {
         self.lambda(span, Vec::new(), blk)
index 9fd5091e194dcee568d8ee9a585f5e19138baaca..0b57e7e7c8e9e63a38a1855fe3fa8caaa040ab5c 100644 (file)
@@ -24,6 +24,10 @@ pub fn expand_deriving_rand<F>(cx: &mut ExtCtxt,
                                push: F) where
     F: FnOnce(P<Item>),
 {
+    cx.span_warn(span,
+                 "`#[derive(Rand)]` is deprecated in favour of `#[derive_Rand]` from \
+                  `rand_macros` on crates.io");
+
     let trait_def = TraitDef {
         span: span,
         attributes: Vec::new(),
@@ -66,7 +70,7 @@ fn rand_substructure(cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure)
         cx.ident_of("Rand"),
         cx.ident_of("rand")
     );
-    let mut rand_call = |&mut: cx: &mut ExtCtxt, span| {
+    let rand_call = |&: cx: &mut ExtCtxt, span| {
         cx.expr_call_global(span,
                             rand_ident.clone(),
                             vec!(rng.clone()))
index 6eacb3440189454f279f31b05b9a03e3ac16eed7..77440914342fb2ef4a60710bf3c16376db58934b 100644 (file)
@@ -322,11 +322,10 @@ pub fn expand_expr(e: P<ast::Expr>, fld: &mut MacroExpander) -> P<ast::Expr> {
             fld.cx.expr_match(span, into_iter_expr, vec![iter_arm])
         }
 
-        ast::ExprClosure(capture_clause, opt_kind, fn_decl, block) => {
+        ast::ExprClosure(capture_clause, fn_decl, block) => {
             let (rewritten_fn_decl, rewritten_block)
                 = expand_and_rename_fn_decl_and_block(fn_decl, block, fld);
             let new_node = ast::ExprClosure(capture_clause,
-                                            opt_kind,
                                             rewritten_fn_decl,
                                             rewritten_block);
             P(ast::Expr{id:id, node: new_node, span: fld.new_span(span)})
index 4e76359e93040d80f731e5f726501f7aed83cc76..d7a51e1149f30b0931636d3e551a0d9e4410d976 100644 (file)
 
     // Allows use of #[staged_api]
     ("staged_api", "1.0.0", Active),
+
+    // Allows using items which are missing stability attributes
+    ("unmarked_api", "1.0.0", Active)
 ];
 
 enum Status {
@@ -145,6 +148,7 @@ pub struct Features {
     pub quote: bool,
     pub old_orphan_check: bool,
     pub simd_ffi: bool,
+    pub unmarked_api: bool,
     pub lib_features: Vec<(InternedString, Span)>
 }
 
@@ -157,6 +161,7 @@ pub fn new() -> Features {
             quote: false,
             old_orphan_check: false,
             simd_ffi: false,
+            unmarked_api: false,
             lib_features: Vec::new()
         }
     }
@@ -566,6 +571,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         quote: cx.has_feature("quote"),
         old_orphan_check: cx.has_feature("old_orphan_check"),
         simd_ffi: cx.has_feature("simd_ffi"),
+        unmarked_api: cx.has_feature("unmarked_api"),
         lib_features: unknown_features
     }
 }
index 9012ec2114d07462f6b3783183ba3dea8953df6c..07b6af651f610eec1e10c9744fcd64d725657dfd 100644 (file)
@@ -1325,9 +1325,8 @@ pub fn noop_fold_expr<T: Folder>(Expr {id, node, span}: Expr, folder: &mut T) ->
                         arms.move_map(|x| folder.fold_arm(x)),
                         source)
             }
-            ExprClosure(capture_clause, opt_kind, decl, body) => {
+            ExprClosure(capture_clause, decl, body) => {
                 ExprClosure(capture_clause,
-                            opt_kind,
                             folder.fold_fn_decl(decl),
                             folder.fold_block(body))
             }
index a3600506057af8737ff9b1e3c7b73d73005f6bfb..60de6c909b78bfc2d8fb7371bea068650da2a536 100644 (file)
@@ -27,6 +27,7 @@ pub enum ObsoleteSyntax {
     ProcType,
     ProcExpr,
     ClosureType,
+    ClosureKind,
 }
 
 pub trait ParserObsoleteMethods {
@@ -65,6 +66,10 @@ fn obsolete(&mut self, sp: Span, kind: ObsoleteSyntax) {
                 "`|usize| -> bool` closure type syntax",
                 "use unboxed closures instead, no type annotation needed"
             ),
+            ObsoleteSyntax::ClosureKind => (
+                "`:`, `&mut:`, or `&:` syntax",
+                "rely on inference instead"
+            ),
             ObsoleteSyntax::Sized => (
                 "`Sized? T` syntax for removing the `Sized` bound",
                 "write `T: ?Sized` instead"
index c3182602a4b89672cab1ff008c7b0a569a6d5946..2cb265033c399842c6783b9af1e97c7f29f5dc7b 100644 (file)
@@ -28,8 +28,6 @@
 use ast::{ExprMethodCall, ExprParen, ExprPath, ExprQPath};
 use ast::{ExprRepeat, ExprRet, ExprStruct, ExprTup, ExprUnary};
 use ast::{ExprVec, ExprWhile, ExprWhileLet, ExprForLoop, Field, FnDecl};
-use ast::{FnClosureKind, FnMutClosureKind};
-use ast::{FnOnceClosureKind};
 use ast::{ForeignItem, ForeignItemStatic, ForeignItemFn, ForeignMod, FunctionRetTy};
 use ast::{Ident, Inherited, ImplItem, Item, Item_, ItemStatic};
 use ast::{ItemEnum, ItemFn, ItemForeignMod, ItemImpl, ItemConst};
@@ -57,7 +55,7 @@
 use ast::{TyTypeof, TyInfer, TypeMethod};
 use ast::{TyParam, TyParamBound, TyParen, TyPath, TyPolyTraitRef, TyPtr, TyQPath};
 use ast::{TyRptr, TyTup, TyU32, TyVec, UnUniq};
-use ast::{TypeImplItem, TypeTraitItem, Typedef, ClosureKind};
+use ast::{TypeImplItem, TypeTraitItem, Typedef,};
 use ast::{UnnamedField, UnsafeBlock};
 use ast::{ViewPath, ViewPathGlob, ViewPathList, ViewPathSimple};
 use ast::{Visibility, WhereClause};
@@ -1139,29 +1137,36 @@ pub fn parse_proc_type(&mut self, lifetime_defs: Vec<ast::LifetimeDef>) -> Ty_ {
         TyInfer
     }
 
-    /// Parses an optional closure kind (`&:`, `&mut:`, or `:`).
-    pub fn parse_optional_closure_kind(&mut self) -> Option<ClosureKind> {
-        if self.check(&token::BinOp(token::And)) &&
-                self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
-                self.look_ahead(2, |t| *t == token::Colon) {
+    /// Parses an obsolete closure kind (`&:`, `&mut:`, or `:`).
+    pub fn parse_obsolete_closure_kind(&mut self) {
+        // let lo = self.span.lo;
+        if
+            self.check(&token::BinOp(token::And)) &&
+            self.look_ahead(1, |t| t.is_keyword(keywords::Mut)) &&
+            self.look_ahead(2, |t| *t == token::Colon)
+        {
             self.bump();
             self.bump();
             self.bump();
-            return Some(FnMutClosureKind)
-        }
-
-        if self.token == token::BinOp(token::And) &&
-                    self.look_ahead(1, |t| *t == token::Colon) {
+        } else if
+            self.token == token::BinOp(token::And) &&
+            self.look_ahead(1, |t| *t == token::Colon)
+        {
             self.bump();
             self.bump();
-            return Some(FnClosureKind)
-        }
-
-        if self.eat(&token::Colon) {
-            return Some(FnOnceClosureKind)
+            return;
+        } else if
+            self.eat(&token::Colon)
+        {
+            /* nothing */
+        } else {
+            return;
         }
 
-        return None
+        // SNAP 474b324
+        // Enable these obsolete errors after snapshot:
+        // let span = mk_sp(lo, self.span.hi);
+        // self.obsolete(span, ObsoleteSyntax::ClosureKind);
     }
 
     pub fn parse_ty_bare_fn_or_ty_closure(&mut self, lifetime_defs: Vec<LifetimeDef>) -> Ty_ {
@@ -3047,7 +3052,7 @@ pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
                              -> P<Expr>
     {
         let lo = self.span.lo;
-        let (decl, optional_closure_kind) = self.parse_fn_block_decl();
+        let decl = self.parse_fn_block_decl();
         let body = self.parse_expr();
         let fakeblock = P(ast::Block {
             id: ast::DUMMY_NODE_ID,
@@ -3060,7 +3065,7 @@ pub fn parse_lambda_expr(&mut self, capture_clause: CaptureClause)
         self.mk_expr(
             lo,
             fakeblock.span.hi,
-            ExprClosure(capture_clause, optional_closure_kind, decl, fakeblock))
+            ExprClosure(capture_clause, decl, fakeblock))
     }
 
     pub fn parse_else_expr(&mut self) -> P<Expr> {
@@ -4529,30 +4534,29 @@ macro_rules! parse_remaining_arguments {
     }
 
     // parse the |arg, arg| header on a lambda
-    fn parse_fn_block_decl(&mut self) -> (P<FnDecl>, Option<ClosureKind>) {
-        let (optional_closure_kind, inputs_captures) = {
+    fn parse_fn_block_decl(&mut self) -> P<FnDecl> {
+        let inputs_captures = {
             if self.eat(&token::OrOr) {
-                (None, Vec::new())
+                Vec::new()
             } else {
                 self.expect(&token::BinOp(token::Or));
-                let optional_closure_kind =
-                    self.parse_optional_closure_kind();
+                self.parse_obsolete_closure_kind();
                 let args = self.parse_seq_to_before_end(
                     &token::BinOp(token::Or),
                     seq_sep_trailing_allowed(token::Comma),
                     |p| p.parse_fn_block_arg()
                 );
                 self.bump();
-                (optional_closure_kind, args)
+                args
             }
         };
         let output = self.parse_ret_ty();
 
-        (P(FnDecl {
+        P(FnDecl {
             inputs: inputs_captures,
             output: output,
             variadic: false
-        }), optional_closure_kind)
+        })
     }
 
     /// Parses the `(arg, arg) -> return_type` header on a procedure.
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 e6d895a49fcd77896657f8e1bedfaf6527e73f0f..ee8e207fa6c059b909914232d1d501cda015a9f0 100644 (file)
 pub use self::AnnNode::*;
 
 use abi;
-use ast::{self, FnClosureKind, FnMutClosureKind};
-use ast::{FnOnceClosureKind};
+use ast;
 use ast::{MethodImplItem, RegionTyParamBound, TraitTyParamBound, TraitBoundModifier};
 use ast::{RequiredMethod, ProvidedMethod, TypeImplItem, TypeTraitItem};
-use ast::{ClosureKind};
 use ast_util;
 use owned_slice::OwnedSlice;
 use attr::{AttrMetaMethods, AttributeMethods};
@@ -350,7 +348,7 @@ pub fn method_to_string(p: &ast::Method) -> String {
 }
 
 pub fn fn_block_to_string(p: &ast::FnDecl) -> String {
-    $to_string(|s| s.print_fn_block_args(p, None))
+    $to_string(|s| s.print_fn_block_args(p))
 }
 
 pub fn path_to_string(p: &ast::Path) -> String {
@@ -1747,10 +1745,10 @@ pub fn print_expr(&mut self, expr: &ast::Expr) -> IoResult<()> {
                 }
                 try!(self.bclose_(expr.span, indent_unit));
             }
-            ast::ExprClosure(capture_clause, opt_kind, ref decl, ref body) => {
+            ast::ExprClosure(capture_clause, ref decl, ref body) => {
                 try!(self.print_capture_clause(capture_clause));
 
-                try!(self.print_fn_block_args(&**decl, opt_kind));
+                try!(self.print_fn_block_args(&**decl));
                 try!(space(&mut self.s));
 
                 if !body.stmts.is_empty() || !body.expr.is_some() {
@@ -2350,16 +2348,9 @@ pub fn print_fn_args_and_ret(&mut self, decl: &ast::FnDecl,
 
     pub fn print_fn_block_args(
             &mut self,
-            decl: &ast::FnDecl,
-            closure_kind: Option<ClosureKind>)
+            decl: &ast::FnDecl)
             -> IoResult<()> {
         try!(word(&mut self.s, "|"));
-        match closure_kind {
-            None => {}
-            Some(FnClosureKind) => try!(self.word_space("&:")),
-            Some(FnMutClosureKind) => try!(self.word_space("&mut:")),
-            Some(FnOnceClosureKind) => try!(self.word_space(":")),
-        }
         try!(self.print_fn_args(decl, None));
         try!(word(&mut self.s, "|"));
 
index bd84306fe17e06047ea235ddbe00cad15af31093..fbcfcaadf12b71c29782e0ae4d5944b92043232a 100644 (file)
@@ -836,7 +836,7 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr) {
                 visitor.visit_arm(arm)
             }
         }
-        ExprClosure(_, _, ref function_declaration, ref body) => {
+        ExprClosure(_, ref function_declaration, ref body) => {
             visitor.visit_fn(FkFnBlock,
                              &**function_declaration,
                              &**body,
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 3679557d06bb761b7f69424b0dc9e5c715163197..7ac3925fb24766385d7958742fa5dc49d84b44f0 100644 (file)
@@ -11,6 +11,7 @@
 #![crate_type = "lib"]
 #![feature(staged_api)]
 #![staged_api]
+#![stable(feature = "lint_stability", since = "1.0.0")]
 
 #[stable(feature = "test_feature", since = "1.0.0")]
 #[deprecated(since = "1.0.0")]
@@ -31,8 +32,6 @@ pub fn unstable() {}
 #[unstable(feature = "test_feature", reason = "text")]
 pub fn unstable_text() {}
 
-pub fn unmarked() {}
-
 #[stable(feature = "rust1", since = "1.0.0")]
 pub fn stable() {}
 #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -61,8 +60,6 @@ pub fn method_unstable(&self) {}
     #[unstable(feature = "test_feature", reason = "text")]
     pub fn method_unstable_text(&self) {}
 
-    pub fn method_unmarked(&self) {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn method_stable(&self) {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -79,6 +76,7 @@ pub fn method_frozen(&self) {}
     pub fn method_frozen_text(&self) {}
 }
 
+#[stable(feature = "test_feature", since = "1.0.0")]
 pub trait Trait {
     #[stable(feature = "test_feature", since = "1.0.0")]
     #[deprecated(since = "1.0.0")]
@@ -99,8 +97,6 @@ fn trait_unstable(&self) {}
     #[unstable(feature = "test_feature", reason = "text")]
     fn trait_unstable_text(&self) {}
 
-    fn trait_unmarked(&self) {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     fn trait_stable(&self) {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -130,7 +126,6 @@ pub struct DeprecatedStruct { pub i: int }
 pub struct DeprecatedUnstableStruct { pub i: int }
 #[unstable(feature = "test_feature")]
 pub struct UnstableStruct { pub i: int }
-pub struct UnmarkedStruct { pub i: int }
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableStruct { pub i: int }
 
@@ -142,10 +137,10 @@ pub struct StableStruct { pub i: int }
 pub struct DeprecatedUnstableUnitStruct;
 #[unstable(feature = "test_feature")]
 pub struct UnstableUnitStruct;
-pub struct UnmarkedUnitStruct;
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableUnitStruct;
 
+#[stable(feature = "test_feature", since = "1.0.0")]
 pub enum Enum {
     #[stable(feature = "test_feature", since = "1.0.0")]
     #[deprecated(since = "1.0.0")]
@@ -156,7 +151,6 @@ pub enum Enum {
     #[unstable(feature = "test_feature")]
     UnstableVariant,
 
-    UnmarkedVariant,
     #[stable(feature = "rust1", since = "1.0.0")]
     StableVariant,
 }
@@ -169,7 +163,6 @@ pub enum Enum {
 pub struct DeprecatedUnstableTupleStruct(pub int);
 #[unstable(feature = "test_feature")]
 pub struct UnstableTupleStruct(pub int);
-pub struct UnmarkedTupleStruct(pub int);
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct StableTupleStruct(pub int);
 
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 12555c550729ca13c405ccd11cd14e5c8572c169..7033f5caef6c6a22d7e144861dfa008ade2f4815 100644 (file)
@@ -8,34 +8,38 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(unboxed_closures, overloaded_calls)]
+#![feature(unboxed_closures)]
 
 // Tests that we can't assign to or mutably borrow upvars from `Fn`
 // closures (issue #17780)
 
 fn set(x: &mut usize) { *x = 5; }
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn main() {
     // By-ref captures
     {
         let mut x = 0us;
-        let _f = |&:| x = 42; //~ ERROR cannot assign
+        let _f = to_fn(|| x = 42); //~ ERROR cannot assign
 
         let mut y = 0us;
-        let _g = |&:| set(&mut y); //~ ERROR cannot borrow
+        let _g = to_fn(|| set(&mut y)); //~ ERROR cannot borrow
 
         let mut z = 0us;
-        let _h = |&mut:| { set(&mut z); |&:| z = 42; }; //~ ERROR cannot assign
+        let _h = to_fn_mut(|| { set(&mut z); to_fn(|| z = 42); }); //~ ERROR cannot assign
     }
+
     // By-value captures
     {
         let mut x = 0us;
-        let _f = move |&:| x = 42; //~ ERROR cannot assign
+        let _f = to_fn(move || x = 42); //~ ERROR cannot assign
 
         let mut y = 0us;
-        let _g = move |&:| set(&mut y); //~ ERROR cannot borrow
+        let _g = to_fn(move || set(&mut y)); //~ ERROR cannot borrow
 
         let mut z = 0us;
-        let _h = move |&mut:| { set(&mut z); move |&:| z = 42; }; //~ ERROR cannot assign
+        let _h = to_fn_mut(move || { set(&mut z); to_fn(move || z = 42); }); //~ ERROR cannot assign
     }
 }
index b0d546cd5c803584846c8cc52100894542708e28..a1708e7f497286c81a4d6007aafb13c7ea4420c0 100644 (file)
@@ -8,11 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax,unboxed_closures)]
+
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 pub fn main() {
     let bar = box 3;
-    let _g = |&mut:| {
-        let _h = move |:| -> isize { *bar }; //~ ERROR cannot move out of captured outer variable
-    };
+    let _g = to_fn_mut(|| {
+        let _h = to_fn_once(move || -> isize { *bar }); //~ ERROR cannot move out of
+    });
 }
index 2951c63828d5c3d34774237a85c616d64120ae84..738755855c0703211532b79c82ce43e92581bebc 100644 (file)
@@ -8,12 +8,16 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(unboxed_closures)]
+
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
     let x = 1;
-    move|:| { x = 2; };
+    to_fn_once(move|:| { x = 2; });
     //~^ ERROR: cannot assign to immutable captured outer variable
 
     let s = std::old_io::stdin();
-    move|:| { s.read_to_end(); };
+    to_fn_once(move|:| { s.read_to_end(); });
     //~^ ERROR: cannot borrow immutable captured outer variable
 }
diff --git a/src/test/compile-fail/deriving-span-Rand-enum-struct-variant.rs b/src/test/compile-fail/deriving-span-Rand-enum-struct-variant.rs
deleted file mode 100644 (file)
index 4d3542c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 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.
-
-// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py'
-
-extern crate rand;
-
-
-struct Error;
-
-#[derive(Rand)]
-enum Enum {
-   A {
-     x: Error //~ ERROR
-   }
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/deriving-span-Rand-enum.rs b/src/test/compile-fail/deriving-span-Rand-enum.rs
deleted file mode 100644 (file)
index dcfdbdc..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright 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.
-
-// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py'
-
-extern crate rand;
-
-
-struct Error;
-
-#[derive(Rand)]
-enum Enum {
-   A(
-     Error //~ ERROR
-     )
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/deriving-span-Rand-struct.rs b/src/test/compile-fail/deriving-span-Rand-struct.rs
deleted file mode 100644 (file)
index 73d8969..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 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.
-
-// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py'
-
-extern crate rand;
-
-
-struct Error;
-
-#[derive(Rand)]
-struct Struct {
-    x: Error //~ ERROR
-}
-
-fn main() {}
diff --git a/src/test/compile-fail/deriving-span-Rand-tuple-struct.rs b/src/test/compile-fail/deriving-span-Rand-tuple-struct.rs
deleted file mode 100644 (file)
index 8038bf3..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 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.
-
-// This file was auto-generated using 'src/etc/generate-deriving-span-tests.py'
-
-extern crate rand;
-
-
-struct Error;
-
-#[derive(Rand)]
-struct Struct(
-    Error //~ ERROR
-);
-
-fn main() {}
index 69f7b46009c38db438ad2c4829353ef590ef2dcf..df4dab2552e7de8922613d5f6a683a4a338778b3 100644 (file)
@@ -8,12 +8,14 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
+
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 
 fn main() {
     let r = {
         let x = box 42;
-        let f = move|:| &x; //~ ERROR: `x` does not live long enough
+        let f = to_fn_once(move|| &x); //~ ERROR: `x` does not live long enough
         f()
     };
 
index c06082de3cd08ae10ce68cc83320de81f993674c..40d446b91a5a8b659d56cb79dcbec7b202c8249d 100644 (file)
@@ -8,14 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
 
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
 fn do_it(x: &isize) { }
 
 fn main() {
     let x = box 22;
-    let f = move|:| do_it(&*x);
-    (move|:| {
+    let f = to_fn_once(move|| do_it(&*x));
+    to_fn_once(move|| {
         f();
         f();
         //~^ ERROR: use of moved value: `f`
index 5b093a8556cdd112f16300bf7dd4d099ca11440f..4cf75bf15de275bd44262c8812893786967c4b7f 100644 (file)
@@ -20,7 +20,7 @@
 #![staged_api]
 
 #[macro_use]
-extern crate lint_stability; //~ ERROR: use of unmarked library feature
+extern crate lint_stability;
 
 mod cross_crate {
     extern crate stability_cfg1;
@@ -61,10 +61,6 @@ fn test() {
         foo.method_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
 
-        unmarked(); //~ ERROR use of unmarked library feature
-        foo.method_unmarked(); //~ ERROR use of unmarked library feature
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
-
         stable();
         foo.method_stable();
         foo.trait_stable();
@@ -77,28 +73,24 @@ fn test() {
         let _ = DeprecatedUnstableStruct { i: 0 }; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableStruct { i: 0 }; //~ WARNING use of unstable library feature
-        let _ = UnmarkedStruct { i: 0 }; //~ ERROR use of unmarked library feature
         let _ = StableStruct { i: 0 };
 
         let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
         let _ = DeprecatedUnstableUnitStruct; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableUnitStruct; //~ WARNING use of unstable library feature
-        let _ = UnmarkedUnitStruct; //~ ERROR use of unmarked library feature
         let _ = StableUnitStruct;
 
         let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
         let _ = Enum::DeprecatedUnstableVariant; //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = Enum::UnstableVariant; //~ WARNING use of unstable library feature
-        let _ = Enum::UnmarkedVariant; //~ ERROR use of unmarked library feature
         let _ = Enum::StableVariant;
 
         let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
         let _ = DeprecatedUnstableTupleStruct (1); //~ ERROR use of deprecated item
         //~^ WARNING use of unstable library feature
         let _ = UnstableTupleStruct (1); //~ WARNING use of unstable library feature
-        let _ = UnmarkedTupleStruct (1); //~ ERROR use of unmarked library feature
         let _ = StableTupleStruct (1);
 
         // At the moment, the lint checker only checks stability in
@@ -123,7 +115,6 @@ fn test_method_param<F: Trait>(foo: F) {
         //~^ WARNING use of unstable library feature
         foo.trait_unstable(); //~ WARNING use of unstable library feature
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
         foo.trait_stable();
     }
 
@@ -136,7 +127,6 @@ fn test_method_object(foo: &Trait) {
         //~^ WARNING use of unstable library feature
         foo.trait_unstable(); //~ WARNING use of unstable library feature
         foo.trait_unstable_text(); //~ WARNING use of unstable library feature 'test_feature': text
-        foo.trait_unmarked(); //~ ERROR use of unmarked library feature
         foo.trait_stable();
     }
 
@@ -183,8 +173,6 @@ pub fn unstable() {}
     #[unstable(feature = "test_feature", reason = "text")]
     pub fn unstable_text() {}
 
-    pub fn unmarked() {}
-
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn stable() {}
     #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -206,8 +194,6 @@ pub fn method_unstable(&self) {}
         #[unstable(feature = "test_feature", reason = "text")]
         pub fn method_unstable_text(&self) {}
 
-        pub fn method_unmarked(&self) {}
-
         #[stable(feature = "rust1", since = "1.0.0")]
         pub fn method_stable(&self) {}
         #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -227,8 +213,6 @@ fn trait_unstable(&self) {}
         #[unstable(feature = "test_feature", reason = "text")]
         fn trait_unstable_text(&self) {}
 
-        fn trait_unmarked(&self) {}
-
         #[stable(feature = "rust1", since = "1.0.0")]
         fn trait_stable(&self) {}
         #[stable(feature = "rust1", since = "1.0.0", reason = "text")]
@@ -242,7 +226,6 @@ impl Trait for MethodTester {}
     pub struct DeprecatedStruct { i: isize }
     #[unstable(feature = "test_feature")]
     pub struct UnstableStruct { i: isize }
-    pub struct UnmarkedStruct { i: isize }
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableStruct { i: isize }
 
@@ -251,7 +234,6 @@ pub struct StableStruct { i: isize }
     pub struct DeprecatedUnitStruct;
     #[unstable(feature = "test_feature")]
     pub struct UnstableUnitStruct;
-    pub struct UnmarkedUnitStruct;
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableUnitStruct;
 
@@ -262,7 +244,6 @@ pub enum Enum {
         #[unstable(feature = "test_feature")]
         UnstableVariant,
 
-        UnmarkedVariant,
         #[stable(feature = "rust1", since = "1.0.0")]
         StableVariant,
     }
@@ -272,7 +253,6 @@ pub enum Enum {
     pub struct DeprecatedTupleStruct(isize);
     #[unstable(feature = "test_feature")]
     pub struct UnstableTupleStruct(isize);
-    pub struct UnmarkedTupleStruct(isize);
     #[stable(feature = "rust1", since = "1.0.0")]
     pub struct StableTupleStruct(isize);
 
@@ -299,10 +279,6 @@ fn test() {
         foo.method_unstable_text();
         foo.trait_unstable_text();
 
-        unmarked();
-        foo.method_unmarked();
-        foo.trait_unmarked();
-
         stable();
         foo.method_stable();
         foo.trait_stable();
@@ -313,22 +289,18 @@ fn test() {
 
         let _ = DeprecatedStruct { i: 0 }; //~ ERROR use of deprecated item
         let _ = UnstableStruct { i: 0 };
-        let _ = UnmarkedStruct { i: 0 };
         let _ = StableStruct { i: 0 };
 
         let _ = DeprecatedUnitStruct; //~ ERROR use of deprecated item
         let _ = UnstableUnitStruct;
-        let _ = UnmarkedUnitStruct;
         let _ = StableUnitStruct;
 
         let _ = Enum::DeprecatedVariant; //~ ERROR use of deprecated item
         let _ = Enum::UnstableVariant;
-        let _ = Enum::UnmarkedVariant;
         let _ = Enum::StableVariant;
 
         let _ = DeprecatedTupleStruct (1); //~ ERROR use of deprecated item
         let _ = UnstableTupleStruct (1);
-        let _ = UnmarkedTupleStruct (1);
         let _ = StableTupleStruct (1);
     }
 
@@ -337,7 +309,6 @@ fn test_method_param<F: Trait>(foo: F) {
         foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
         foo.trait_unstable();
         foo.trait_unstable_text();
-        foo.trait_unmarked();
         foo.trait_stable();
     }
 
@@ -346,7 +317,6 @@ fn test_method_object(foo: &Trait) {
         foo.trait_deprecated_text(); //~ ERROR use of deprecated item: text
         foo.trait_unstable();
         foo.trait_unstable_text();
-        foo.trait_unmarked();
         foo.trait_stable();
     }
 
index 03bb7cc1f15e049091b6916e637260703e3ccf6f..ada0cd2bc98f82cf035e817aa62697cebecdb9af 100644 (file)
@@ -12,6 +12,7 @@
 
 #![deny(unused_extern_crates)]
 #![allow(unused_variables)]
+#![allow(deprecated)]
 #![feature(libc)]
 #![feature(collections)]
 #![feature(rand)]
index ce1b372a4c11ea901bc39ac9d0838d77d5703bc4..42a0f41dd97c3921ffdc50b02e8e461eac9fae46 100644 (file)
@@ -15,7 +15,6 @@
 #![feature(trace_macros, concat_idents)]
 
 #[derive(Default, //~ ERROR
-           Rand, //~ ERROR
            Zero)] //~ ERROR
 enum CantDeriveThose {}
 
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());
diff --git a/src/test/compile-fail/missing-stability.rs b/src/test/compile-fail/missing-stability.rs
new file mode 100644 (file)
index 0000000..14dd983
--- /dev/null
@@ -0,0 +1,33 @@
+// 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.
+
+// Checks that exported items without stability attributes cause an error
+
+#![crate_type="lib"]
+#![feature(staged_api)]
+#![staged_api]
+
+pub fn unmarked() {
+    //~^ ERROR This node does not have a stability attribute
+    ()
+}
+
+#[unstable(feature = "foo")]
+pub mod foo {
+    // #[unstable] is inherited
+    pub fn unmarked() {}
+}
+
+#[stable(feature = "bar", since="1.0.0")]
+pub mod bar {
+    // #[stable] is not inherited
+    pub fn unmarked() {}
+    //~^ ERROR This node does not have a stability attribute
+}
\ No newline at end of file
index 5dfe7f0c71f140dd01d6164b3b5e98acebbcd465..4251be36ab43805591025cea7e8a01b83f6294b2 100644 (file)
@@ -8,13 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-#![feature(box_syntax)]
+#![feature(box_syntax, unboxed_closures)]
 
 use std::usize;
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+
 fn test(_x: Box<usize>) {}
 
 fn main() {
     let i = box 3;
-    let _f = |&:| test(i); //~ ERROR cannot move out
+    let _f = to_fn(|| test(i)); //~ ERROR cannot move out
 }
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 182c632d062613977fbf2e9dd0394e90a9cc417f..2d559794919817754daa3e1c606253d58c39afd2 100644 (file)
 
 #![feature(unboxed_closures)]
 
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
-    let f = move|:| ();
+    let f = to_fn_once(move|| ());
     f();
     f(); //~ ERROR use of moved value
 }
index 1312b42fb82d4ccdeaf33e2cb2a738bc415fa182..224cbc2bef3245c624a949cc1e382cd92304417b 100644 (file)
 // if the upvar is captured by ref or the closure takes self by
 // reference.
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+fn to_fn_once<A,F:FnOnce<A>>(f: F) -> F { f }
+
 fn main() {
     // By-ref cases
     {
         let x = box 0us;
-        let f = |&:| drop(x); //~ ERROR cannot move
+        let f = to_fn(|| drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = |&mut:| drop(x); //~ ERROR cannot move
+        let f = to_fn_mut(|| drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = |:| drop(x); // OK -- FnOnce
+        let f = to_fn_once(|| drop(x)); // OK -- FnOnce
     }
     // By-value cases
     {
         let x = box 0us;
-        let f = move |&:| drop(x); //~ ERROR cannot move
+        let f = to_fn(move || drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = move |&mut:| drop(x); //~ ERROR cannot move
+        let f = to_fn_mut(move || drop(x)); //~ ERROR cannot move
     }
     {
         let x = box 0us;
-        let f = move |:| drop(x); // this one is ok
+        let f = to_fn_once(move || drop(x)); // this one is ok
     }
 }
index 96c7948dcb0469253d781a411a6e85ab3bfda608..650bb17bb7758f9ce60d81d2dcc7ec38ff7cab7b 100644 (file)
 // as `mut` through a closure. Also test that we CAN mutate a moved copy,
 // unless this is a `Fn` closure. Issue #16749.
 
+#![feature(unboxed_closures)]
+
 use std::mem;
 
+fn to_fn<A,F:Fn<A>>(f: F) -> F { f }
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn a() {
     let n = 0u8;
-    let mut f = |&mut:| { //~ ERROR closure cannot assign
+    let mut f = to_fn_mut(|| { //~ ERROR closure cannot assign
         n += 1;
-    };
+    });
 }
 
 fn b() {
     let mut n = 0u8;
-    let mut f = |&mut:| {
+    let mut f = to_fn_mut(|| {
         n += 1; // OK
-    };
+    });
 }
 
 fn c() {
     let n = 0u8;
-    let mut f = move |&mut:| {
+    let mut f = to_fn_mut(move || {
         // If we just did a straight-forward desugaring, this would
         // compile, but we do something a bit more subtle, and hence
         // we get an error.
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn d() {
     let mut n = 0u8;
-    let mut f = move |&mut:| {
+    let mut f = to_fn_mut(move || {
         n += 1; // OK
-    };
+    });
 }
 
 fn e() {
     let n = 0u8;
-    let mut f = move |&:| {
+    let mut f = to_fn(move || {
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn f() {
     let mut n = 0u8;
-    let mut f = move |&:| {
+    let mut f = to_fn(move || {
         n += 1; //~ ERROR cannot assign
-    };
+    });
 }
 
 fn main() { }
index 8d3721f28db50ec5cf32b12cfee562e1b30e4066..f430e9fc7590228fba05867ea5a3e855a85f8188 100644 (file)
 
 #![feature(unboxed_closures)]
 
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn main() {
-    let mut_ = |&mut: x| x;
+    let mut_ = to_fn_mut(|x| x);
     mut_.call((0, )); //~ ERROR does not implement any method in scope named `call`
 }
 
index 305dd33e5a05a950b03280e36cc29675ff027a6b..c2a2e5162ace070a12c18aa6383f7cc9078ab323 100644 (file)
 
 use std::ops::FnMut;
 
+fn to_fn_mut<A,F:FnMut<A>>(f: F) -> F { f }
+
 fn call_it<F:FnMut(isize,isize)->isize>(y: isize, mut f: F) -> isize {
     f(2, y)
 }
 
 pub fn main() {
-    let f = |&mut: x: usize, y: isize| -> isize { (x as isize) + y };
+    let f = to_fn_mut(|x: usize, y: isize| -> isize { (x as isize) + y });
     let z = call_it(3, f);
     //~^ ERROR type mismatch
     //~| ERROR type mismatch
diff --git a/src/test/compile-fail/unboxed-closures-wrong-trait.rs b/src/test/compile-fail/unboxed-closures-wrong-trait.rs
deleted file mode 100644 (file)
index 2ada0dd..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 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.
-
-#![feature(lang_items, overloaded_calls, unboxed_closures)]
-
-fn c<F:Fn(isize, isize) -> isize>(f: F) -> isize {
-    f(5, 6)
-}
-
-fn main() {
-    let z: isize = 7;
-    assert_eq!(c(|&mut: x: isize, y| x + y + z), 10);
-    //~^ ERROR not implemented
-    //~| ERROR not implemented
-}
-
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 893003dd997226171d8ce39966524097eb9bae40..3bd0273216de31e352315a0d7dd93e9dfa7272b5 100644 (file)
@@ -9,11 +9,11 @@
 // except according to those terms.
 
 
-fn foo(i: int) -> int { i + 1 }
+fn foo(i: isize) -> isize { i + 1 }
 
 fn apply<A, F>(f: F, v: A) -> A where F: FnOnce(A) -> A { f(v) }
 
 pub fn main() {
-    let f = {|i| foo(i)};
+    let f = {|i| foo(i)};
     assert_eq!(apply(f, 2), 3);
 }
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 0cdd4d3889c06fd68d07bcd0d849badcd3094f2a..0cd8c13a4e10a60644ec0c80d887de9f236d1919 100644 (file)
@@ -14,9 +14,9 @@
 #![feature(box_syntax)]
 #![feature(unboxed_closures)]
 
-struct A { a: Box<int> }
+struct A { a: Box<isize> }
 
-fn foo() -> Box<FnMut() -> int + 'static> {
+fn foo() -> Box<FnMut() -> isize + 'static> {
     let k = box 22;
     let _u = A {a: k.clone()};
     let result  = |&mut:| 22;
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();
index f2eddd84af83252009bc8e96f81fcaa1329e8f6a..8e3d44df798a7679333ad85536e334b4d73c906c 100644 (file)
@@ -11,7 +11,7 @@
 #![feature(unboxed_closures)]
 
 fn main() {
-    let mut zero = |&mut:| {};
-    let () = zero.call_mut(());
+    let mut zero = || {};
+    let () = zero();
 }