about summary refs log tree commit diff
path: root/src/libcore/path2.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libcore/path2.rs')
-rw-r--r--src/libcore/path2.rs294
1 files changed, 165 insertions, 129 deletions
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");