about summary refs log tree commit diff
path: root/src/libcore
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-08-24 15:28:43 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-08-24 15:51:16 -0700
commitc284b8b1dc348ab8b9c82350dd1b4e53fac1225c (patch)
tree99de39b149969275f6f9ddebd7a9f555d91c5bff /src/libcore
parenta8f1bee4574b8427a052e2fad93a90839288584b (diff)
Start using core::path2::Path in a lot of places.
Diffstat (limited to 'src/libcore')
-rw-r--r--src/libcore/core.rc2
-rw-r--r--src/libcore/core.rs10
-rw-r--r--src/libcore/io.rs45
-rw-r--r--src/libcore/os.rs248
-rw-r--r--src/libcore/path2.rs294
5 files changed, 318 insertions, 281 deletions
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index 4b1ace5651b..84c0568797c 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -54,7 +54,7 @@ export send_map;
 export hash;
 export cmp;
 export num;
-export path;
+export path, path2;
 export managed;
 
 // NDM seems to be necessary for resolve to work
diff --git a/src/libcore/core.rs b/src/libcore/core.rs
index 2f7ae426517..c95a42ea3ec 100644
--- a/src/libcore/core.rs
+++ b/src/libcore/core.rs
@@ -4,7 +4,12 @@
 
 import option::{some, none};
 import option = option::option;
-import Path = path::Path;
+
+import Path = path2::Path;
+import GenericPath = path2::GenericPath;
+import WindowsPath = path2::WindowsPath;
+import PosixPath = path2::PosixPath;
+
 import tuple::{TupleOps, ExtendedTupleOps};
 import str::{StrSlice, UniqueStr};
 import vec::{ConstVector, CopyableVector, ImmutableVector};
@@ -14,7 +19,8 @@ import num::Num;
 import ptr::Ptr;
 import to_str::ToStr;
 
-export Path, option, some, none, unreachable;
+export Path, WindowsPath, PosixPath, GenericPath;
+export option, some, none, unreachable;
 export extensions;
 // The following exports are the extension impls for numeric types
 export Num, Times, TimesIx;
