(index<- )        ./libstd/path/posix.rs

    git branch:    * master           5200215 auto merge of #14035 : alexcrichton/rust/experimental, r=huonw
    modified:    Fri May  9 13:02:28 2014
    1  // Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
    2  // file at the top-level directory of this distribution and at
    3  // http://rust-lang.org/COPYRIGHT.
    4  //
    5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    8  // option. This file may not be copied, modified, or distributed
    9  // except according to those terms.
   10  
   11  //! POSIX file path handling
   12  
   13  use container::Container;
   14  use c_str::{CString, ToCStr};
   15  use clone::Clone;
   16  use cmp::{Eq, TotalEq};
   17  use from_str::FromStr;
   18  use io::Writer;
   19  use iter::{DoubleEndedIterator, Rev, AdditiveIterator, Extendable, Iterator, Map};
   20  use option::{Option, None, Some};
   21  use str;
   22  use str::Str;
   23  use slice::{CloneableVector, Splits, Vector, VectorVector,
   24              ImmutableEqVector, OwnedVector, ImmutableVector};
   25  use vec::Vec;
   26  
   27  use super::{BytesContainer, GenericPath, GenericPathUnsafe};
   28  
   29  /// Iterator that yields successive components of a Path as &[u8]
   30  pub type Components<'a> = Splits<'a, u8>;
   31  /// Iterator that yields components of a Path in reverse as &[u8]
   32  #[deprecated = "replaced by Rev<Components<'a>>"]
   33  pub type RevComponents<'a> = Rev<Components<'a>>;
   34  
   35  /// Iterator that yields successive components of a Path as Option<&str>
   36  pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
   37                                         Components<'a>>;
   38  /// Iterator that yields components of a Path in reverse as Option<&str>
   39  #[deprecated = "replaced by Rev<StrComponents<'a>>"]
   40  pub type RevStrComponents<'a> = Rev<StrComponents<'a>>;
   41  
   42  /// Represents a POSIX file path
   43  #[deriving(Clone)]
   44  pub struct Path {
   45      repr: Vec<u8>, // assumed to never be empty or contain NULs
   46      sepidx: Option<uint> // index of the final separator in repr
   47  }
   48  
   49  /// The standard path separator character
   50  pub static SEP: char = '/';
   51  
   52  /// The standard path separator byte
   53  pub static SEP_BYTE: u8 = SEP as u8;
   54  
   55  /// Returns whether the given byte is a path separator
   56  #[inline]
   57  pub fn is_sep_byte(u: &u8) -> bool {
   58      *u as char == SEP
   59  }
   60  
   61  /// Returns whether the given char is a path separator
   62  #[inline]
   63  pub fn is_sep(c: char) -> bool {
   64      c == SEP
   65  }
   66  
   67  impl Eq for Path {
   68      #[inline]
   69      fn eq(&self, other&Path) -> bool {
   70          self.repr == other.repr
   71      }
   72  }
   73  
   74  impl TotalEq for Path {}
   75  
   76  impl FromStr for Path {
   77      fn from_str(s&str) -> Option<Path> {
   78          Path::new_opt(s)
   79      }
   80  }
   81  
   82  impl ToCStr for Path {
   83      #[inline]
   84      fn to_c_str(&self) -> CString {
   85          // The Path impl guarantees no internal NUL
   86          unsafe { self.as_vec().to_c_str_unchecked() }
   87      }
   88  
   89      #[inline]
   90      unsafe fn to_c_str_unchecked(&self) -> CString {
   91          self.as_vec().to_c_str_unchecked()
   92      }
   93  }
   94  
   95  impl<S: Writer> ::hash::Hash<S> for Path {
   96      #[inline]
   97      fn hash(&self, state&mut S) {
   98          self.repr.hash(state)
   99      }
  100  }
  101  
  102  impl BytesContainer for Path {
  103      #[inline]
  104      fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
  105          self.as_vec()
  106      }
  107      #[inline]
  108      fn container_into_owned_bytes(self) -> Vec<u8> {
  109          self.into_vec()
  110      }
  111  }
  112  
  113  impl<'a> BytesContainer for &'a Path {
  114      #[inline]
  115      fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
  116          self.as_vec()
  117      }
  118  }
  119  
  120  impl GenericPathUnsafe for Path {
  121      unsafe fn new_unchecked<T: BytesContainer>(pathT) -> Path {
  122          let path = Path::normalize(path.container_as_bytes());
  123          assert!(!path.is_empty());
  124          let idx = path.as_slice().rposition_elem(&SEP_BYTE);
  125          Path{ repr: path, sepidx: idx }
  126      }
  127  
  128      unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filenameT) {
  129          let filename = filename.container_as_bytes();
  130          match self.sepidx {
  131              None if bytes!("..") == self.repr.as_slice() => {
  132                  let mut v = Vec::with_capacity(3 + filename.len());
  133                  v.push_all(dot_dot_static);
  134                  v.push(SEP_BYTE);
  135                  v.push_all(filename);
  136                  // FIXME: this is slow
  137                  self.repr = Path::normalize(v.as_slice());
  138              }
  139              None => {
  140                  self.repr = Path::normalize(filename);
  141              }
  142              Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
  143                  let mut v = Vec::with_capacity(self.repr.len() + 1 + filename.len());
  144                  v.push_all(self.repr.as_slice());
  145                  v.push(SEP_BYTE);
  146                  v.push_all(filename);
  147                  // FIXME: this is slow
  148                  self.repr = Path::normalize(v.as_slice());
  149              }
  150              Some(idx) => {
  151                  let mut v = Vec::with_capacity(idx + 1 + filename.len());
  152                  v.push_all(self.repr.slice_to(idx+1));
  153                  v.push_all(filename);
  154                  // FIXME: this is slow
  155                  self.repr = Path::normalize(v.as_slice());
  156              }
  157          }
  158          self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
  159      }
  160  
  161      unsafe fn push_unchecked<T: BytesContainer>(&mut self, pathT) {
  162          let path = path.container_as_bytes();
  163          if !path.is_empty() {
  164              if path[0] == SEP_BYTE {
  165                  self.repr = Path::normalize(path);
  166              }  else {
  167                  let mut v = Vec::with_capacity(self.repr.len() + path.len() + 1);
  168                  v.push_all(self.repr.as_slice());
  169                  v.push(SEP_BYTE);
  170                  v.push_all(path);
  171                  // FIXME: this is slow
  172                  self.repr = Path::normalize(v.as_slice());
  173              }
  174              self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
  175          }
  176      }
  177  }
  178  
  179  impl GenericPath for Path {
  180      #[inline]
  181      fn as_vec<'a>(&'a self) -> &'a [u8] {
  182          self.repr.as_slice()
  183      }
  184  
  185      fn into_vec(self) -> Vec<u8> {
  186          self.repr
  187      }
  188  
  189      fn dirname<'a>(&'a self) -> &'a [u8] {
  190          match self.sepidx {
  191              None if bytes!("..") == self.repr.as_slice() => self.repr.as_slice(),
  192              None => dot_static,
  193              Some(0) => self.repr.slice_to(1),
  194              Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => self.repr.as_slice(),
  195              Some(idx) => self.repr.slice_to(idx)
  196          }
  197      }
  198  
  199      fn filename<'a>(&'a self) -> Option<&'a [u8]> {
  200          match self.sepidx {
  201              None if bytes!(".") == self.repr.as_slice() ||
  202                  bytes!("..") == self.repr.as_slice() => None,
  203              None => Some(self.repr.as_slice()),
  204              Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => None,
  205              Some(0) if self.repr.slice_from(1).is_empty() => None,
  206              Some(idx) => Some(self.repr.slice_from(idx+1))
  207          }
  208      }
  209  
  210      fn pop(&mut self) -> bool {
  211          match self.sepidx {
  212              None if bytes!(".") == self.repr.as_slice() => false,
  213              None => {
  214                  self.repr = vec!['.' as u8];
  215                  self.sepidx = None;
  216                  true
  217              }
  218              Some(0) if bytes!("/") == self.repr.as_slice() => false,
  219              Some(idx) => {
  220                  if idx == 0 {
  221                      self.repr.truncate(idx+1);
  222                  } else {
  223                      self.repr.truncate(idx);
  224                  }
  225                  self.sepidx = self.repr.as_slice().rposition_elem(&SEP_BYTE);
  226                  true
  227              }
  228          }
  229      }
  230  
  231      fn root_path(&self) -> Option<Path> {
  232          if self.is_absolute() {
  233              Some(Path::new("/"))
  234          } else {
  235              None
  236          }
  237      }
  238  
  239      #[inline]
  240      fn is_absolute(&self) -> bool {
  241          *self.repr.get(0) == SEP_BYTE
  242      }
  243  
  244      fn is_ancestor_of(&self, other&Path) -> bool {
  245          if self.is_absolute() != other.is_absolute() {
  246              false
  247          } else {
  248              let mut ita = self.components();
  249              let mut itb = other.components();
  250              if bytes!(".") == self.repr.as_slice() {
  251                  return match itb.next() {
  252                      None => true,
  253                      Some(b) => b != bytes!("..")
  254                  };
  255              }
  256              loop {
  257                  match (ita.next(), itb.next()) {
  258                      (None, _) => break,
  259                      (Some(a), Some(b)) if a == b => { continue },
  260                      (Some(a), _) if a == bytes!("..") => {
  261                          // if ita contains only .. components, it's an ancestor
  262                          return ita.all(|x| x == bytes!(".."));
  263                      }
  264                      _ => return false
  265                  }
  266              }
  267              true
  268          }
  269      }
  270  
  271      #[allow(deprecated_owned_vector)]
  272      fn path_relative_from(&self, base&Path) -> Option<Path> {
  273          if self.is_absolute() != base.is_absolute() {
  274              if self.is_absolute() {
  275                  Some(self.clone())
  276              } else {
  277                  None
  278              }
  279          } else {
  280              let mut ita = self.components();
  281              let mut itb = base.components();
  282              let mut comps = vec![];
  283              loop {
  284                  match (ita.next(), itb.next()) {
  285                      (None, None) => break,
  286                      (Some(a), None) => {
  287                          comps.push(a);
  288                          comps.extend(ita.by_ref());
  289                          break;
  290                      }
  291                      (None, _) => comps.push(dot_dot_static),
  292                      (Some(a), Some(b)) if comps.is_empty() && a == b => (),
  293                      (Some(a), Some(b)) if b == bytes!(".") => comps.push(a),
  294                      (Some(_), Some(b)) if b == bytes!("..") => return None,
  295                      (Some(a), Some(_)) => {
  296                          comps.push(dot_dot_static);
  297                          for _ in itb {
  298                              comps.push(dot_dot_static);
  299                          }
  300                          comps.push(a);
  301                          comps.extend(ita.by_ref());
  302                          break;
  303                      }
  304                  }
  305              }
  306              Some(Path::new(comps.as_slice().connect_vec(&SEP_BYTE)))
  307          }
  308      }
  309  
  310      fn ends_with_path(&self, child&Path) -> bool {
  311          if !child.is_relative() { return false; }
  312          let mut selfit = self.components().rev();
  313          let mut childit = child.components().rev();
  314          loop {
  315              match (selfit.next(), childit.next()) {
  316                  (Some(a), Some(b)) => if a != b { return false; },
  317                  (Some(_), None) => break,
  318                  (None, Some(_)) => return false,
  319                  (None, None) => break
  320              }
  321          }
  322          true
  323      }
  324  }
  325  
  326  impl Path {
  327      /// Returns a new Path from a byte vector or string
  328      ///
  329      /// # Failure
  330      ///
  331      /// Fails the task if the vector contains a NUL.
  332      #[inline]
  333      pub fn new<T: BytesContainer>(pathT) -> Path {
  334          GenericPath::new(path)
  335      }
  336  
  337      /// Returns a new Path from a byte vector or string, if possible
  338      #[inline]
  339      pub fn new_opt<T: BytesContainer>(pathT) -> Option<Path> {
  340          GenericPath::new_opt(path)
  341      }
  342  
  343      /// Returns a normalized byte vector representation of a path, by removing all empty
  344      /// components, and unnecessary . and .. components.
  345      fn normalize<V: Vector<u8>+CloneableVector<u8>>(vV) -> Vec<u8> {
  346          // borrowck is being very picky
  347          let val = {
  348              let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == SEP_BYTE;
  349              let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
  350              let comps = normalize_helper(v_, is_abs);
  351              match comps {
  352                  None => None,
  353                  Some(comps) => {
  354                      if is_abs && comps.is_empty() {
  355                          Some(vec![SEP_BYTE])
  356                      } else {
  357                          let n = if is_abs { comps.len() } else { comps.len() - 1} +
  358                                  comps.iter().map(|v| v.len()).sum();
  359                          let mut v = Vec::with_capacity(n);
  360                          let mut it = comps.move_iter();
  361                          if !is_abs {
  362                              match it.next() {
  363                                  None => (),
  364                                  Some(comp) => v.push_all(comp)
  365                              }
  366                          }
  367                          for comp in it {
  368                              v.push(SEP_BYTE);
  369                              v.push_all(comp);
  370                          }
  371                          Some(v)
  372                      }
  373                  }
  374              }
  375          };
  376          match val {
  377              None => Vec::from_slice(v.as_slice()),
  378              Some(val) => val
  379          }
  380      }
  381  
  382      /// Returns an iterator that yields each component of the path in turn.
  383      /// Does not distinguish between absolute and relative paths, e.g.
  384      /// /a/b/c and a/b/c yield the same set of components.
  385      /// A path of "/" yields no components. A path of "." yields one component.
  386      pub fn components<'a>(&'a self) -> Components<'a> {
  387          let v = if *self.repr.get(0) == SEP_BYTE {
  388              self.repr.slice_from(1)
  389          } else { self.repr.as_slice() };
  390          let mut ret = v.split(is_sep_byte);
  391          if v.is_empty() {
  392              // consume the empty "" component
  393              ret.next();
  394          }
  395          ret
  396      }
  397  
  398      /// Returns an iterator that yields each component of the path in reverse.
  399      /// See components() for details.
  400      #[deprecated = "replaced by .components().rev()"]
  401      pub fn rev_components<'a>(&'a self) -> Rev<Components<'a>> {
  402          self.components().rev()
  403      }
  404  
  405      /// Returns an iterator that yields each component of the path as Option<&str>.
  406      /// See components() for details.
  407      pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
  408          self.components().map(str::from_utf8)
  409      }
  410  
  411      /// Returns an iterator that yields each component of the path in reverse as Option<&str>.
  412      /// See components() for details.
  413      #[deprecated = "replaced by .str_components().rev()"]
  414      pub fn rev_str_components<'a>(&'a self) -> Rev<StrComponents<'a>> {
  415          self.str_components().rev()
  416      }
  417  }
  418  
  419  // None result means the byte vector didn't need normalizing
  420  fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<Vec<&'a [u8]>> {
  421      if is_abs && v.as_slice().is_empty() {
  422          return None;
  423      }
  424      let mut compsVec<&'a [u8]> = vec![];
  425      let mut n_up = 0u;
  426      let mut changed = false;
  427      for comp in v.split(is_sep_byte) {
  428          if comp.is_empty() { changed = true }
  429          else if comp == bytes!(".") { changed = true }
  430          else if comp == bytes!("..") {
  431              if is_abs && comps.is_empty() { changed = true }
  432              else if comps.len() == n_up { comps.push(dot_dot_static); n_up += 1 }
  433              else { comps.pop().unwrap(); changed = true }
  434          } else { comps.push(comp) }
  435      }
  436      if changed {
  437          if comps.is_empty() && !is_abs {
  438              if v == bytes!(".") {
  439                  return None;
  440              }
  441              comps.push(dot_static);
  442          }
  443          Some(comps)
  444      } else {
  445          None
  446      }
  447  }
  448  
  449  static dot_static: &'static [u8] = bytes!(".");
  450  static dot_dot_static: &'static [u8] = bytes!("..");
  451  
  452  #[cfg(test)]
  453  mod tests {
  454      use prelude::*;
  455      use super::*;
  456      use str;
  457      use str::StrSlice;
  458  
  459      macro_rules! t(
  460          (s: $path:expr, $exp:expr) => (
  461              {
  462                  let path = $path;
  463                  assert!(path.as_str() == Some($exp));
  464              }
  465          );
  466          (v: $path:expr, $exp:expr) => (
  467              {
  468                  let path = $path;
  469                  assert!(path.as_vec() == $exp);
  470              }
  471          )
  472      )
  473  
  474      macro_rules! b(
  475          ($($arg:expr),+) => (
  476              {
  477                  static the_bytes: &'static [u8] = bytes!($($arg),+);
  478                  the_bytes
  479              }
  480          )
  481      )
  482  
  483      #[test]
  484      fn test_paths() {
  485          let empty: &[u8] = [];
  486          t!(v: Path::new(empty), b!("."));
  487          t!(v: Path::new(b!("/")), b!("/"));
  488          t!(v: Path::new(b!("a/b/c")), b!("a/b/c"));
  489          t!(v: Path::new(b!("a/b/c", 0xff)), b!("a/b/c", 0xff));
  490          t!(v: Path::new(b!(0xff, "/../foo", 0x80)), b!("foo", 0x80));
  491          let p = Path::new(b!("a/b/c", 0xff));
  492          assert!(p.as_str() == None);
  493  
  494          t!(s: Path::new(""), ".");
  495          t!(s: Path::new("/"), "/");
  496          t!(s: Path::new("hi"), "hi");
  497          t!(s: Path::new("hi/"), "hi");
  498          t!(s: Path::new("/lib"), "/lib");
  499          t!(s: Path::new("/lib/"), "/lib");
  500          t!(s: Path::new("hi/there"), "hi/there");
  501          t!(s: Path::new("hi/there.txt"), "hi/there.txt");
  502  
  503          t!(s: Path::new("hi/there/"), "hi/there");
  504          t!(s: Path::new("hi/../there"), "there");
  505          t!(s: Path::new("../hi/there"), "../hi/there");
  506          t!(s: Path::new("/../hi/there"), "/hi/there");
  507          t!(s: Path::new("foo/.."), ".");
  508          t!(s: Path::new("/foo/.."), "/");
  509          t!(s: Path::new("/foo/../.."), "/");
  510          t!(s: Path::new("/foo/../../bar"), "/bar");
  511          t!(s: Path::new("/./hi/./there/."), "/hi/there");
  512          t!(s: Path::new("/./hi/./there/./.."), "/hi");
  513          t!(s: Path::new("foo/../.."), "..");
  514          t!(s: Path::new("foo/../../.."), "../..");
  515          t!(s: Path::new("foo/../../bar"), "../bar");
  516  
  517          assert_eq!(Path::new(b!("foo/bar")).into_vec().as_slice(), b!("foo/bar"));
  518          assert_eq!(Path::new(b!("/foo/../../bar")).into_vec().as_slice(),
  519                     b!("/bar"));
  520  
  521          let p = Path::new(b!("foo/bar", 0x80));
  522          assert!(p.as_str() == None);
  523      }
  524  
  525      #[test]
  526      fn test_opt_paths() {
  527          assert!(Path::new_opt(b!("foo/bar", 0)) == None);
  528          t!(v: Path::new_opt(b!("foo/bar")).unwrap(), b!("foo/bar"));
  529          assert!(Path::new_opt("foo/bar\0") == None);
  530          t!(s: Path::new_opt("foo/bar").unwrap(), "foo/bar");
  531      }
  532  
  533      #[test]
  534      fn test_null_byte() {
  535          use task;
  536          let result = task::try(proc() {
  537              Path::new(b!("foo/bar", 0))
  538          });
  539          assert!(result.is_err());
  540  
  541          let result = task::try(proc() {
  542              Path::new("test").set_filename(b!("f", 0, "o"))
  543          });
  544          assert!(result.is_err());
  545  
  546          let result = task::try(proc() {
  547              Path::new("test").push(b!("f", 0, "o"));
  548          });
  549          assert!(result.is_err());
  550      }
  551  
  552      #[test]
  553      fn test_display_str() {
  554          macro_rules! t(
  555              ($path:expr, $disp:ident, $exp:expr) => (
  556                  {
  557                      let path = Path::new($path);
  558                      assert!(path.$disp().to_str().as_slice() == $exp);
  559                  }
  560              )
  561          )
  562          t!("foo", display, "foo");
  563          t!(b!("foo", 0x80), display, "foo\uFFFD");
  564          t!(b!("foo", 0xff, "bar"), display, "foo\uFFFDbar");
  565          t!(b!("foo", 0xff, "/bar"), filename_display, "bar");
  566          t!(b!("foo/", 0xff, "bar"), filename_display, "\uFFFDbar");
  567          t!(b!("/"), filename_display, "");
  568  
  569          macro_rules! t(
  570              ($path:expr, $exp:expr) => (
  571                  {
  572                      let path = Path::new($path);
  573                      let mo = path.display().as_maybe_owned();
  574                      assert!(mo.as_slice() == $exp);
  575                  }
  576              );
  577              ($path:expr, $exp:expr, filename) => (
  578                  {
  579                      let path = Path::new($path);
  580                      let mo = path.filename_display().as_maybe_owned();
  581                      assert!(mo.as_slice() == $exp);
  582                  }
  583              )
  584          )
  585  
  586          t!("foo", "foo");
  587          t!(b!("foo", 0x80), "foo\uFFFD");
  588          t!(b!("foo", 0xff, "bar"), "foo\uFFFDbar");
  589          t!(b!("foo", 0xff, "/bar"), "bar", filename);
  590          t!(b!("foo/", 0xff, "bar"), "\uFFFDbar", filename);
  591          t!(b!("/"), "", filename);
  592      }
  593  
  594      #[test]
  595      fn test_display() {
  596          macro_rules! t(
  597              ($path:expr, $exp:expr, $expf:expr) => (
  598                  {
  599                      let path = Path::new($path);
  600                      let f = format!("{}", path.display());
  601                      assert!(f.as_slice() == $exp);
  602                      let f = format!("{}", path.filename_display());
  603                      assert!(f.as_slice() == $expf);
  604                  }
  605              )
  606          )
  607  
  608          t!(b!("foo"), "foo", "foo");
  609          t!(b!("foo/bar"), "foo/bar", "bar");
  610          t!(b!("/"), "/", "");
  611          t!(b!("foo", 0xff), "foo\uFFFD", "foo\uFFFD");
  612          t!(b!("foo", 0xff, "/bar"), "foo\uFFFD/bar", "bar");
  613          t!(b!("foo/", 0xff, "bar"), "foo/\uFFFDbar", "\uFFFDbar");
  614          t!(b!(0xff, "foo/bar", 0xff), "\uFFFDfoo/bar\uFFFD", "bar\uFFFD");
  615      }
  616  
  617      #[test]
  618      fn test_components() {
  619          macro_rules! t(
  620              (s: $path:expr, $op:ident, $exp:expr) => (
  621                  {
  622                      let path = Path::new($path);
  623                      assert!(path.$op() == ($exp).as_bytes());
  624                  }
  625              );
  626              (s: $path:expr, $op:ident, $exp:expr, opt) => (
  627                  {
  628                      let path = Path::new($path);
  629                      let left = path.$op().map(|x| str::from_utf8(x).unwrap());
  630                      assert!(left == $exp);
  631                  }
  632              );
  633              (v: $path:expr, $op:ident, $exp:expr) => (
  634                  {
  635                      let arg = $path;
  636                      let path = Path::new(arg);
  637                      assert!(path.$op() == $exp);
  638                  }
  639              );
  640          )
  641  
  642          t!(v: b!("a/b/c"), filename, Some(b!("c")));
  643          t!(v: b!("a/b/c", 0xff), filename, Some(b!("c", 0xff)));
  644          t!(v: b!("a/b", 0xff, "/c"), filename, Some(b!("c")));
  645          t!(s: "a/b/c", filename, Some("c"), opt);
  646          t!(s: "/a/b/c", filename, Some("c"), opt);
  647          t!(s: "a", filename, Some("a"), opt);
  648          t!(s: "/a", filename, Some("a"), opt);
  649          t!(s: ".", filename, None, opt);
  650          t!(s: "/", filename, None, opt);
  651          t!(s: "..", filename, None, opt);
  652          t!(s: "../..", filename, None, opt);
  653  
  654          t!(v: b!("a/b/c"), dirname, b!("a/b"));
  655          t!(v: b!("a/b/c", 0xff), dirname, b!("a/b"));
  656          t!(v: b!("a/b", 0xff, "/c"), dirname, b!("a/b", 0xff));
  657          t!(s: "a/b/c", dirname, "a/b");
  658          t!(s: "/a/b/c", dirname, "/a/b");
  659          t!(s: "a", dirname, ".");
  660          t!(s: "/a", dirname, "/");
  661          t!(s: ".", dirname, ".");
  662          t!(s: "/", dirname, "/");
  663          t!(s: "..", dirname, "..");
  664          t!(s: "../..", dirname, "../..");
  665  
  666          t!(v: b!("hi/there.txt"), filestem, Some(b!("there")));
  667          t!(v: b!("hi/there", 0x80, ".txt"), filestem, Some(b!("there", 0x80)));
  668          t!(v: b!("hi/there.t", 0x80, "xt"), filestem, Some(b!("there")));
  669          t!(s: "hi/there.txt", filestem, Some("there"), opt);
  670          t!(s: "hi/there", filestem, Some("there"), opt);
  671          t!(s: "there.txt", filestem, Some("there"), opt);
  672          t!(s: "there", filestem, Some("there"), opt);
  673          t!(s: ".", filestem, None, opt);
  674          t!(s: "/", filestem, None, opt);
  675          t!(s: "foo/.bar", filestem, Some(".bar"), opt);
  676          t!(s: ".bar", filestem, Some(".bar"), opt);
  677          t!(s: "..bar", filestem, Some("."), opt);
  678          t!(s: "hi/there..txt", filestem, Some("there."), opt);
  679          t!(s: "..", filestem, None, opt);
  680          t!(s: "../..", filestem, None, opt);
  681  
  682          t!(v: b!("hi/there.txt"), extension, Some(b!("txt")));
  683          t!(v: b!("hi/there", 0x80, ".txt"), extension, Some(b!("txt")));
  684          t!(v: b!("hi/there.t", 0x80, "xt"), extension, Some(b!("t", 0x80, "xt")));
  685          t!(v: b!("hi/there"), extension, None);
  686          t!(v: b!("hi/there", 0x80), extension, None);
  687          t!(s: "hi/there.txt", extension, Some("txt"), opt);
  688          t!(s: "hi/there", extension, None, opt);
  689          t!(s: "there.txt", extension, Some("txt"), opt);
  690          t!(s: "there", extension, None, opt);
  691          t!(s: ".", extension, None, opt);
  692          t!(s: "/", extension, None, opt);
  693          t!(s: "foo/.bar", extension, None, opt);
  694          t!(s: ".bar", extension, None, opt);
  695          t!(s: "..bar", extension, Some("bar"), opt);
  696          t!(s: "hi/there..txt", extension, Some("txt"), opt);
  697          t!(s: "..", extension, None, opt);
  698          t!(s: "../..", extension, None, opt);
  699      }
  700  
  701      #[test]
  702      fn test_push() {
  703          macro_rules! t(
  704              (s: $path:expr, $join:expr) => (
  705                  {
  706                      let path = $path;
  707                      let join = $join;
  708                      let mut p1 = Path::new(path);
  709                      let p2 = p1.clone();
  710                      p1.push(join);
  711                      assert!(p1 == p2.join(join));
  712                  }
  713              )
  714          )
  715  
  716          t!(s: "a/b/c", "..");
  717          t!(s: "/a/b/c", "d");
  718          t!(s: "a/b", "c/d");
  719          t!(s: "a/b", "/c/d");
  720      }
  721  
  722      #[test]
  723      fn test_push_path() {
  724          macro_rules! t(
  725              (s: $path:expr, $push:expr, $exp:expr) => (
  726                  {
  727                      let mut p = Path::new($path);
  728                      let push = Path::new($push);
  729                      p.push(&push);
  730                      assert!(p.as_str() == Some($exp));
  731                  }
  732              )
  733          )
  734  
  735          t!(s: "a/b/c", "d", "a/b/c/d");
  736          t!(s: "/a/b/c", "d", "/a/b/c/d");
  737          t!(s: "a/b", "c/d", "a/b/c/d");
  738          t!(s: "a/b", "/c/d", "/c/d");
  739          t!(s: "a/b", ".", "a/b");
  740          t!(s: "a/b", "../c", "a/c");
  741      }
  742  
  743      #[test]
  744      fn test_push_many() {
  745          macro_rules! t(
  746              (s: $path:expr, $push:expr, $exp:expr) => (
  747                  {
  748                      let mut p = Path::new($path);
  749                      p.push_many($push);
  750                      assert!(p.as_str() == Some($exp));
  751                  }
  752              );
  753              (v: $path:expr, $push:expr, $exp:expr) => (
  754                  {
  755                      let mut p = Path::new($path);
  756                      p.push_many($push);
  757                      assert!(p.as_vec() == $exp);
  758                  }
  759              )
  760          )
  761  
  762          t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
  763          t!(s: "a/b/c", ["d", "/e"], "/e");
  764          t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
  765          t!(s: "a/b/c", ["d".to_owned(), "e".to_owned()], "a/b/c/d/e");
  766          t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
  767          t!(v: b!("a/b/c"), [b!("d"), b!("/e"), b!("f")], b!("/e/f"));
  768          t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
  769      }
  770  
  771      #[test]
  772      fn test_pop() {
  773          macro_rules! t(
  774              (s: $path:expr, $left:expr, $right:expr) => (
  775                  {
  776                      let mut p = Path::new($path);
  777                      let result = p.pop();
  778                      assert!(p.as_str() == Some($left));
  779                      assert!(result == $right);
  780                  }
  781              );
  782              (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => (
  783                  {
  784                      let mut p = Path::new(b!($($path),+));
  785                      let result = p.pop();
  786                      assert!(p.as_vec() == b!($($left),+));
  787                      assert!(result == $right);
  788                  }
  789              )
  790          )
  791  
  792          t!(v: ["a/b/c"], ["a/b"], true);
  793          t!(v: ["a"], ["."], true);
  794          t!(v: ["."], ["."], false);
  795          t!(v: ["/a"], ["/"], true);
  796          t!(v: ["/"], ["/"], false);
  797          t!(v: ["a/b/c", 0x80], ["a/b"], true);
  798          t!(v: ["a/b", 0x80, "/c"], ["a/b", 0x80], true);
  799          t!(v: [0xff], ["."], true);
  800          t!(v: ["/", 0xff], ["/"], true);
  801          t!(s: "a/b/c", "a/b", true);
  802          t!(s: "a", ".", true);
  803          t!(s: ".", ".", false);
  804          t!(s: "/a", "/", true);
  805          t!(s: "/", "/", false);
  806      }
  807  
  808      #[test]
  809      fn test_root_path() {
  810          assert!(Path::new(b!("a/b/c")).root_path() == None);
  811          assert!(Path::new(b!("/a/b/c")).root_path() == Some(Path::new("/")));
  812      }
  813  
  814      #[test]
  815      fn test_join() {
  816          t!(v: Path::new(b!("a/b/c")).join(b!("..")), b!("a/b"));
  817          t!(v: Path::new(b!("/a/b/c")).join(b!("d")), b!("/a/b/c/d"));
  818          t!(v: Path::new(b!("a/", 0x80, "/c")).join(b!(0xff)), b!("a/", 0x80, "/c/", 0xff));
  819          t!(s: Path::new("a/b/c").join(".."), "a/b");
  820          t!(s: Path::new("/a/b/c").join("d"), "/a/b/c/d");
  821          t!(s: Path::new("a/b").join("c/d"), "a/b/c/d");
  822          t!(s: Path::new("a/b").join("/c/d"), "/c/d");
  823          t!(s: Path::new(".").join("a/b"), "a/b");
  824          t!(s: Path::new("/").join("a/b"), "/a/b");
  825      }
  826  
  827      #[test]
  828      fn test_join_path() {
  829          macro_rules! t(
  830              (s: $path:expr, $join:expr, $exp:expr) => (
  831                  {
  832                      let path = Path::new($path);
  833                      let join = Path::new($join);
  834                      let res = path.join(&join);
  835                      assert!(res.as_str() == Some($exp));
  836                  }
  837              )
  838          )
  839  
  840          t!(s: "a/b/c", "..", "a/b");
  841          t!(s: "/a/b/c", "d", "/a/b/c/d");
  842          t!(s: "a/b", "c/d", "a/b/c/d");
  843          t!(s: "a/b", "/c/d", "/c/d");
  844          t!(s: ".", "a/b", "a/b");
  845          t!(s: "/", "a/b", "/a/b");
  846      }
  847  
  848      #[test]
  849      fn test_join_many() {
  850          macro_rules! t(
  851              (s: $path:expr, $join:expr, $exp:expr) => (
  852                  {
  853                      let path = Path::new($path);
  854                      let res = path.join_many($join);
  855                      assert!(res.as_str() == Some($exp));
  856                  }
  857              );
  858              (v: $path:expr, $join:expr, $exp:expr) => (
  859                  {
  860                      let path = Path::new($path);
  861                      let res = path.join_many($join);
  862                      assert!(res.as_vec() == $exp);
  863                  }
  864              )
  865          )
  866  
  867          t!(s: "a/b/c", ["d", "e"], "a/b/c/d/e");
  868          t!(s: "a/b/c", ["..", "d"], "a/b/d");
  869          t!(s: "a/b/c", ["d", "/e", "f"], "/e/f");
  870          t!(s: "a/b/c", ["d".to_owned(), "e".to_owned()], "a/b/c/d/e");
  871          t!(v: b!("a/b/c"), [b!("d"), b!("e")], b!("a/b/c/d/e"));
  872          t!(v: b!("a/b/c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))], b!("a/b/c/d/e"));
  873      }
  874  
  875      #[test]
  876      fn test_with_helpers() {
  877          let empty: &[u8] = [];
  878  
  879          t!(v: Path::new(b!("a/b/c")).with_filename(b!("d")), b!("a/b/d"));
  880          t!(v: Path::new(b!("a/b/c", 0xff)).with_filename(b!(0x80)), b!("a/b/", 0x80));
  881          t!(v: Path::new(b!("/", 0xff, "/foo")).with_filename(b!(0xcd)),
  882                b!("/", 0xff, "/", 0xcd));
  883          t!(s: Path::new("a/b/c").with_filename("d"), "a/b/d");
  884          t!(s: Path::new(".").with_filename("foo"), "foo");
  885          t!(s: Path::new("/a/b/c").with_filename("d"), "/a/b/d");
  886          t!(s: Path::new("/").with_filename("foo"), "/foo");
  887          t!(s: Path::new("/a").with_filename("foo"), "/foo");
  888          t!(s: Path::new("foo").with_filename("bar"), "bar");
  889          t!(s: Path::new("/").with_filename("foo/"), "/foo");
  890          t!(s: Path::new("/a").with_filename("foo/"), "/foo");
  891          t!(s: Path::new("a/b/c").with_filename(""), "a/b");
  892          t!(s: Path::new("a/b/c").with_filename("."), "a/b");
  893          t!(s: Path::new("a/b/c").with_filename(".."), "a");
  894          t!(s: Path::new("/a").with_filename(""), "/");
  895          t!(s: Path::new("foo").with_filename(""), ".");
  896          t!(s: Path::new("a/b/c").with_filename("d/e"), "a/b/d/e");
  897          t!(s: Path::new("a/b/c").with_filename("/d"), "a/b/d");
  898          t!(s: Path::new("..").with_filename("foo"), "../foo");
  899          t!(s: Path::new("../..").with_filename("foo"), "../../foo");
  900          t!(s: Path::new("..").with_filename(""), "..");
  901          t!(s: Path::new("../..").with_filename(""), "../..");
  902  
  903          t!(v: Path::new(b!("hi/there", 0x80, ".txt")).with_extension(b!("exe")),
  904                b!("hi/there", 0x80, ".exe"));
  905          t!(v: Path::new(b!("hi/there.txt", 0x80)).with_extension(b!(0xff)),
  906                b!("hi/there.", 0xff));
  907          t!(v: Path::new(b!("hi/there", 0x80)).with_extension(b!(0xff)),
  908                b!("hi/there", 0x80, ".", 0xff));
  909          t!(v: Path::new(b!("hi/there.", 0xff)).with_extension(empty), b!("hi/there"));
  910          t!(s: Path::new("hi/there.txt").with_extension("exe"), "hi/there.exe");
  911          t!(s: Path::new("hi/there.txt").with_extension(""), "hi/there");
  912          t!(s: Path::new("hi/there.txt").with_extension("."), "hi/there..");
  913          t!(s: Path::new("hi/there.txt").with_extension(".."), "hi/there...");
  914          t!(s: Path::new("hi/there").with_extension("txt"), "hi/there.txt");
  915          t!(s: Path::new("hi/there").with_extension("."), "hi/there..");
  916          t!(s: Path::new("hi/there").with_extension(".."), "hi/there...");
  917          t!(s: Path::new("hi/there.").with_extension("txt"), "hi/there.txt");
  918          t!(s: Path::new("hi/.foo").with_extension("txt"), "hi/.foo.txt");
  919          t!(s: Path::new("hi/there.txt").with_extension(".foo"), "hi/there..foo");
  920          t!(s: Path::new("/").with_extension("txt"), "/");
  921          t!(s: Path::new("/").with_extension("."), "/");
  922          t!(s: Path::new("/").with_extension(".."), "/");
  923          t!(s: Path::new(".").with_extension("txt"), ".");
  924      }
  925  
  926      #[test]
  927      fn test_setters() {
  928          macro_rules! t(
  929              (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
  930                  {
  931                      let path = $path;
  932                      let arg = $arg;
  933                      let mut p1 = Path::new(path);
  934                      p1.$set(arg);
  935                      let p2 = Path::new(path);
  936                      assert!(p1 == p2.$with(arg));
  937                  }
  938              );
  939              (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
  940                  {
  941                      let path = $path;
  942                      let arg = $arg;
  943                      let mut p1 = Path::new(path);
  944                      p1.$set(arg);
  945                      let p2 = Path::new(path);
  946                      assert!(p1 == p2.$with(arg));
  947                  }
  948              )
  949          )
  950  
  951          t!(v: b!("a/b/c"), set_filename, with_filename, b!("d"));
  952          t!(v: b!("/"), set_filename, with_filename, b!("foo"));
  953          t!(v: b!(0x80), set_filename, with_filename, b!(0xff));
  954          t!(s: "a/b/c", set_filename, with_filename, "d");
  955          t!(s: "/", set_filename, with_filename, "foo");
  956          t!(s: ".", set_filename, with_filename, "foo");
  957          t!(s: "a/b", set_filename, with_filename, "");
  958          t!(s: "a", set_filename, with_filename, "");
  959  
  960          t!(v: b!("hi/there.txt"), set_extension, with_extension, b!("exe"));
  961          t!(v: b!("hi/there.t", 0x80, "xt"), set_extension, with_extension, b!("exe", 0xff));
  962          t!(s: "hi/there.txt", set_extension, with_extension, "exe");
  963          t!(s: "hi/there.", set_extension, with_extension, "txt");
  964          t!(s: "hi/there", set_extension, with_extension, "txt");
  965          t!(s: "hi/there.txt", set_extension, with_extension, "");
  966          t!(s: "hi/there", set_extension, with_extension, "");
  967          t!(s: ".", set_extension, with_extension, "txt");
  968      }
  969  
  970      #[test]
  971      fn test_getters() {
  972          macro_rules! t(
  973              (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
  974                  {
  975                      let path = $path;
  976                      let filename = $filename;
  977                      assert!(path.filename_str() == filename,
  978                              "{}.filename_str(): Expected `{:?}`, found {:?}",
  979                              path.as_str().unwrap(), filename, path.filename_str());
  980                      let dirname = $dirname;
  981                      assert!(path.dirname_str() == dirname,
  982                              "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
  983                              path.as_str().unwrap(), dirname, path.dirname_str());
  984                      let filestem = $filestem;
  985                      assert!(path.filestem_str() == filestem,
  986                              "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
  987                              path.as_str().unwrap(), filestem, path.filestem_str());
  988                      let ext = $ext;
  989                      assert!(path.extension_str() == ext,
  990                              "`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
  991                              path.as_str().unwrap(), ext, path.extension_str());
  992                  }
  993              );
  994              (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
  995                  {
  996                      let path = $path;
  997                      assert!(path.filename() == $filename);
  998                      assert!(path.dirname() == $dirname);
  999                      assert!(path.filestem() == $filestem);
 1000                      assert!(path.extension() == $ext);
 1001                  }
 1002              )
 1003          )
 1004  
 1005          t!(v: Path::new(b!("a/b/c")), Some(b!("c")), b!("a/b"), Some(b!("c")), None);
 1006          t!(v: Path::new(b!("a/b/", 0xff)), Some(b!(0xff)), b!("a/b"), Some(b!(0xff)), None);
 1007          t!(v: Path::new(b!("hi/there.", 0xff)), Some(b!("there.", 0xff)), b!("hi"),
 1008                Some(b!("there")), Some(b!(0xff)));
 1009          t!(s: Path::new("a/b/c"), Some("c"), Some("a/b"), Some("c"), None);
 1010          t!(s: Path::new("."), None, Some("."), None, None);
 1011          t!(s: Path::new("/"), None, Some("/"), None, None);
 1012          t!(s: Path::new(".."), None, Some(".."), None, None);
 1013          t!(s: Path::new("../.."), None, Some("../.."), None, None);
 1014          t!(s: Path::new("hi/there.txt"), Some("there.txt"), Some("hi"),
 1015                Some("there"), Some("txt"));
 1016          t!(s: Path::new("hi/there"), Some("there"), Some("hi"), Some("there"), None);
 1017          t!(s: Path::new("hi/there."), Some("there."), Some("hi"),
 1018                Some("there"), Some(""));
 1019          t!(s: Path::new("hi/.there"), Some(".there"), Some("hi"), Some(".there"), None);
 1020          t!(s: Path::new("hi/..there"), Some("..there"), Some("hi"),
 1021                Some("."), Some("there"));
 1022          t!(s: Path::new(b!("a/b/", 0xff)), None, Some("a/b"), None, None);
 1023          t!(s: Path::new(b!("a/b/", 0xff, ".txt")), None, Some("a/b"), None, Some("txt"));
 1024          t!(s: Path::new(b!("a/b/c.", 0x80)), None, Some("a/b"), Some("c"), None);
 1025          t!(s: Path::new(b!(0xff, "/b")), Some("b"), None, Some("b"), None);
 1026      }
 1027  
 1028      #[test]
 1029      fn test_dir_path() {
 1030          t!(v: Path::new(b!("hi/there", 0x80)).dir_path(), b!("hi"));
 1031          t!(v: Path::new(b!("hi", 0xff, "/there")).dir_path(), b!("hi", 0xff));
 1032          t!(s: Path::new("hi/there").dir_path(), "hi");
 1033          t!(s: Path::new("hi").dir_path(), ".");
 1034          t!(s: Path::new("/hi").dir_path(), "/");
 1035          t!(s: Path::new("/").dir_path(), "/");
 1036          t!(s: Path::new("..").dir_path(), "..");
 1037          t!(s: Path::new("../..").dir_path(), "../..");
 1038      }
 1039  
 1040      #[test]
 1041      fn test_is_absolute() {
 1042          macro_rules! t(
 1043              (s: $path:expr, $abs:expr, $rel:expr) => (
 1044                  {
 1045                      let path = Path::new($path);
 1046                      assert_eq!(path.is_absolute(), $abs);
 1047                      assert_eq!(path.is_relative(), $rel);
 1048                  }
 1049              )
 1050          )
 1051          t!(s: "a/b/c", false, true);
 1052          t!(s: "/a/b/c", true, false);
 1053          t!(s: "a", false, true);
 1054          t!(s: "/a", true, false);
 1055          t!(s: ".", false, true);
 1056          t!(s: "/", true, false);
 1057          t!(s: "..", false, true);
 1058          t!(s: "../..", false, true);
 1059      }
 1060  
 1061      #[test]
 1062      fn test_is_ancestor_of() {
 1063          macro_rules! t(
 1064              (s: $path:expr, $dest:expr, $exp:expr) => (
 1065                  {
 1066                      let path = Path::new($path);
 1067                      let dest = Path::new($dest);
 1068                      assert_eq!(path.is_ancestor_of(&dest), $exp);
 1069                  }
 1070              )
 1071          )
 1072  
 1073          t!(s: "a/b/c", "a/b/c/d", true);
 1074          t!(s: "a/b/c", "a/b/c", true);
 1075          t!(s: "a/b/c", "a/b", false);
 1076          t!(s: "/a/b/c", "/a/b/c", true);
 1077          t!(s: "/a/b", "/a/b/c", true);
 1078          t!(s: "/a/b/c/d", "/a/b/c", false);
 1079          t!(s: "/a/b", "a/b/c", false);
 1080          t!(s: "a/b", "/a/b/c", false);
 1081          t!(s: "a/b/c", "a/b/d", false);
 1082          t!(s: "../a/b/c", "a/b/c", false);
 1083          t!(s: "a/b/c", "../a/b/c", false);
 1084          t!(s: "a/b/c", "a/b/cd", false);
 1085          t!(s: "a/b/cd", "a/b/c", false);
 1086          t!(s: "../a/b", "../a/b/c", true);
 1087          t!(s: ".", "a/b", true);
 1088          t!(s: ".", ".", true);
 1089          t!(s: "/", "/", true);
 1090          t!(s: "/", "/a/b", true);
 1091          t!(s: "..", "a/b", true);
 1092          t!(s: "../..", "a/b", true);
 1093      }
 1094  
 1095      #[test]
 1096      fn test_ends_with_path() {
 1097          macro_rules! t(
 1098              (s: $path:expr, $child:expr, $exp:expr) => (
 1099                  {
 1100                      let path = Path::new($path);
 1101                      let child = Path::new($child);
 1102                      assert_eq!(path.ends_with_path(&child), $exp);
 1103                  }
 1104              );
 1105              (v: $path:expr, $child:expr, $exp:expr) => (
 1106                  {
 1107                      let path = Path::new($path);
 1108                      let child = Path::new($child);
 1109                      assert_eq!(path.ends_with_path(&child), $exp);
 1110                  }
 1111              )
 1112          )
 1113  
 1114          t!(s: "a/b/c", "c", true);
 1115          t!(s: "a/b/c", "d", false);
 1116          t!(s: "foo/bar/quux", "bar", false);
 1117          t!(s: "foo/bar/quux", "barquux", false);
 1118          t!(s: "a/b/c", "b/c", true);
 1119          t!(s: "a/b/c", "a/b/c", true);
 1120          t!(s: "a/b/c", "foo/a/b/c", false);
 1121          t!(s: "/a/b/c", "a/b/c", true);
 1122          t!(s: "/a/b/c", "/a/b/c", false); // child must be relative
 1123          t!(s: "/a/b/c", "foo/a/b/c", false);
 1124          t!(s: "a/b/c", "", false);
 1125          t!(s: "", "", true);
 1126          t!(s: "/a/b/c", "d/e/f", false);
 1127          t!(s: "a/b/c", "a/b", false);
 1128          t!(s: "a/b/c", "b", false);
 1129          t!(v: b!("a/b/c"), b!("b/c"), true);
 1130          t!(v: b!("a/b/", 0xff), b!(0xff), true);
 1131          t!(v: b!("a/b/", 0xff), b!("b/", 0xff), true);
 1132      }
 1133  
 1134      #[test]
 1135      fn test_path_relative_from() {
 1136          macro_rules! t(
 1137              (s: $path:expr, $other:expr, $exp:expr) => (
 1138                  {
 1139                      let path = Path::new($path);
 1140                      let other = Path::new($other);
 1141                      let res = path.path_relative_from(&other);
 1142                      assert_eq!(res.as_ref().and_then(|x| x.as_str()), $exp);
 1143                  }
 1144              )
 1145          )
 1146  
 1147          t!(s: "a/b/c", "a/b", Some("c"));
 1148          t!(s: "a/b/c", "a/b/d", Some("../c"));
 1149          t!(s: "a/b/c", "a/b/c/d", Some(".."));
 1150          t!(s: "a/b/c", "a/b/c", Some("."));
 1151          t!(s: "a/b/c", "a/b/c/d/e", Some("../.."));
 1152          t!(s: "a/b/c", "a/d/e", Some("../../b/c"));
 1153          t!(s: "a/b/c", "d/e/f", Some("../../../a/b/c"));
 1154          t!(s: "a/b/c", "/a/b/c", None);
 1155          t!(s: "/a/b/c", "a/b/c", Some("/a/b/c"));
 1156          t!(s: "/a/b/c", "/a/b/c/d", Some(".."));
 1157          t!(s: "/a/b/c", "/a/b", Some("c"));
 1158          t!(s: "/a/b/c", "/a/b/c/d/e", Some("../.."));
 1159          t!(s: "/a/b/c", "/a/d/e", Some("../../b/c"));
 1160          t!(s: "/a/b/c", "/d/e/f", Some("../../../a/b/c"));
 1161          t!(s: "hi/there.txt", "hi/there", Some("../there.txt"));
 1162          t!(s: ".", "a", Some(".."));
 1163          t!(s: ".", "a/b", Some("../.."));
 1164          t!(s: ".", ".", Some("."));
 1165          t!(s: "a", ".", Some("a"));
 1166          t!(s: "a/b", ".", Some("a/b"));
 1167          t!(s: "..", ".", Some(".."));
 1168          t!(s: "a/b/c", "a/b/c", Some("."));
 1169          t!(s: "/a/b/c", "/a/b/c", Some("."));
 1170          t!(s: "/", "/", Some("."));
 1171          t!(s: "/", ".", Some("/"));
 1172          t!(s: "../../a", "b", Some("../../../a"));
 1173          t!(s: "a", "../../b", None);
 1174          t!(s: "../../a", "../../b", Some("../a"));
 1175          t!(s: "../../a", "../../a/b", Some(".."));
 1176          t!(s: "../../a/b", "../../a", Some("b"));
 1177      }
 1178  
 1179      #[test]
 1180      fn test_components_iter() {
 1181          macro_rules! t(
 1182              (s: $path:expr, $exp:expr) => (
 1183                  {
 1184                      let path = Path::new($path);
 1185                      let comps = path.components().collect::<Vec<&[u8]>>();
 1186                      let exp: &[&str] = $exp;
 1187                      let exps = exp.iter().map(|x| x.as_bytes()).collect::<Vec<&[u8]>>();
 1188                      assert!(comps == exps, "components: Expected {:?}, found {:?}",
 1189                              comps, exps);
 1190                      let comps = path.components().rev().collect::<Vec<&[u8]>>();
 1191                      let exps = exps.move_iter().rev().collect::<Vec<&[u8]>>();
 1192                      assert!(comps == exps, "rev_components: Expected {:?}, found {:?}",
 1193                              comps, exps);
 1194                  }
 1195              );
 1196              (v: [$($arg:expr),+], [$([$($exp:expr),*]),*]) => (
 1197                  {
 1198                      let path = Path::new(b!($($arg),+));
 1199                      let comps = path.components().collect::<Vec<&[u8]>>();
 1200                      let exp: &[&[u8]] = [$(b!($($exp),*)),*];
 1201                      assert_eq!(comps.as_slice(), exp);
 1202                      let comps = path.components().rev().collect::<Vec<&[u8]>>();
 1203                      let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
 1204                      assert_eq!(comps, exp)
 1205                  }
 1206              )
 1207          )
 1208  
 1209          t!(v: ["a/b/c"], [["a"], ["b"], ["c"]]);
 1210          t!(v: ["/", 0xff, "/a/", 0x80], [[0xff], ["a"], [0x80]]);
 1211          t!(v: ["../../foo", 0xcd, "bar"], [[".."], [".."], ["foo", 0xcd, "bar"]]);
 1212          t!(s: "a/b/c", ["a", "b", "c"]);
 1213          t!(s: "a/b/d", ["a", "b", "d"]);
 1214          t!(s: "a/b/cd", ["a", "b", "cd"]);
 1215          t!(s: "/a/b/c", ["a", "b", "c"]);
 1216          t!(s: "a", ["a"]);
 1217          t!(s: "/a", ["a"]);
 1218          t!(s: "/", []);
 1219          t!(s: ".", ["."]);
 1220          t!(s: "..", [".."]);
 1221          t!(s: "../..", ["..", ".."]);
 1222          t!(s: "../../foo", ["..", "..", "foo"]);
 1223      }
 1224  
 1225      #[test]
 1226      fn test_str_components() {
 1227          macro_rules! t(
 1228              (v: [$($arg:expr),+], $exp:expr) => (
 1229                  {
 1230                      let path = Path::new(b!($($arg),+));
 1231                      let comps = path.str_components().collect::<Vec<Option<&str>>>();
 1232                      let exp: &[Option<&str>] = $exp;
 1233                      assert_eq!(comps.as_slice(), exp);
 1234                      let comps = path.str_components().rev().collect::<Vec<Option<&str>>>();
 1235                      let exp = exp.iter().rev().map(|&x|x).collect::<Vec<Option<&str>>>();
 1236                      assert_eq!(comps, exp);
 1237                  }
 1238              )
 1239          )
 1240  
 1241          t!(v: ["a/b/c"], [Some("a"), Some("b"), Some("c")]);
 1242          t!(v: ["/", 0xff, "/a/", 0x80], [None, Some("a"), None]);
 1243          t!(v: ["../../foo", 0xcd, "bar"], [Some(".."), Some(".."), None]);
 1244          // str_components is a wrapper around components, so no need to do
 1245          // the full set of tests
 1246      }
 1247  }
 1248  
 1249  #[cfg(test)]
 1250  mod bench {
 1251      extern crate test;
 1252      use self::test::Bencher;
 1253      use super::*;
 1254      use prelude::*;
 1255  
 1256      #[bench]
 1257      fn join_home_dir(b: &mut Bencher) {
 1258          let posix_path = Path::new("/");
 1259          b.iter(|| {
 1260              posix_path.join("home");
 1261          });
 1262      }
 1263  
 1264      #[bench]
 1265      fn join_abs_path_home_dir(b: &mut Bencher) {
 1266          let posix_path = Path::new("/");
 1267          b.iter(|| {
 1268              posix_path.join("/home");
 1269          });
 1270      }
 1271  
 1272      #[bench]
 1273      fn join_many_home_dir(b: &mut Bencher) {
 1274          let posix_path = Path::new("/");
 1275          b.iter(|| {
 1276              posix_path.join_many(&["home"]);
 1277          });
 1278      }
 1279  
 1280      #[bench]
 1281      fn join_many_abs_path_home_dir(b: &mut Bencher) {
 1282          let posix_path = Path::new("/");
 1283          b.iter(|| {
 1284              posix_path.join_many(&["/home"]);
 1285          });
 1286      }
 1287  
 1288      #[bench]
 1289      fn push_home_dir(b: &mut Bencher) {
 1290          let mut posix_path = Path::new("/");
 1291          b.iter(|| {
 1292              posix_path.push("home");
 1293          });
 1294      }
 1295  
 1296      #[bench]
 1297      fn push_abs_path_home_dir(b: &mut Bencher) {
 1298          let mut posix_path = Path::new("/");
 1299          b.iter(|| {
 1300              posix_path.push("/home");
 1301          });
 1302      }
 1303  
 1304      #[bench]
 1305      fn push_many_home_dir(b: &mut Bencher) {
 1306          let mut posix_path = Path::new("/");
 1307          b.iter(|| {
 1308              posix_path.push_many(&["home"]);
 1309          });
 1310      }
 1311  
 1312      #[bench]
 1313      fn push_many_abs_path_home_dir(b: &mut Bencher) {
 1314          let mut posix_path = Path::new("/");
 1315          b.iter(|| {
 1316              posix_path.push_many(&["/home"]);
 1317          });
 1318      }
 1319  
 1320      #[bench]
 1321      fn ends_with_path_home_dir(b: &mut Bencher) {
 1322          let posix_home_path = Path::new("/home");
 1323          b.iter(|| {
 1324              posix_home_path.ends_with_path(&Path::new("home"));
 1325          });
 1326      }
 1327  
 1328      #[bench]
 1329      fn ends_with_path_missmatch_jome_home(b: &mut Bencher) {
 1330          let posix_home_path = Path::new("/home");
 1331          b.iter(|| {
 1332              posix_home_path.ends_with_path(&Path::new("jome"));
 1333          });
 1334      }
 1335  
 1336      #[bench]
 1337      fn is_ancestor_of_path_with_10_dirs(b: &mut Bencher) {
 1338          let path = Path::new("/home/1/2/3/4/5/6/7/8/9");
 1339          let mut sub = path.clone();
 1340          sub.pop();
 1341          b.iter(|| {
 1342              path.is_ancestor_of(&sub);
 1343          });
 1344      }
 1345  
 1346      #[bench]
 1347      fn path_relative_from_forward(b: &mut Bencher) {
 1348          let path = Path::new("/a/b/c");
 1349          let mut other = path.clone();
 1350          other.pop();
 1351          b.iter(|| {
 1352              path.path_relative_from(&other);
 1353          });
 1354      }
 1355  
 1356      #[bench]
 1357      fn path_relative_from_same_level(b: &mut Bencher) {
 1358          let path = Path::new("/a/b/c");
 1359          let mut other = path.clone();
 1360          other.pop();
 1361          other.push("d");
 1362          b.iter(|| {
 1363              path.path_relative_from(&other);
 1364          });
 1365      }
 1366  
 1367      #[bench]
 1368      fn path_relative_from_backward(b: &mut Bencher) {
 1369          let path = Path::new("/a/b");
 1370          let mut other = path.clone();
 1371          other.push("c");
 1372          b.iter(|| {
 1373              path.path_relative_from(&other);
 1374          });
 1375      }
 1376  }


libstd/path/posix.rs:43:19-43:19 -struct- definition:
pub struct Path {
    repr: Vec<u8>, // assumed to never be empty or contain NULs
    sepidx: Option<uint> // index of the final separator in repr
references:- 82
libstd/unstable/dynamic_lib.rs:
libstd/rt/rtio.rs:
libstd/os.rs:
libstd/io/mod.rs:
libstd/io/test.rs:
libstd/io/tempfile.rs:
libstd/io/fs.rs:
libstd/io/process.rs:
libstd/io/fs.rs:


libstd/path/posix.rs:35:73-35:73 -NK_AS_STR_TODO- definition:
/// Iterator that yields successive components of a Path as Option<&str>
pub type StrComponents<'a> = Map<'a, &'a [u8], Option<&'a str>,
                                       Components<'a>>;
references:- 3
40: pub type RevStrComponents<'a> = Rev<StrComponents<'a>>;
--
406:     /// See components() for details.
407:     pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
408:         self.components().map(str::from_utf8)
--
413:     #[deprecated = "replaced by .str_components().rev()"]
414:     pub fn rev_str_components<'a>(&'a self) -> Rev<StrComponents<'a>> {
415:         self.str_components().rev()


libstd/path/posix.rs:29:66-29:66 -NK_AS_STR_TODO- definition:
/// Iterator that yields successive components of a Path as &[u8]
pub type Components<'a> = Splits<'a, u8>;
/// Iterator that yields components of a Path in reverse as &[u8]
references:- 4
400:     #[deprecated = "replaced by .components().rev()"]
401:     pub fn rev_components<'a>(&'a self) -> Rev<Components<'a>> {
402:         self.components().rev()


libstd/path/posix.rs:56:10-56:10 -fn- definition:
pub fn is_sep_byte(u: &u8) -> bool {
    *u as char == SEP
}
references:- 2
389:         } else { self.repr.as_slice() };
390:         let mut ret = v.split(is_sep_byte);
391:         if v.is_empty() {
--
426:     let mut changed = false;
427:     for comp in v.split(is_sep_byte) {
428:         if comp.is_empty() { changed = true }