about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorKevin Ballard <kevin@sb.org>2013-08-25 20:46:26 -0700
committerKevin Ballard <kevin@sb.org>2013-10-15 20:10:10 -0700
commit550bc9bd1c5aa90f6574b7d4ebd9922b986f9741 (patch)
tree21fc404dfe96594798ed89ea92e0fd9842d42b76 /src/libstd
parentb41391306692c82d9b44721a47833eb809e0cbf1 (diff)
downloadrust-550bc9bd1c5aa90f6574b7d4ebd9922b986f9741.tar.gz
rust-550bc9bd1c5aa90f6574b7d4ebd9922b986f9741.zip
path2: Reimplement PosixPath in terms of ~[u8]
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/path2.rs292
1 files changed, 154 insertions, 138 deletions
diff --git a/src/libstd/path2.rs b/src/libstd/path2.rs
index 45ce6e94ae4..dea326fadfe 100644
--- a/src/libstd/path2.rs
+++ b/src/libstd/path2.rs
@@ -18,10 +18,11 @@ use from_str::FromStr;
 use iterator::{AdditiveIterator, Extendable, Iterator};
 use option::{Option, None, Some};
 use str;
-use str::{OwnedStr, Str, StrSlice, StrVector};
+use str::{OwnedStr, Str, StrSlice};
 use util;
 use vec;
-use vec::{ImmutableVector, OwnedVector};
+use vec::{CopyableVector, OwnedCopyableVector, OwnedVector};
+use vec::{ImmutableEqVector, ImmutableVector, Vector, VectorVector};
 
 /// Typedef for the platform-native path type
 #[cfg(unix)]
@@ -38,7 +39,7 @@ pub type ComponentIter<'self> = PosixComponentIter<'self>;
 //pub type ComponentIter<'self> = WindowsComponentIter<'self>;
 
 /// Iterator that yields successive components of a PosixPath
-type PosixComponentIter<'self> = str::CharSplitIterator<'self, char>;
+type PosixComponentIter<'self> = vec::SplitIterator<'self, u8>;
 
 // Condition that is raised when a NUL is found in a byte vector given to a Path function
 condition! {
@@ -541,142 +542,142 @@ impl ToCStr for PosixPath {
     }
 }
 