diff --git a/src/libcore/io.rs b/src/libcore/io.rs
index a2b02f55b22..452aae49984 100644
--- a/src/libcore/io.rs
+++ b/src/libcore/io.rs
@@ -257,13 +257,14 @@ fn FILE_reader(f: *libc::FILE, cleanup: bool) -> Reader {
 
 fn stdin() -> Reader { rustrt::rust_get_stdin() as Reader }
 
-fn file_reader(path: ~str) -> result<Reader, ~str> {
-    let f = os::as_c_charp(path, |pathbuf| {
-        os::as_c_charp(~"r", |modebuf|
+fn file_reader(path: &Path) -> result<Reader, ~str> {
+    let f = os::as_c_charp(path.to_str(), |pathbuf| {
+        os::as_c_charp("r", |modebuf|
             libc::fopen(pathbuf, modebuf)
         )
     });
-    return if f as uint == 0u { result::err(~"error opening " + path) }
+    return if f as uint == 0u { result::err(~"error opening "
+                                            + path.to_str()) }
     else {
         result::ok(FILE_reader(f, true))
     }
@@ -412,7 +413,7 @@ fn fd_writer(fd: fd_t, cleanup: bool) -> Writer {
 }
 
 
-fn mk_file_writer(path: ~str, flags: ~[FileFlag])
+fn mk_file_writer(path: &Path, flags: ~[FileFlag])
     -> result<Writer, ~str> {
 
     #[cfg(windows)]
@@ -430,12 +431,13 @@ fn mk_file_writer(path: ~str, flags: ~[FileFlag])
           NoFlag => ()
         }
     }
-    let fd = do os::as_c_charp(path) |pathbuf| {
+    let fd = do os::as_c_charp(path.to_str()) |pathbuf| {
         libc::open(pathbuf, fflags,
                    (S_IRUSR | S_IWUSR) as c_int)
     };
     if fd < (0 as c_int) {
-        result::err(fmt!("error opening %s: %s", path, os::last_os_error()))
+        result::err(fmt!("error opening %s: %s", path.to_str(),
+                         os::last_os_error()))
     } else {
         result::ok(fd_writer(fd, true))
     }
@@ -614,19 +616,20 @@ impl<T: Writer> T : WriterUtil {
     fn write_u8(n: u8) { self.write(&[n]) }
 }
 
-fn file_writer(path: ~str, flags: ~[FileFlag]) -> result<Writer, ~str> {
+fn file_writer(path: &Path, flags: ~[FileFlag]) -> result<Writer, ~str> {
     result::chain(mk_file_writer(path, flags), |w| result::ok(w))
 }
 
 
 // FIXME: fileflags // #2004
-fn buffered_file_writer(path: ~str) -> result<Writer, ~str> {
-    let f = do os::as_c_charp(path) |pathbuf| {
-        do os::as_c_charp(~"w") |modebuf| {
+fn buffered_file_writer(path: &Path) -> result<Writer, ~str> {
+    let f = do os::as_c_charp(path.to_str()) |pathbuf| {
+        do os::as_c_charp("w") |modebuf| {
             libc::fopen(pathbuf, modebuf)
         }
     };
-    return if f as uint == 0u { result::err(~"error opening " + path) }
+    return if f as uint == 0u { result::err(~"error opening "
+                                            + path.to_str()) }
     else { result::ok(FILE_writer(f, true)) }
 }
 
@@ -709,19 +712,19 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: SeekStyle) ->
     return bpos as uint;
 }
 
-fn read_whole_file_str(file: ~str) -> result<~str, ~str> {
+fn read_whole_file_str(file: &Path) -> result<~str, ~str> {
     result::chain(read_whole_file(file), |bytes| {
         if str::is_utf8(bytes) {
             result::ok(str::from_bytes(bytes))
        } else {
-           result::err(file + ~" is not UTF-8")
+           result::err(file.to_str() + ~" is not UTF-8")
        }
     })
 }
 
 // FIXME (#2004): implement this in a low-level way. Going through the
 // abstractions is pointless.
-fn read_whole_file(file: ~str) -> result<~[u8], ~str> {
+fn read_whole_file(file: &Path) -> result<~[u8], ~str> {
     result::chain(file_reader(file), |rdr| {
         result::ok(rdr.read_whole_stream())
     })
@@ -810,7 +813,7 @@ mod tests {
 
     #[test]
     fn test_simple() {
-        let tmpfile: ~str = ~"tmp/lib-io-test-simple.tmp";
+        let tmpfile = &Path("tmp/lib-io-test-simple.tmp");
         log(debug, tmpfile);
         let frood: ~str =
             ~"A hoopy frood who really knows where his towel is.";
@@ -881,7 +884,7 @@ mod tests {
 
     #[test]
     fn file_reader_not_exist() {
-        match io::file_reader(~"not a file") {
+        match io::file_reader(&Path("not a file")) {
           result::err(e) => {
             assert e == ~"error opening not a file";
           }
@@ -891,9 +894,9 @@ mod tests {
 
     #[test]
     fn file_writer_bad_name() {
-        match io::file_writer(~"?/?", ~[]) {
+        match io::file_writer(&Path("?/?"), ~[]) {
           result::err(e) => {
-            assert str::starts_with(e, ~"error opening ?/?");
+            assert str::starts_with(e, "error opening");
           }
           result::ok(_) => fail
         }
@@ -901,9 +904,9 @@ mod tests {
 
     #[test]
     fn buffered_file_writer_bad_name() {
-        match io::buffered_file_writer(~"?/?") {
+        match io::buffered_file_writer(&Path("?/?")) {
           result::err(e) => {
-            assert e == ~"error opening ?/?";
+            assert str::starts_with(e, "error opening");
           }
           result::ok(_) => fail
         }
diff --git a/src/libcore/os.rs b/src/libcore/os.rs
index 749cb246af2..4fb3e744235 100644
--- a/src/libcore/os.rs
+++ b/src/libcore/os.rs
@@ -1,3 +1,7 @@
+// NB: transitionary, de-mode-ing.
+#[forbid(deprecated_mode)];
+#[forbid(deprecated_pattern)];
+
 /*!
  * Higher-level interfaces to libc::* functions and operating system services.
  *
@@ -16,16 +20,12 @@
  * to write OS-ignorant code by default.
  */
 
-#[forbid(deprecated_mode)];
-#[forbid(deprecated_pattern)];
-
 import libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
               mode_t, pid_t, FILE};
 import libc::{close, fclose};
 
 import option::{some, none};
 
-import getcwd = rustrt::rust_getcwd;
 import consts::*;
 import task::TaskBuilder;
 
@@ -56,7 +56,11 @@ extern mod rustrt {
 
 const tmpbuf_sz : uint = 1000u;
 
-fn as_c_charp<T>(+s: ~str, f: fn(*c_char) -> T) -> T {
+fn getcwd() -> Path {
+    Path(rustrt::rust_getcwd())
+}
+
+fn as_c_charp<T>(s: &str, f: fn(*c_char) -> T) -> T {
     str::as_c_str(s, |b| f(b as *c_char))
 }
 
@@ -106,7 +110,7 @@ mod win32 {
         return res;
     }
 
-    fn as_utf16_p<T>(+s: ~str, f: fn(*u16) -> T) -> T {
+    fn as_utf16_p<T>(s: &str, f: fn(*u16) -> T) -> T {
         let mut t = str::to_utf16(s);
         // Null terminate before passing on.
         t += ~[0u16];
@@ -114,11 +118,11 @@ mod win32 {
     }
 }
 
-fn getenv(+n: ~str) -> option<~str> {
+fn getenv(n: &str) -> option<~str> {
     global_env::getenv(n)
 }
 
-fn setenv(+n: ~str, +v: ~str) {
+fn setenv(n: &str, v: &str) {
     global_env::setenv(n, v)
 }
 
@@ -143,17 +147,20 @@ mod global_env {
         MsgEnv(comm::Chan<~[(~str,~str)]>)
     }
 
-    fn getenv(+n: ~str) -> option<~str> {
+    fn getenv(n: &str) -> option<~str> {
         let env_ch = get_global_env_chan();
         let po = comm::port();
-        comm::send(env_ch, MsgGetEnv(n, comm::chan(po)));
+        comm::send(env_ch, MsgGetEnv(str::from_slice(n),
+                                     comm::chan(po)));
         comm::recv(po)
     }
 
-    fn setenv(+n: ~str, +v: ~str) {
+    fn setenv(n: &str, v: &str) {
         let env_ch = get_global_env_chan();
         let po = comm::port();
-        comm::send(env_ch, MsgSetEnv(n, v, comm::chan(po)));
+        comm::send(env_ch, MsgSetEnv(str::from_slice(n),
+                                     str::from_slice(v),
+                                     comm::chan(po)));
         comm::recv(po)
     }
 
@@ -212,7 +219,7 @@ mod global_env {
         }
 
         #[cfg(unix)]
-        fn getenv(+n: ~str) -> option<~str> {
+        fn getenv(n: &str) -> option<~str> {
             unsafe {
                 let s = str::as_c_str(n, libc::getenv);
                 return if unsafe::reinterpret_cast(s) == 0 {
@@ -225,7 +232,7 @@ mod global_env {
         }
 
         #[cfg(windows)]
-        fn getenv(+n: ~str) -> option<~str> {
+        fn getenv(n: &str) -> option<~str> {
             import libc::types::os::arch::extra::*;
             import libc::funcs::extra::kernel32::*;
             import win32::*;
@@ -238,7 +245,7 @@ mod global_env {
 
 
         #[cfg(unix)]
-        fn setenv(+n: ~str, +v: ~str) {
+        fn setenv(n: &str, v: &str) {
 
             // FIXME: remove this when export globs work properly. #1238
             import libc::funcs::posix01::unistd::setenv;
@@ -251,7 +258,7 @@ mod global_env {
 
 
         #[cfg(windows)]
-        fn setenv(+n: ~str, +v: ~str) {
+        fn setenv(n: &str, v: &str) {
             // FIXME: remove imports when export globs work properly. #1238
             import libc::funcs::extra::kernel32::*;
             import win32::*;
@@ -266,7 +273,7 @@ mod global_env {
 }
 
 fn fdopen(fd: c_int) -> *FILE {
-    return do as_c_charp(~"r") |modebuf| {
+    return do as_c_charp("r") |modebuf| {
         libc::fdopen(fd, modebuf)
     };
 }
@@ -365,8 +372,8 @@ fn dup2(src: c_int, dst: c_int) -> c_int {
 }
 
 
-fn dll_filename(+base: ~str) -> ~str {
-    return pre() + base + dll_suffix();
+fn dll_filename(base: &str) -> ~str {
+    return pre() + str::from_slice(base) + dll_suffix();
 
     #[cfg(unix)]
     fn pre() -> ~str { ~"lib" }
@@ -379,7 +386,7 @@ fn dll_filename(+base: ~str) -> ~str {
 fn self_exe_path() -> option<Path> {
 
     #[cfg(target_os = "freebsd")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         unsafe {
             import libc::funcs::bsd44::*;
             import libc::consts::os::extra::*;
@@ -395,17 +402,17 @@ fn self_exe_path() -> option<Path> {
     }
 
     #[cfg(target_os = "linux")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         import libc::funcs::posix01::unistd::readlink;
         do fill_charp_buf() |buf, sz| {
-            do as_c_charp(~"/proc/self/exe") |proc_self_buf| {
+            do as_c_charp("/proc/self/exe") |proc_self_buf| {
                 readlink(proc_self_buf, buf, sz) != (-1 as ssize_t)
             }
         }
     }
 
     #[cfg(target_os = "macos")]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::*;
         do fill_charp_buf() |buf, sz| {
@@ -415,7 +422,7 @@ fn self_exe_path() -> option<Path> {
     }
 
     #[cfg(windows)]
-    fn load_self() -> option<Path> {
+    fn load_self() -> option<~str> {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::types::os::arch::extra::*;
         import libc::funcs::extra::kernel32::*;
@@ -426,7 +433,7 @@ fn self_exe_path() -> option<Path> {
     }
 
     do option::map(load_self()) |pth| {
-        path::dirname(pth) + path::path_sep()
+        Path(pth).dir_path()
     }
 }
 
@@ -447,7 +454,7 @@ fn self_exe_path() -> option<Path> {
 fn homedir() -> option<Path> {
     return match getenv(~"HOME") {
         some(p) => if !str::is_empty(p) {
-          some(p)
+          some(Path(p))
         } else {
           secondary()
         },
@@ -463,7 +470,7 @@ fn homedir() -> option<Path> {
     fn secondary() -> option<Path> {
         do option::chain(getenv(~"USERPROFILE")) |p| {
             if !str::is_empty(p) {
-                some(p)
+                some(Path(p))
             } else {
                 none
             }
@@ -484,13 +491,13 @@ fn homedir() -> option<Path> {
 fn tmpdir() -> Path {
     return lookup();
 
-    fn getenv_nonempty(+v: Path) -> option<Path> {
+    fn getenv_nonempty(v: &str) -> option<Path> {
         match getenv(v) {
             some(x) =>
                 if str::is_empty(x) {
                     none
                 } else {
-                    some(x)
+                    some(Path(x))
                 },
             _ => none
         }
@@ -498,28 +505,29 @@ fn tmpdir() -> Path {
 
     #[cfg(unix)]
     fn lookup() -> Path {
-        option::get_default(getenv_nonempty(~"TMPDIR"), ~"/tmp")
+        option::get_default(getenv_nonempty("TMPDIR"),
+                            Path("/tmp"))
     }
 
     #[cfg(windows)]
     fn lookup() -> Path {
         option::get_default(
-                    option::or(getenv_nonempty(~"TMP"),
-                    option::or(getenv_nonempty(~"TEMP"),
-                    option::or(getenv_nonempty(~"USERPROFILE"),
-                               getenv_nonempty(~"WINDIR")))),
-                    ~"C:\\Windows")
+                    option::or(getenv_nonempty("TMP"),
+                    option::or(getenv_nonempty("TEMP"),
+                    option::or(getenv_nonempty("USERPROFILE"),
+                               getenv_nonempty("WINDIR")))),
+                    Path("C:\\Windows"))
     }
 }
 /// Recursively walk a directory structure
-fn walk_dir(+p: Path, f: fn(Path) -> bool) {
+fn walk_dir(p: &Path, f: fn((&Path)) -> bool) {
 
     walk_dir_(p, f);
 
-    fn walk_dir_(+p: Path, f: fn(Path) -> bool) -> bool {
+    fn walk_dir_(p: &Path, f: fn((&Path)) -> bool) -> bool {
         let mut keepgoing = true;
         do list_dir(p).each |q| {
-            let path = path::connect(p, q);
+            let path = &p.push(q);
             if !f(path) {
                 keepgoing = false;
                 false
@@ -541,15 +549,15 @@ fn walk_dir(+p: Path, f: fn(Path) -> bool) {
 }
 
 /// Indicates whether a path represents a directory
-fn path_is_dir(+p: Path) -> bool {
-    do str::as_c_str(p) |buf| {
+fn path_is_dir(p: &Path) -> bool {
+    do str::as_c_str(p.to_str()) |buf| {
         rustrt::rust_path_is_dir(buf) != 0 as c_int
     }
 }
 
 /// Indicates whether a path exists
-fn path_exists(+p: Path) -> bool {
-    do str::as_c_str(p) |buf| {
+fn path_exists(p: &Path) -> bool {
+    do str::as_c_str(p.to_str()) |buf| {
         rustrt::rust_path_exists(buf) != 0 as c_int
     }
 }
@@ -566,58 +574,50 @@ fn path_exists(+p: Path) -> bool {
 // NB: this is here rather than in path because it is a form of environment
 // querying; what it does depends on the process working directory, not just
 // the input paths.
-fn make_absolute(+p: Path) -> Path {
-    if path::path_is_absolute(p) {
-        p
+fn make_absolute(p: &Path) -> Path {
+    if p.is_absolute {
+        copy *p
     } else {
-        path::connect(getcwd(), p)
+        getcwd().push_many(p.components)
     }
 }
 
 
 /// Creates a directory at the specified path
-fn make_dir(+p: Path, mode: c_int) -> bool {
+fn make_dir(p: &Path, mode: c_int) -> bool {
     return mkdir(p, mode);
 
     #[cfg(windows)]
-    fn mkdir(+p: Path, _mode: c_int) -> bool {
+    fn mkdir(p: &Path, _mode: c_int) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::types::os::arch::extra::*;
         import libc::funcs::extra::kernel32::*;
         import win32::*;
         // FIXME: turn mode into something useful? #2623
-        do as_utf16_p(p) |buf| {
+        do as_utf16_p(p.to_str()) |buf| {
             CreateDirectoryW(buf, unsafe { unsafe::reinterpret_cast(0) })
                 != (0 as BOOL)
         }
     }
 
     #[cfg(unix)]
-    fn mkdir(+p: Path, mode: c_int) -> bool {
-        do as_c_charp(p) |c| {
+    fn mkdir(p: &Path, mode: c_int) -> bool {
+        do as_c_charp(p.to_str()) |c| {
             libc::mkdir(c, mode as mode_t) == (0 as c_int)
         }
     }
 }
 
 /// Lists the contents of a directory
-fn list_dir(+p: Path) -> ~[~str] {
+fn list_dir(p: &Path) -> ~[~str] {
 
     #[cfg(unix)]
-    fn star(+p: ~str) -> ~str { p }
+    fn star(p: &Path) -> Path { copy *p }
 
     #[cfg(windows)]
-    fn star(+p: ~str) -> ~str {
-        let pl = str::len(p);
-        if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
-                        || p[pl - 1u] as char != path::consts::alt_path_sep) {
-            p + path::path_sep() + ~"*"
-        } else {
-            p + ~"*"
-        }
-    }
+    fn star(p: &Path) -> Path { p.push("*") }
 
-    do rustrt::rust_list_files(star(p)).filter |filename| {
+    do rustrt::rust_list_files(star(p).to_str()).filter |filename| {
         filename != ~"." && filename != ~".."
     }
 }
@@ -627,90 +627,84 @@ fn list_dir(+p: Path) -> ~[~str] {
  *
  * This version prepends each entry with the directory.
  */
-fn list_dir_path(+p: Path) -> ~[~str] {
-    let mut p = p;
-    let pl = str::len(p);
-    if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
-                    && p[pl - 1u] as char != path::consts::alt_path_sep) {
-        p += path::path_sep();
-    }
-    os::list_dir(p).map(|f| p + f)
+fn list_dir_path(p: &Path) -> ~[~Path] {
+    os::list_dir(p).map(|f| ~p.push(f))
 }
 
 /// Removes a directory at the specified path
-fn remove_dir(+p: Path) -> bool {
+fn remove_dir(p: &Path) -> bool {
    return rmdir(p);
 
     #[cfg(windows)]
-    fn rmdir(+p: Path) -> bool {
+    fn rmdir(p: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             RemoveDirectoryW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn rmdir(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn rmdir(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::rmdir(buf) == (0 as c_int)
         };
     }
 }
 
-fn change_dir(+p: Path) -> bool {
+fn change_dir(p: &Path) -> bool {
     return chdir(p);
 
     #[cfg(windows)]
-    fn chdir(+p: Path) -> bool {
+    fn chdir(p: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             SetCurrentDirectoryW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn chdir(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn chdir(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::chdir(buf) == (0 as c_int)
         };
     }
 }
 
 /// Copies a file from one location to another
-fn copy_file(+from: Path, +to: Path) -> bool {
+fn copy_file(from: &Path, to: &Path) -> bool {
     return do_copy_file(from, to);
 
     #[cfg(windows)]
-    fn do_copy_file(+from: Path, +to: Path) -> bool {
+    fn do_copy_file(from: &Path, to: &Path) -> bool {
         // FIXME: remove imports when export globs work properly. #1238
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(from) |fromp| {
-            do as_utf16_p(to) |top| {
+        return do as_utf16_p(from.to_str()) |fromp| {
+            do as_utf16_p(to.to_str()) |top| {
                 CopyFileW(fromp, top, (0 as BOOL)) != (0 as BOOL)
             }
         }
     }
 
     #[cfg(unix)]
-    fn do_copy_file(+from: Path, +to: Path) -> bool {
-        let istream = do as_c_charp(from) |fromp| {
-            do as_c_charp(~"rb") |modebuf| {
+    fn do_copy_file(from: &Path, to: &Path) -> bool {
+        let istream = do as_c_charp(from.to_str()) |fromp| {
+            do as_c_charp("rb") |modebuf| {
                 libc::fopen(fromp, modebuf)
             }
         };
         if istream as uint == 0u {
             return false;
         }
-        let ostream = do as_c_charp(to) |top| {
-            do as_c_charp(~"w+b") |modebuf| {
+        let ostream = do as_c_charp(to.to_str()) |top| {
+            do as_c_charp("w+b") |modebuf| {
                 libc::fopen(top, modebuf)
             }
         };
@@ -746,24 +740,24 @@ fn copy_file(+from: Path, +to: Path) -> bool {
 }
 
 /// Deletes an existing file
-fn remove_file(+p: Path) -> bool {
+fn remove_file(p: &Path) -> bool {
     return unlink(p);
 
     #[cfg(windows)]
-    fn unlink(+p: Path) -> bool {
+    fn unlink(p: &Path) -> bool {
         // FIXME (similar to Issue #2006): remove imports when export globs
         // work properly.
         import libc::funcs::extra::kernel32::*;
         import libc::types::os::arch::extra::*;
         import win32::*;
-        return do as_utf16_p(p) |buf| {
+        return do as_utf16_p(p.to_str()) |buf| {
             DeleteFileW(buf) != (0 as BOOL)
         };
     }
 
     #[cfg(unix)]
-    fn unlink(+p: Path) -> bool {
-        return do as_c_charp(p) |buf| {
+    fn unlink(p: &Path) -> bool {
+        return do as_c_charp(p.to_str()) |buf| {
             libc::unlink(buf) == (0 as c_int)
         };
     }
@@ -887,11 +881,7 @@ mod tests {
         log(debug, path);
 
         // Hard to test this function
-        if os::sysname() != ~"win32" {
-            assert str::starts_with(path, path::path_sep());
-        } else {
-            assert path[1] == ':' as u8;
-        }
+        assert path.is_absolute;
     }
 
     #[test]
@@ -926,10 +916,10 @@ mod tests {
     fn test() {
         assert (!path::path_is_absolute(~"test-path"));
 
-        log(debug, ~"Current working directory: " + getcwd());
+        log(debug, ~"Current working directory: " + getcwd().to_str());
 
-        log(debug, make_absolute(~"test-path"));
-        log(debug, make_absolute(~"/usr/bin"));
+        log(debug, make_absolute(&Path("test-path")));
+        log(debug, make_absolute(&Path("/usr/bin")));
     }
 
     #[test]
@@ -938,7 +928,7 @@ mod tests {
         let oldhome = getenv(~"HOME");
 
         setenv(~"HOME", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"");
         assert os::homedir() == none;
@@ -959,16 +949,16 @@ mod tests {
         assert os::homedir() == none;
 
         setenv(~"HOME", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"");
 
         setenv(~"USERPROFILE", ~"/home/MountainView");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         setenv(~"HOME", ~"/home/MountainView");
         setenv(~"USERPROFILE", ~"/home/PaloAlto");
-        assert os::homedir() == some(~"/home/MountainView");
+        assert os::homedir() == some(Path("/home/MountainView"));
 
         option::iter(oldhome, |s| setenv(~"HOME", s));
         option::iter(olduserprofile,
@@ -977,16 +967,18 @@ mod tests {
 
     #[test]
     fn tmpdir() {
-        assert !str::is_empty(os::tmpdir());
+        assert !str::is_empty(os::tmpdir().to_str());
     }
 
     // Issue #712
     #[test]
-    fn test_list_dir_no_invalid_memory_access() { os::list_dir(~"."); }
+    fn test_list_dir_no_invalid_memory_access() {
+        os::list_dir(&Path("."));
+    }
 
     #[test]
     fn list_dir() {
-        let dirs = os::list_dir(~".");
+        let dirs = os::list_dir(&Path("."));
         // Just assuming that we've got some contents in the current directory
         assert (vec::len(dirs) > 0u);
 
@@ -995,34 +987,34 @@ mod tests {
 
     #[test]
     fn path_is_dir() {
-        assert (os::path_is_dir(~"."));
-        assert (!os::path_is_dir(~"test/stdtest/fs.rs"));
+        assert (os::path_is_dir(&Path(".")));
+        assert (!os::path_is_dir(&Path("test/stdtest/fs.rs")));
     }
 
     #[test]
     fn path_exists() {
-        assert (os::path_exists(~"."));
-        assert (!os::path_exists(~"test/nonexistent-bogus-path"));
+        assert (os::path_exists(&Path(".")));
+        assert (!os::path_exists(&Path("test/nonexistent-bogus-path")));
     }
 
     #[test]
     fn copy_file_does_not_exist() {
-      assert !os::copy_file(~"test/nonexistent-bogus-path",
-                           ~"test/other-bogus-path");
-      assert !os::path_exists(~"test/other-bogus-path");
+      assert !os::copy_file(&Path("test/nonexistent-bogus-path"),
+                            &Path("test/other-bogus-path"));
+      assert !os::path_exists(&Path("test/other-bogus-path"));
     }
 
     #[test]
     fn copy_file_ok() {
       let tempdir = getcwd(); // would like to use $TMPDIR,
                               // doesn't seem to work on Linux
-      assert (str::len(tempdir) > 0u);
-      let in = tempdir + path::path_sep() + ~"in.txt";
-      let out = tempdir + path::path_sep() + ~"out.txt";
+      assert (str::len(tempdir.to_str()) > 0u);
+      let in = tempdir.push("in.txt");
+      let out = tempdir.push("out.txt");
 
       /* Write the temp input file */
-        let ostream = do as_c_charp(in) |fromp| {
-            do as_c_charp(~"w+b") |modebuf| {
+        let ostream = do as_c_charp(in.to_str()) |fromp| {
+            do as_c_charp("w+b") |modebuf| {
                 libc::fopen(fromp, modebuf)
             }
       };
@@ -1034,14 +1026,14 @@ mod tests {
                                (str::len(s) + 1u) as size_t, ostream)
                   == buf.len() as size_t)};
       assert (libc::fclose(ostream) == (0u as c_int));
-      let rs = os::copy_file(in, out);
-      if (!os::path_exists(in)) {
-        fail (fmt!("%s doesn't exist", in));
+      let rs = os::copy_file(&in, &out);
+      if (!os::path_exists(&in)) {
+        fail (fmt!("%s doesn't exist", in.to_str()));
       }
       assert(rs);
-      let rslt = run::run_program(~"diff", ~[in, out]);
+      let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]);
       assert (rslt == 0);
-      assert (remove_file(in));
-      assert (remove_file(out));
+      assert (remove_file(&in));
+      assert (remove_file(&out));
     }
 }
diff --git a/src/libcore/path2.rs b/src/libcore/path2.rs
index 50996c7876b..9d1351db3ac 100644
--- a/src/libcore/path2.rs
+++ b/src/libcore/path2.rs
@@ -14,73 +14,82 @@ struct PosixPath {
     components: ~[~str];
 }
 
-trait Path {
+trait GenericPath {
 
-    static fn from_str((&str)) -> self;
-    fn to_str() -> ~str;
+    static pure fn from_str((&str)) -> self;
 
-    fn dirname() -> ~str;
-    fn filename() -> option<~str>;
-    fn filestem() -> option<~str>;
-    fn filetype() -> option<~str>;
+    pure fn dirname() -> ~str;
+    pure fn filename() -> option<~str>;
+    pure fn filestem() -> option<~str>;
+    pure fn filetype() -> option<~str>;
 
-    fn with_dirname((&str)) -> self;
-    fn with_filename((&str)) -> self;
-    fn with_filestem((&str)) -> self;
-    fn with_filetype((&str)) -> self;
+    pure fn with_dirname((&str)) -> self;
+    pure fn with_filename((&str)) -> self;
+    pure fn with_filestem((&str)) -> self;
+    pure fn with_filetype((&str)) -> self;
 
-    fn push_components((&[~str])) -> self;
-    fn pop_component() -> self;
+    pure fn push((&str)) -> self;
+    pure fn push_rel((&self)) -> self;
+    pure fn push_many((&[~str])) -> self;
+    pure fn pop() -> self;
 }
 
-// FIXME (#3227): when default methods in traits are working, de-duplicate
-// PosixPath and WindowsPath, most of their methods are common.
+#[cfg(windows)]
+type Path = WindowsPath;
+
+#[cfg(windows)]
+pure fn Path(s: &str) -> Path {
+    from_str::<WindowsPath>(s)
+}
+
+#[cfg(unix)]
+type Path = PosixPath;
 
-impl PosixPath : Path {
+#[cfg(unix)]
+pure fn Path(s: &str) -> Path {
+    from_str::<PosixPath>(s)
+}
+
+impl PosixPath : ToStr {
     fn to_str() -> ~str {
-        match self.filename() {
-          none => self.dirname(),
-          some(ref f) =>
-          if (self.components.len() == 1 &&
-              !self.is_absolute) {
-            copy *f
-          } else {
-            self.dirname() + "/" + *f
-          }
+        let mut s = ~"";
+        if self.is_absolute {
+            s += "/";
         }
+        s + str::connect(self.components, "/")
     }
+}
 
-    static fn from_str(s: &str) -> PosixPath {
+// FIXME (#3227): when default methods in traits are working, de-duplicate
+// PosixPath and WindowsPath, most of their methods are common.
+impl PosixPath : GenericPath {
+
+    static pure fn from_str(s: &str) -> PosixPath {
         let mut components = str::split_nonempty(s, |c| c == '/');
         let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
         return PosixPath { is_absolute: is_absolute,
                            components: normalize(components) }
     }
 
-    fn dirname() -> ~str {
-        let mut s = ~"";
-        if self.is_absolute {
-            s += "/";
-        }
-        let mut d = copy self.components;
-        if d.len() != 0 {
-            vec::pop(d);
-        }
-        s += str::connect(d, "/");
-        if s.len() == 0 {
-            s = ~".";
+    pure fn dirname() -> ~str {
+        unchecked {
+            let s = self.dir_path().to_str();
+            if s.len() == 0 {
+                ~"."
+            } else {
+                s
+            }
         }
-        return s;
     }
 
-    fn filename() -> option<~str> {
+    pure fn filename() -> option<~str> {
         match self.components.len() {
           0 => none,
           n => some(copy self.components[n - 1])
         }
     }
 
-    fn filestem() -> option<~str> {
+    pure fn filestem() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -92,7 +101,7 @@ impl PosixPath : Path {
         }
     }
 
-    fn filetype() -> option<~str> {
+    pure fn filetype() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -104,20 +113,22 @@ impl PosixPath : Path {
         }
     }
 
-    fn with_dirname(d: &str) -> PosixPath {
+    pure fn with_dirname(d: &str) -> PosixPath {
         let dpath = from_str::<PosixPath>(d);
         match self.filename() {
-          some(ref f) => dpath.push_components(~[copy *f]),
+          some(ref f) => dpath.push(*f),
           none => dpath
         }
     }
 
-    fn with_filename(f: &str) -> PosixPath {
-        assert ! str::any(f, |c| windows::is_sep(c as u8));
-        self.dir_path().push_components(~[str::from_slice(f)])
+    pure fn with_filename(f: &str) -> PosixPath {
+        unchecked {
+            assert ! str::any(f, |c| windows::is_sep(c as u8));
+            self.dir_path().push(f)
+        }
     }
 
-    fn with_filestem(s: &str) -> PosixPath {
+    pure fn with_filestem(s: &str) -> PosixPath {
         match self.filetype() {
           none => self.with_filename(s),
           some(ref t) =>
@@ -125,7 +136,7 @@ impl PosixPath : Path {
         }
     }
 
-    fn with_filetype(t: &str) -> PosixPath {
+    pure fn with_filetype(t: &str) -> PosixPath {
         if t.len() == 0 {
             match self.filestem() {
               none => copy self,
@@ -141,15 +152,15 @@ impl PosixPath : Path {
         }
     }
 
-    fn dir_path() -> PosixPath {
+    pure fn dir_path() -> PosixPath {
         if self.components.len() != 0 {
-            self.pop_component()
+            self.pop()
         } else {
             copy self
         }
     }
 
-    fn file_path() -> PosixPath {
+    pure fn file_path() -> PosixPath {
         let cs = match self.filename() {
           none => ~[],
           some(ref f) => ~[copy *f]
@@ -158,42 +169,56 @@ impl PosixPath : Path {
                            components: cs }
     }
 
-    fn push_components(cs: &[~str]) -> PosixPath {
+    pure fn push_rel(other: &PosixPath) -> PosixPath {
+        assert !other.is_absolute;
+        self.push_many(other.components)
+    }
+
+    pure fn push_many(cs: &[~str]) -> PosixPath {
         return PosixPath { components: normalize(self.components + cs),
                            ..self }
     }
 
-    fn pop_component() -> PosixPath {
+    pure fn push(s: &str) -> PosixPath {
+        let mut cs = self.components;
+        unchecked { vec::push(cs, move str::from_slice(s)); }
+        cs = normalize(cs);
+        return PosixPath { components: move cs,
+                           ..self }
+    }
+
+    pure fn pop() -> PosixPath {
         let mut cs = copy self.components;
         if cs.len() != 0 {
-            vec::pop(cs);
+            unchecked { vec::pop(cs); }
         }
-        return PosixPath { components: cs, ..self }
+        return PosixPath { components: move cs, ..self }
     }
-
-
-
 }
 
 
-impl WindowsPath : Path {
-
+impl WindowsPath : ToStr {
     fn to_str() -> ~str {
-        match self.filename() {
-          none => self.dirname(),
-          some(ref f) =>
-          if (self.components.len() == 1 &&
-              !self.is_absolute &&
-              self.host == none &&
-              self.device == none) {
-            copy *f
-          } else {
-            self.dirname() + "\\" + *f
-          }
+        let mut s = ~"";
+        match self.host {
+          some(h) => { s += "\\\\"; s += h; }
+          none => { }
+        }
+        match self.device {
+          some(d) => { s += d; s += ":"; }
+          none => { }
+        }
+        if self.is_absolute {
+            s += "\\";
         }
+        s + str::connect(self.components, "\\")
     }
+}
+
 
-    static fn from_str(s: &str) -> WindowsPath {
+impl WindowsPath : GenericPath {
+
+    static pure fn from_str(s: &str) -> WindowsPath {
         let host;
         let device;
         let rest;
@@ -229,38 +254,25 @@ impl WindowsPath : Path {
                              components: normalize(components) }
     }
 
-    fn dirname() -> ~str {
-        let mut s = ~"";
-        match self.host {
-          some(h) => { s += "\\\\"; s += h; }
-          none => { }
-        }
-        match self.device {
-          some(d) => { s += d; s += ":"; }
-          none => { }
-        }
-        if self.is_absolute {
-            s += "\\";
-        }
-        let mut d = copy self.components;
-        if d.len() != 0 {
-            vec::pop(d);
-        }
-        s += str::connect(d, "\\");
-        if s.len() == 0 {
-            s = ~".";
+    pure fn dirname() -> ~str {
+        unchecked {
+            let s = self.dir_path().to_str();
+            if s.len() == 0 {
+                ~"."
+            } else {
+                s
+            }
         }
-        return s;
     }
 
-    fn filename() -> option<~str> {
+    pure fn filename() -> option<~str> {
         match self.components.len() {
           0 => none,
           n => some(copy self.components[n - 1])
         }
     }
 
-    fn filestem() -> option<~str> {
+    pure fn filestem() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -272,7 +284,7 @@ impl WindowsPath : Path {
         }
     }
 
-    fn filetype() -> option<~str> {
+    pure fn filetype() -> option<~str> {
         match self.filename() {
           none => none,
           some(ref f) => {
@@ -284,20 +296,20 @@ impl WindowsPath : Path {
         }
     }
 
-    fn with_dirname(d: &str) -> WindowsPath {
+    pure fn with_dirname(d: &str) -> WindowsPath {
         let dpath = from_str::<WindowsPath>(d);
         match self.filename() {
-          some(ref f) => dpath.push_components(~[copy *f]),
+          some(ref f) => dpath.push(*f),
           none => dpath
         }
     }
 
-    fn with_filename(f: &str) -> WindowsPath {
+    pure fn with_filename(f: &str) -> WindowsPath {
         assert ! str::any(f, |c| windows::is_sep(c as u8));
-        self.dir_path().push_components(~[str::from_slice(f)])
+        self.dir_path().push(f)
     }
 
-    fn with_filestem(s: &str) -> WindowsPath {
+    pure fn with_filestem(s: &str) -> WindowsPath {
         match self.filetype() {
           none => self.with_filename(s),
           some(ref t) =>
@@ -305,7 +317,7 @@ impl WindowsPath : Path {
         }
     }
 
-    fn with_filetype(t: &str) -> WindowsPath {
+    pure fn with_filetype(t: &str) -> WindowsPath {
         if t.len() == 0 {
             match self.filestem() {
               none => copy self,
@@ -321,15 +333,15 @@ impl WindowsPath : Path {
         }
     }
 
-    fn dir_path() -> WindowsPath {
+    pure fn dir_path() -> WindowsPath {
         if self.components.len() != 0 {
-            self.pop_component()
+            self.pop()
         } else {
             copy self
         }
     }
 
-    fn file_path() -> WindowsPath {
+    pure fn file_path() -> WindowsPath {
         let cs = match self.filename() {
           none => ~[],
           some(ref f) => ~[copy *f]
@@ -340,30 +352,47 @@ impl WindowsPath : Path {
                              components: cs }
     }
 
-    fn push_components(cs: &[~str]) -> WindowsPath {
+    pure fn push_rel(other: &WindowsPath) -> WindowsPath {
+        assert !other.is_absolute;
+        self.push_many(other.components)
+    }
+
+    pure fn push_many(cs: &[~str]) -> WindowsPath {
         return WindowsPath { components: normalize(self.components + cs),
                             ..self }
     }
 
-    fn pop_component() -> WindowsPath {
+    pure fn push(s: &str) -> WindowsPath {
+        let mut cs = self.components;
+        unchecked { vec::push(cs, move str::from_slice(s)); }
+        cs = normalize(cs);
+        return WindowsPath { components: move cs,
+                             ..self }
+    }
+
+    pure fn pop() -> WindowsPath {
         let mut cs = copy self.components;
         if cs.len() != 0 {
-            vec::pop(cs);
+            unchecked { vec::pop(cs); }
         }
-        return WindowsPath { components: cs, ..self }
+        return WindowsPath { components: move cs, ..self }
     }
 }
 
 
-fn normalize(components: &[~str]) -> ~[~str] {
+pure fn normalize(components: &[~str]) -> ~[~str] {
     let mut cs = ~[];
-    for components.each |c| {
-        if c == ~"." { again; }
-        if c == ~".." && cs.len() != 0 {
-            vec::pop(cs);
-            again;
+    unchecked {
+        for components.each |c| {
+            unchecked {
+                if c == ~"." && components.len() > 1 { again; }
+                if c == ~".." && cs.len() != 0 {
+                    vec::pop(cs);
+                    again;
+                }
+                vec::push(cs, copy c);
+            }
         }
-        vec::push(cs, copy c);
     }
     cs
 }
@@ -384,6 +413,7 @@ mod posix {
         }
 
         t(&(mk("hi")), "hi");
+        t(&(mk("/lib")), "/lib");
         t(&(mk("hi/there")), "hi/there");
         t(&(mk("hi/there.txt")), "hi/there.txt");
 
@@ -401,7 +431,7 @@ mod posix {
           "a/foo.txt");
 
         t(&(mk("a/b/c")
-            .push_components([~".."])), "a/b");
+            .push("..")), "a/b");
 
         t(&(mk("there.txt")
             .with_filetype("o")), "there.o");
@@ -425,7 +455,7 @@ mod posix {
             "/usr/lib/there.o");
 
         t(&(mk("/usr/bin/rust")
-            .push_components([~"lib", ~"thingy.so"])
+            .push_many([~"lib", ~"thingy.so"])
             .with_filestem("librustc")),
           "/usr/bin/rust/lib/librustc.so");
 
@@ -437,11 +467,11 @@ mod posix {
 mod windows {
 
     #[inline(always)]
-    fn is_sep(u: u8) -> bool {
+    pure fn is_sep(u: u8) -> bool {
         u == '/' as u8 || u == '\\' as u8
     }
 
-    fn extract_unc_prefix(s: &str) -> option<(~str,~str)> {
+    pure fn extract_unc_prefix(s: &str) -> option<(~str,~str)> {
         if (s.len() > 1 &&
             s[0] == '\\' as u8 &&
             s[1] == '\\' as u8) {
@@ -458,14 +488,20 @@ mod windows {
         none
     }
 
-    fn extract_drive_prefix(s: &str) -> option<(~str,~str)> {
-        if (s.len() > 1 &&
-            libc::isalpha(s[0] as libc::c_int) != 0 &&
-            s[1] == ':' as u8) {
-            let rest = if s.len() == 2 { ~"" } else { s.slice(2, s.len()) };
-            return some((s.slice(0,1), rest));
+    pure fn extract_drive_prefix(s: &str) -> option<(~str,~str)> {
+        unchecked {
+            if (s.len() > 1 &&
+                libc::isalpha(s[0] as libc::c_int) != 0 &&
+                s[1] == ':' as u8) {
+                let rest = if s.len() == 2 {
+                    ~""
+                } else {
+                    s.slice(2, s.len())
+                };
+                return some((s.slice(0,1), rest));
+            }
+            none
         }
-        none
     }
 
     #[test]
@@ -532,7 +568,7 @@ mod windows {
             "c:\\program files C\\there.o");
 
         t(&(mk("c:\\program files (x86)\\rust")
-            .push_components([~"lib", ~"thingy.dll"])
+            .push_many([~"lib", ~"thingy.dll"])
             .with_filename("librustc.dll")),
           "c:\\program files (x86)\\rust\\lib\\librustc.dll");