-impl GenericPath for PosixPath {
-    #[inline]
-    fn from_str(s: &str) -> PosixPath {
-        PosixPath::new(s)
+impl GenericPathUnsafe for PosixPath {
+    unsafe fn from_vec_unchecked(path: &[u8]) -> PosixPath {
+        let path = PosixPath::normalize(path);
+        assert!(!path.is_empty());
+        let idx = path.rposition_elem(&posix::sep);
+        PosixPath{ repr: path, sepidx: idx }
     }
 
-    #[inline]
-    fn as_str<'a>(&'a self) -> &'a str {
-        self.repr.as_slice()
-    }
-
-    fn dirname<'a>(&'a self) -> &'a str {
+    unsafe fn set_dirname_unchecked(&mut self, dirname: &[u8]) {
         match self.sepidx {
-            None if ".." == self.repr => "..",
-            None => ".",
-            Some(0) => self.repr.slice_to(1),
-            Some(idx) if self.repr.slice_from(idx+1) == ".." => self.repr.as_slice(),
-            Some(idx) => self.repr.slice_to(idx)
-        }
-    }
-
-    fn filename<'a>(&'a self) -> &'a str {
-        match self.sepidx {
-            None if "." == self.repr || ".." == self.repr => "",
-            None => self.repr.as_slice(),
-            Some(idx) if self.repr.slice_from(idx+1) == ".." => "",
-            Some(idx) => self.repr.slice_from(idx+1)
-        }
-    }
-
-    fn set_dirname(&mut self, dirname: &str) {
-        match self.sepidx {
-            None if "." == self.repr || ".." == self.repr => {
+            None if bytes!(".") == self.repr || bytes!("..") == self.repr => {
                 self.repr = PosixPath::normalize(dirname);
             }
             None => {
-                let mut s = str::with_capacity(dirname.len() + self.repr.len() + 1);
-                s.push_str(dirname);
-                s.push_char(posix::sep);
-                s.push_str(self.repr);
-                self.repr = PosixPath::normalize(s);
+                let mut v = vec::with_capacity(dirname.len() + self.repr.len() + 1);
+                v.push_all(dirname);
+                v.push(posix::sep);
+                v.push_all(self.repr);
+                self.repr = PosixPath::normalize(v);
             }
-            Some(0) if self.repr.len() == 1 && self.repr[0] == posix::sep as u8 => {
+            Some(0) if self.repr.len() == 1 && self.repr[0] == posix::sep => {
                 self.repr = PosixPath::normalize(dirname);
             }
-            Some(idx) if dirname == "" => {
-                let s = PosixPath::normalize(self.repr.slice_from(idx+1));
-                self.repr = s;
+            Some(idx) if dirname.is_empty() => {
+                let v = PosixPath::normalize(self.repr.slice_from(idx+1));
+                self.repr = v;
             }
-            Some(idx) if self.repr.slice_from(idx+1) == ".." => {
+            Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
                 self.repr = PosixPath::normalize(dirname);
             }
             Some(idx) => {
-                let mut s = str::with_capacity(dirname.len() + self.repr.len() - idx);
-                s.push_str(dirname);
-                s.push_str(self.repr.slice_from(idx));
-                self.repr = PosixPath::normalize(s);
+                let mut v = vec::with_capacity(dirname.len() + self.repr.len() - idx);
+                v.push_all(dirname);
+                v.push_all(self.repr.slice_from(idx));
+                self.repr = PosixPath::normalize(v);
             }
         }
-        self.sepidx = self.repr.rfind(posix::sep);
+        self.sepidx = self.repr.rposition_elem(&posix::sep);
     }
 
-    fn set_filename(&mut self, filename: &str) {
+    unsafe fn set_filename_unchecked(&mut self, filename: &[u8]) {
         match self.sepidx {
-            None if ".." == self.repr => {
-                let mut s = str::with_capacity(3 + filename.len());
-                s.push_str("..");
-                s.push_char(posix::sep);
-                s.push_str(filename);
-                self.repr = PosixPath::normalize(s);
+            None if bytes!("..") == self.repr => {
+                let mut v = vec::with_capacity(3 + filename.len());
+                v.push_all(dot_dot_static);
+                v.push(posix::sep);
+                v.push_all(filename);
+                self.repr = PosixPath::normalize(v);
             }
             None => {
                 self.repr = PosixPath::normalize(filename);
             }
-            Some(idx) if self.repr.slice_from(idx+1) == ".." => {
-                let mut s = str::with_capacity(self.repr.len() + 1 + filename.len());
-                s.push_str(self.repr);
-                s.push_char(posix::sep);
-                s.push_str(filename);
-                self.repr = PosixPath::normalize(s);
+            Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
+                let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
+                v.push_all(self.repr);
+                v.push(posix::sep);
+                v.push_all(filename);
+                self.repr = PosixPath::normalize(v);
             }
             Some(idx) => {
-                let mut s = str::with_capacity(self.repr.len() - idx + filename.len());
-                s.push_str(self.repr.slice_to(idx+1));
-                s.push_str(filename);
-                self.repr = PosixPath::normalize(s);
+                let mut v = vec::with_capacity(self.repr.len() - idx + filename.len());
+                v.push_all(self.repr.slice_to(idx+1));
+                v.push_all(filename);
+                self.repr = PosixPath::normalize(v);
             }
         }
-        self.sepidx = self.repr.rfind(posix::sep);
+        self.sepidx = self.repr.rposition_elem(&posix::sep);
     }
 
-    fn push(&mut self, path: &str) {
+    unsafe fn push_unchecked(&mut self, path: &[u8]) {
         if !path.is_empty() {
-            if path[0] == posix::sep as u8 {
+            if path[0] == posix::sep {
                 self.repr = PosixPath::normalize(path);
             }  else {
-                let mut s = str::with_capacity(self.repr.len() + path.len() + 1);
-                s.push_str(self.repr);
-                s.push_char(posix::sep);
-                s.push_str(path);
-                self.repr = PosixPath::normalize(s);
+                let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
+                v.push_all(self.repr);
+                v.push(posix::sep);
+                v.push_all(path);
+                self.repr = PosixPath::normalize(v);
             }
-            self.sepidx = self.repr.rfind(posix::sep);
+            self.sepidx = self.repr.rposition_elem(&posix::sep);
         }
     }
+}
 
-    fn push_path(&mut self, path: &PosixPath) {
-        self.push(path.as_str());
+impl GenericPath for PosixPath {
+    #[inline]
+    fn as_vec<'a>(&'a self) -> &'a [u8] {
+        self.repr.as_slice()
     }
 
-    fn pop_opt(&mut self) -> Option<~str> {
+    fn dirname<'a>(&'a self) -> &'a [u8] {
         match self.sepidx {
-            None if "." == self.repr => None,
+            None if bytes!("..") == self.repr => self.repr.as_slice(),
+            None => dot_static,
+            Some(0) => self.repr.slice_to(1),
+            Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => self.repr.as_slice(),
+            Some(idx) => self.repr.slice_to(idx)
+        }
+    }
+
+    fn filename<'a>(&'a self) -> &'a [u8] {
+        match self.sepidx {
+            None if bytes!(".") == self.repr || bytes!("..") == self.repr => &[],
+            None => self.repr.as_slice(),
+            Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => &[],
+            Some(idx) => self.repr.slice_from(idx+1)
+        }
+    }
+
+    fn pop_opt(&mut self) -> Option<~[u8]> {
+        match self.sepidx {
+            None if bytes!(".") == self.repr => None,
             None => {
-                let mut s = ~".";
-                util::swap(&mut s, &mut self.repr);
+                let mut v = ~['.' as u8];
+                util::swap(&mut v, &mut self.repr);
                 self.sepidx = None;
-                Some(s)
+                Some(v)
             }
-            Some(0) if "/" == self.repr => None,
+            Some(0) if bytes!("/") == self.repr => None,
             Some(idx) => {
-                let s = self.repr.slice_from(idx+1).to_owned();
+                let v = self.repr.slice_from(idx+1).to_owned();
                 if idx == 0 {
                     self.repr.truncate(idx+1);
                 } else {
                     self.repr.truncate(idx);
                 }
-                self.sepidx = self.repr.rfind(posix::sep);
-                Some(s)
+                self.sepidx = self.repr.rposition_elem(&posix::sep);
+                Some(v)
             }
         }
     }
 
     #[inline]
     fn is_absolute(&self) -> bool {
-        self.repr[0] == posix::sep as u8
+        self.repr[0] == posix::sep
     }
 
     fn is_ancestor_of(&self, other: &PosixPath) -> bool {
@@ -685,19 +686,16 @@ impl GenericPath for PosixPath {
         } else {
             let mut ita = self.component_iter();
             let mut itb = other.component_iter();
-            if "." == self.repr {
-                return match itb.next() {
-                    Some("..") => false,
-                    _ => true
-                };
+            if bytes!(".") == self.repr {
+                return itb.next() != Some(bytes!(".."));
             }
             loop {
                 match (ita.next(), itb.next()) {
                     (None, _) => break,
                     (Some(a), Some(b)) if a == b => { loop },
-                    (Some(".."), _) => {
+                    (Some(a), _) if a == bytes!("..") => {
                         // if ita contains only .. components, it's an ancestor
-                        return ita.all(|x| x == "..");
+                        return ita.all(|x| x == bytes!(".."));
                     }
                     _ => return false
                 }
@@ -725,14 +723,14 @@ impl GenericPath for PosixPath {
                         comps.extend(&mut ita);
                         break;
                     }
-                    (None, _) => comps.push(".."),
+                    (None, _) => comps.push(dot_dot_static),
                     (Some(a), Some(b)) if comps.is_empty() && a == b => (),
-                    (Some(a), Some(".")) => comps.push(a),
-                    (Some(_), Some("..")) => return None,
+                    (Some(a), Some(b)) if b == bytes!(".") => comps.push(a),
+                    (Some(_), Some(b)) if b == bytes!("..") => return None,
                     (Some(a), Some(_)) => {
-                        comps.push("..");
+                        comps.push(dot_dot_static);
                         for _ in itb {
-                            comps.push("..");
+                            comps.push(dot_dot_static);
                         }
                         comps.push(a);
                         comps.extend(&mut ita);
@@ -740,61 +738,77 @@ impl GenericPath for PosixPath {
                     }
                 }
             }
-            Some(PosixPath::new(comps.connect(str::from_char(posix::sep))))
+            Some(PosixPath::new(comps.connect_vec(&posix::sep)))
         }
     }
 }
 
 impl PosixPath {
+    /// Returns a new PosixPath from a byte vector
+    ///
+    /// # Failure
+    ///
+    /// Raises the `null_byte` condition if the vector contains a NUL.
+    #[inline]
+    pub fn new(v: &[u8]) -> PosixPath {
+        GenericPath::from_vec(v)
+    }
+
     /// Returns a new PosixPath from a string
-    pub fn new(s: &str) -> PosixPath {
-        let s = PosixPath::normalize(s);
-        assert!(!s.is_empty());
-        let idx = s.rfind(posix::sep);
-        PosixPath{ repr: s, sepidx: idx }
+    ///
+    /// # Failure
+    ///
+    /// Raises the `null_byte` condition if the str contains a NUL.
+    #[inline]
+    pub fn from_str(s: &str) -> PosixPath {
+        GenericPath::from_str(s)
     }
 
-    /// Converts the PosixPath into an owned string
-    pub fn into_str(self) -> ~str {
+    /// Converts the PosixPath into an owned byte vector
+    pub fn into_vec(self) -> ~[u8] {
         self.repr
     }
 
-    /// Returns a normalized string representation of a path, by removing all empty
+    /// Converts the PosixPath into an owned string, if possible
+    pub fn into_str(self) -> Option<~str> {
+        str::from_bytes_owned_opt(self.repr)
+    }
+
+    /// Returns a normalized byte vector representation of a path, by removing all empty
     /// components, and unnecessary . and .. components.
-    pub fn normalize<S: Str>(s: S) -> ~str {
+    pub fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
         // borrowck is being very picky
         let val = {
-            let is_abs = !s.as_slice().is_empty() && s.as_slice()[0] == posix::sep as u8;
-            let s_ = if is_abs { s.as_slice().slice_from(1) } else { s.as_slice() };
-            let comps = normalize_helper(s_, is_abs, posix::sep);
+            let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == posix::sep;
+            let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
+            let comps = normalize_helper(v_, is_abs, posix::is_sep);
             match comps {
                 None => None,
                 Some(comps) => {
-                    let sepstr = str::from_char(posix::sep);
                     if is_abs && comps.is_empty() {
-                        Some(sepstr)
+                        Some(~[posix::sep])
                     } else {
                         let n = if is_abs { comps.len() } else { comps.len() - 1} +
-                                comps.iter().map(|s| s.len()).sum();
-                        let mut s = str::with_capacity(n);
+                                comps.iter().map(|v| v.len()).sum();
+                        let mut v = vec::with_capacity(n);
                         let mut it = comps.move_iter();
                         if !is_abs {
                             match it.next() {
                                 None => (),
-                                Some(comp) => s.push_str(comp)
+                                Some(comp) => v.push_all(comp)
                             }
                         }
                         for comp in it {
-                            s.push_str(sepstr);
-                            s.push_str(comp);
+                            v.push(posix::sep);
+                            v.push_all(comp);
                         }
-                        Some(s)
+                        Some(v)
                     }
                 }
             }
         };
         match val {
-            None => s.into_owned(),
+            None => v.into_owned(),
             Some(val) => val
         }
     }
@@ -804,11 +818,11 @@ impl PosixPath {
     /// /a/b/c and a/b/c yield the same set of components.
     /// A path of "/" yields no components. A path of "." yields one component.
     pub fn component_iter<'a>(&'a self) -> PosixComponentIter<'a> {
-        let s = if self.repr[0] == posix::sep as u8 {
+        let v = if self.repr[0] == posix::sep {
             self.repr.slice_from(1)
         } else { self.repr.as_slice() };
-        let mut ret = s.split_iter(posix::sep);
-        if s.is_empty() {
+        let mut ret = v.split_iter(posix::is_sep);
+        if v.is_empty() {
             // consume the empty "" component
             ret.next();
         }
@@ -816,30 +830,29 @@ impl PosixPath {
     }
 }
 
-// None result means the string didn't need normalizing
-fn normalize_helper<'a, Sep: str::CharEq>(s: &'a str, is_abs: bool, sep: Sep) -> Option<~[&'a str]> {
-    if is_abs && s.as_slice().is_empty() {
+// None result means the byte vector didn't need normalizing
+fn normalize_helper<'a>(v: &'a [u8], is_abs: bool, f: &'a fn(&u8) -> bool) -> Option<~[&'a [u8]]> {
+    if is_abs && v.as_slice().is_empty() {
         return None;
     }
-    let mut comps: ~[&'a str] = ~[];
+    let mut comps: ~[&'a [u8]] = ~[];
     let mut n_up = 0u;
     let mut changed = false;
-    for comp in s.split_iter(sep) {
-        match comp {
-            "" => { changed = true; }
-            "." => { changed = true; }
-            ".." if is_abs && comps.is_empty() => { changed = true; }
-            ".." if comps.len() == n_up => { comps.push(".."); n_up += 1; }
-            ".." => { comps.pop_opt(); changed = true; }
-            x => comps.push(x)
-        }
+    for comp in v.split_iter(f) {
+        if comp.is_empty() { changed = true }
+        else if comp == bytes!(".") { changed = true }
+        else if comp == bytes!("..") {
+            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_opt(); changed = true }
+        } else { comps.push(comp) }
     }
     if changed {
         if comps.is_empty() && !is_abs {
-            if s == "." {
+            if v == bytes!(".") {
                 return None;
             }
-            comps.push(".");
+            comps.push(dot_static);
         }
         Some(comps)
     } else {
@@ -847,6 +860,9 @@ fn normalize_helper<'a, Sep: str::CharEq>(s: &'a str, is_abs: bool, sep: Sep) ->
     }
 }
 
+static dot_static: &'static [u8] = &'static ['.' as u8];
+static dot_dot_static: &'static [u8] = &'static ['.' as u8, '.' as u8];
+
 /// Various POSIX helpers
 pub mod posix {
     /// The standard path separator character