(index<- )        ./libstd/path/windows.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  //! Windows file path handling
   12  
   13  use ascii::AsciiCast;
   14  use c_str::{CString, ToCStr};
   15  use cast;
   16  use clone::Clone;
   17  use container::Container;
   18  use cmp::{Eq, TotalEq};
   19  use from_str::FromStr;
   20  use io::Writer;
   21  use iter::{AdditiveIterator, DoubleEndedIterator, Extendable, Rev, Iterator, Map};
   22  use option::{Option, Some, None};
   23  use slice::{Vector, OwnedVector, ImmutableVector};
   24  use str::{CharSplits, Str, StrAllocating, StrVector, StrSlice};
   25  use strbuf::StrBuf;
   26  use vec::Vec;
   27  
   28  use super::{contains_nul, BytesContainer, GenericPath, GenericPathUnsafe};
   29  
   30  /// Iterator that yields successive components of a Path as &str
   31  ///
   32  /// Each component is yielded as Option<&str> for compatibility with PosixPath, but
   33  /// every component in WindowsPath is guaranteed to be Some.
   34  pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>,
   35                                         CharSplits<'a, char>>;
   36  /// Iterator that yields components of a Path in reverse as &str
   37  ///
   38  /// Each component is yielded as Option<&str> for compatibility with PosixPath, but
   39  /// every component in WindowsPath is guaranteed to be Some.
   40  #[deprecated = "replaced by Rev<StrComponents<'a>>"]
   41  pub type RevStrComponents<'a> = Rev<StrComponents<'a>>;
   42  
   43  /// Iterator that yields successive components of a Path as &[u8]
   44  pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8],
   45                                      StrComponents<'a>>;
   46  /// Iterator that yields components of a Path in reverse as &[u8]
   47  #[deprecated = "replaced by Rev<Components<'a>>"]
   48  pub type RevComponents<'a> = Rev<Components<'a>>;
   49  
   50  /// Represents a Windows path
   51  // Notes for Windows path impl:
   52  // The MAX_PATH is 260, but 253 is the practical limit due to some API bugs
   53  // See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx for good information
   54  // about windows paths.
   55  // That same page puts a bunch of restrictions on allowed characters in a path.
   56  // `\foo.txt` means "relative to current drive", but will not be considered to be absolute here
   57  // as `∃P | P.join("\foo.txt") != "\foo.txt"`.
   58  // `C:` is interesting, that means "the current directory on drive C".
   59  // Long absolute paths need to have \\?\ prefix (or, for UNC, \\?\UNC\). I think that can be
   60  // ignored for now, though, and only added in a hypothetical .to_pwstr() function.
   61  // However, if a path is parsed that has \\?\, this needs to be preserved as it disables the
   62  // processing of "." and ".." components and / as a separator.
   63  // Experimentally, \\?\foo is not the same thing as \foo.
   64  // Also, \\foo is not valid either (certainly not equivalent to \foo).
   65  // Similarly, C:\\Users is not equivalent to C:\Users, although C:\Users\\foo is equivalent
   66  // to C:\Users\foo. In fact the command prompt treats C:\\foo\bar as UNC path. But it might be
   67  // best to just ignore that and normalize it to C:\foo\bar.
   68  //
   69  // Based on all this, I think the right approach is to do the following:
   70  // * Require valid utf-8 paths. Windows API may use WCHARs, but we don't, and utf-8 is convertible
   71  // to UTF-16 anyway (though does Windows use UTF-16 or UCS-2? Not sure).
   72  // * Parse the prefixes \\?\UNC\, \\?\, and \\.\ explicitly.
   73  // * If \\?\UNC\, treat following two path components as server\share. Don't error for missing
   74  //   server\share.
   75  // * If \\?\, parse disk from following component, if present. Don't error for missing disk.
   76  // * If \\.\, treat rest of path as just regular components. I don't know how . and .. are handled
   77  //   here, they probably aren't, but I'm not going to worry about that.
   78  // * Else if starts with \\, treat following two components as server\share. Don't error for missing
   79  //   server\share.
   80  // * Otherwise, attempt to parse drive from start of path.
   81  //
   82  // The only error condition imposed here is valid utf-8. All other invalid paths are simply
   83  // preserved by the data structure; let the Windows API error out on them.
   84  #[deriving(Clone)]
   85  pub struct Path {
   86      repr: StrBuf, // assumed to never be empty
   87      prefix: Option<PathPrefix>,
   88      sepidx: Option<uint> // index of the final separator in the non-prefix portion of repr
   89  }
   90  
   91  impl Eq for Path {
   92      #[inline]
   93      fn eq(&self, other&Path) -> bool {
   94          self.repr == other.repr
   95      }
   96  }
   97  
   98  impl TotalEq for Path {}
   99  
  100  impl FromStr for Path {
  101      fn from_str(s&str) -> Option<Path> {
  102          Path::new_opt(s)
  103      }
  104  }
  105  
  106  impl ToCStr for Path {
  107      #[inline]
  108      fn to_c_str(&self) -> CString {
  109          // The Path impl guarantees no embedded NULs
  110          unsafe { self.as_vec().to_c_str_unchecked() }
  111      }
  112  
  113      #[inline]
  114      unsafe fn to_c_str_unchecked(&self) -> CString {
  115          self.as_vec().to_c_str_unchecked()
  116      }
  117  }
  118  
  119  impl<S: Writer> ::hash::Hash<S> for Path {
  120      #[inline]
  121      fn hash(&self, state&mut S) {
  122          self.repr.hash(state)
  123      }
  124  }
  125  
  126  impl BytesContainer for Path {
  127      #[inline]
  128      fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
  129          self.as_vec()
  130      }
  131      #[inline]
  132      fn container_into_owned_bytes(self) -> Vec<u8> {
  133          self.into_vec()
  134      }
  135      #[inline]
  136      fn container_as_str<'a>(&'a self) -> Option<&'a str> {
  137          self.as_str()
  138      }
  139      #[inline]
  140      fn is_str(_Option<Path>) -> bool { true }
  141  }
  142  
  143  impl<'a> BytesContainer for &'a Path {
  144      #[inline]
  145      fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
  146          self.as_vec()
  147      }
  148      #[inline]
  149      fn container_as_str<'a>(&'a self) -> Option<&'a str> {
  150          self.as_str()
  151      }
  152      #[inline]
  153      fn is_str(_Option<&'a Path>) -> bool { true }
  154  }
  155  
  156  impl GenericPathUnsafe for Path {
  157      /// See `GenericPathUnsafe::from_vec_unchecked`.
  158      ///
  159      /// # Failure
  160      ///
  161      /// Fails if not valid UTF-8.
  162      #[inline]
  163      unsafe fn new_unchecked<T: BytesContainer>(pathT) -> Path {
  164          let (prefix, path) = Path::normalize_(path.container_as_str().unwrap());
  165          assert!(!path.is_empty());
  166          let mut ret = Path{ repr: path, prefix: prefix, sepidx: None };
  167          ret.update_sepidx();
  168          ret
  169      }
  170  
  171      /// See `GenericPathUnsafe::set_filename_unchecekd`.
  172      ///
  173      /// # Failure
  174      ///
  175      /// Fails if not valid UTF-8.
  176      unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filenameT) {
  177          let filename = filename.container_as_str().unwrap();
  178          match self.sepidx_or_prefix_len() {
  179              None if ".." == self.repr.as_slice() => {
  180                  let mut s = StrBuf::with_capacity(3 + filename.len());
  181                  s.push_str("..");
  182                  s.push_char(SEP);
  183                  s.push_str(filename);
  184                  self.update_normalized(s);
  185              }
  186              None => {
  187                  self.update_normalized(filename);
  188              }
  189              Some((_,idxa,end)) if self.repr.as_slice().slice(idxa,end) == ".." => {
  190                  let mut s = StrBuf::with_capacity(end + 1 + filename.len());
  191                  s.push_str(self.repr.as_slice().slice_to(end));
  192                  s.push_char(SEP);
  193                  s.push_str(filename);
  194                  self.update_normalized(s);
  195              }
  196              Some((idxb,idxa,_)) if self.prefix == Some(DiskPrefix) && idxa == self.prefix_len() => {
  197                  let mut s = StrBuf::with_capacity(idxb + filename.len());
  198                  s.push_str(self.repr.as_slice().slice_to(idxb));
  199                  s.push_str(filename);
  200                  self.update_normalized(s);
  201              }
  202              Some((idxb,_,_)) => {
  203                  let mut s = StrBuf::with_capacity(idxb + 1 + filename.len());
  204                  s.push_str(self.repr.as_slice().slice_to(idxb));
  205                  s.push_char(SEP);
  206                  s.push_str(filename);
  207                  self.update_normalized(s);
  208              }
  209          }
  210      }
  211  
  212      /// See `GenericPathUnsafe::push_unchecked`.
  213      ///
  214      /// Concatenating two Windows Paths is rather complicated.
  215      /// For the most part, it will behave as expected, except in the case of
  216      /// pushing a volume-relative path, e.g. `C:foo.txt`. Because we have no
  217      /// concept of per-volume cwds like Windows does, we can't behave exactly
  218      /// like Windows will. Instead, if the receiver is an absolute path on
  219      /// the same volume as the new path, it will be treated as the cwd that
  220      /// the new path is relative to. Otherwise, the new path will be treated
  221      /// as if it were absolute and will replace the receiver outright.
  222      unsafe fn push_unchecked<T: BytesContainer>(&mut self, pathT) {
  223          let path = path.container_as_str().unwrap();
  224          fn is_vol_abs(path: &str, prefixOption<PathPrefix>) -> bool {
  225              // assume prefix is Some(DiskPrefix)
  226              let rest = path.slice_from(prefix_len(prefix));
  227              !rest.is_empty() && rest[0].is_ascii() && is_sep(rest[0] as char)
  228          }
  229          fn shares_volume(me: &Path, path: &str) -> bool {
  230              // path is assumed to have a prefix of Some(DiskPrefix)
  231              let repr = me.repr.as_slice();
  232              match me.prefix {
  233                  Some(DiskPrefix) => repr[0] == path[0].to_ascii().to_upper().to_byte(),
  234                  Some(VerbatimDiskPrefix) => repr[4] == path[0].to_ascii().to_upper().to_byte(),
  235                  _ => false
  236              }
  237          }
  238          fn is_sep_(prefixOption<PathPrefix>, uu8) -> bool {
  239              if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
  240              else { is_sep(u as char) }
  241          }
  242  
  243          fn replace_path(me&mut Path, path&str, prefixOption<PathPrefix>) {
  244              let newpath = Path::normalize__(path, prefix);
  245              me.repr = match newpath {
  246                  Some(p) => p,
  247                  None => StrBuf::from_str(path)
  248              };
  249              me.prefix = prefix;
  250              me.update_sepidx();
  251          }
  252          fn append_path(me: &mut Path, path: &str) {
  253              // appends a path that has no prefix
  254              // if me is verbatim, we need to pre-normalize the new path
  255              let path_ = if is_verbatim(me) { Path::normalize__(path, None) }
  256                          else { None };
  257              let pathlen = path_.as_ref().map_or(path.len(), |p| p.len());
  258              let mut s = StrBuf::with_capacity(me.repr.len() + 1 + pathlen);
  259              s.push_str(me.repr.as_slice());
  260              let plen = me.prefix_len();
  261              // if me is "C:" we don't want to add a path separator
  262              match me.prefix {
  263                  Some(DiskPrefix) if me.repr.len() == plen => (),
  264                  _ if !(me.repr.len() > plen && me.repr.as_slice()[me.repr.len()-1] == SEP_BYTE) => {
  265                      s.push_char(SEP);
  266                  }
  267                  _ => ()
  268              }
  269              match path_ {
  270                  None => s.push_str(path),
  271                  Some(p) => s.push_str(p.as_slice())
  272              };
  273              me.update_normalized(s)
  274          }
  275  
  276          if !path.is_empty() {
  277              let prefix = parse_prefix(path);
  278              match prefix {
  279                  Some(DiskPrefix) if !is_vol_abs(path, prefix) && shares_volume(self, path) => {
  280                      // cwd-relative path, self is on the same volume
  281                      append_path(self, path.slice_from(prefix_len(prefix)));
  282                  }
  283                  Some(_) => {
  284                      // absolute path, or cwd-relative and self is not same volume
  285                      replace_path(self, path, prefix);
  286                  }
  287                  None if !path.is_empty() && is_sep_(self.prefix, path[0]) => {
  288                      // volume-relative path
  289                      if self.prefix.is_some() {
  290                          // truncate self down to the prefix, then append
  291                          let n = self.prefix_len();
  292                          self.repr.truncate(n);
  293                          append_path(self, path);
  294                      } else {
  295                          // we have no prefix, so nothing to be relative to
  296                          replace_path(self, path, prefix);
  297                      }
  298                  }
  299                  None => {
  300                      // relative path
  301                      append_path(self, path);
  302                  }
  303              }
  304          }
  305      }
  306  }
  307  
  308  impl GenericPath for Path {
  309      #[inline]
  310      fn new_opt<T: BytesContainer>(pathT) -> Option<Path> {
  311          match path.container_as_str() {
  312              None => None,
  313              Some(ref s) => {
  314                  if contains_nul(s) {
  315                      None
  316                  } else {
  317                      Some(unsafe { GenericPathUnsafe::new_unchecked(*s) })
  318                  }
  319              }
  320          }
  321      }
  322  
  323      /// See `GenericPath::as_str` for info.
  324      /// Always returns a `Some` value.
  325      #[inline]
  326      fn as_str<'a>(&'a self) -> Option<&'a str> {
  327          Some(self.repr.as_slice())
  328      }
  329  
  330      #[inline]
  331      fn as_vec<'a>(&'a self) -> &'a [u8] {
  332          self.repr.as_bytes()
  333      }
  334  
  335      #[inline]
  336      fn into_vec(self) -> Vec<u8> {
  337          Vec::from_slice(self.repr.as_bytes())
  338      }
  339  
  340      #[inline]
  341      fn dirname<'a>(&'a self) -> &'a [u8] {
  342          self.dirname_str().unwrap().as_bytes()
  343      }
  344  
  345      /// See `GenericPath::dirname_str` for info.
  346      /// Always returns a `Some` value.
  347      fn dirname_str<'a>(&'a self) -> Option<&'a str> {
  348          Some(match self.sepidx_or_prefix_len() {
  349              None if ".." == self.repr.as_slice() => self.repr.as_slice(),
  350              None => ".",
  351              Some((_,idxa,end)) if self.repr.as_slice().slice(idxa, end) == ".." => {
  352                  self.repr.as_slice()
  353              }
  354              Some((idxb,_,end)) if self.repr.as_slice().slice(idxb, end) == "\\" => {
  355                  self.repr.as_slice()
  356              }
  357              Some((0,idxa,_)) => self.repr.as_slice().slice_to(idxa),
  358              Some((idxb,idxa,_)) => {
  359                  match self.prefix {
  360                      Some(DiskPrefix) | Some(VerbatimDiskPrefix) if idxb == self.prefix_len() => {
  361                          self.repr.as_slice().slice_to(idxa)
  362                      }
  363                      _ => self.repr.as_slice().slice_to(idxb)
  364                  }
  365              }
  366          })
  367      }
  368  
  369      #[inline]
  370      fn filename<'a>(&'a self) -> Option<&'a [u8]> {
  371          self.filename_str().map(|x| x.as_bytes())
  372      }
  373  
  374      /// See `GenericPath::filename_str` for info.
  375      /// Always returns a `Some` value if `filename` returns a `Some` value.
  376      fn filename_str<'a>(&'a self) -> Option<&'a str> {
  377          let repr = self.repr.as_slice();
  378          match self.sepidx_or_prefix_len() {
  379              None if "." == repr || ".." == repr => None,
  380              None => Some(repr),
  381              Some((_,idxa,end)) if repr.slice(idxa, end) == ".." => None,
  382              Some((_,idxa,end)) if idxa == end => None,
  383              Some((_,idxa,end)) => Some(repr.slice(idxa, end))
  384          }
  385      }
  386  
  387      /// See `GenericPath::filestem_str` for info.
  388      /// Always returns a `Some` value if `filestem` returns a `Some` value.
  389      #[inline]
  390      fn filestem_str<'a>(&'a self) -> Option<&'a str> {
  391          // filestem() returns a byte vector that's guaranteed valid UTF-8
  392          self.filestem().map(|t| unsafe { cast::transmute(t) })
  393      }
  394  
  395      #[inline]
  396      fn extension_str<'a>(&'a self) -> Option<&'a str> {
  397          // extension() returns a byte vector that's guaranteed valid UTF-8
  398          self.extension().map(|t| unsafe { cast::transmute(t) })
  399      }
  400  
  401      fn dir_path(&self) -> Path {
  402          unsafe { GenericPathUnsafe::new_unchecked(self.dirname_str().unwrap()) }
  403      }
  404  
  405      #[inline]
  406      fn pop(&mut self) -> bool {
  407          match self.sepidx_or_prefix_len() {
  408              None if "." == self.repr.as_slice() => false,
  409              None => {
  410                  self.repr = StrBuf::from_str(".");
  411                  self.sepidx = None;
  412                  true
  413              }
  414              Some((idxb,idxa,end)) if idxb == idxa && idxb == end => false,
  415              Some((idxb,_,end)) if self.repr.as_slice().slice(idxb, end) == "\\" => false,
  416              Some((idxb,idxa,_)) => {
  417                  let trunc = match self.prefix {
  418                      Some(DiskPrefix) | Some(VerbatimDiskPrefix) | None => {
  419                          let plen = self.prefix_len();
  420                          if idxb == plen { idxa } else { idxb }
  421                      }
  422                      _ => idxb
  423                  };
  424                  self.repr.truncate(trunc);
  425                  self.update_sepidx();
  426                  true
  427              }
  428          }
  429      }
  430  
  431      fn root_path(&self) -> Option<Path> {
  432          if self.prefix.is_some() {
  433              Some(Path::new(match self.prefix {
  434                  Some(DiskPrefix) if self.is_absolute() => {
  435                      self.repr.as_slice().slice_to(self.prefix_len()+1)
  436                  }
  437                  Some(VerbatimDiskPrefix) => {
  438                      self.repr.as_slice().slice_to(self.prefix_len()+1)
  439                  }
  440                  _ => self.repr.as_slice().slice_to(self.prefix_len())
  441              }))
  442          } else if is_vol_relative(self) {
  443              Some(Path::new(self.repr.as_slice().slice_to(1)))
  444          } else {
  445              None
  446          }
  447      }
  448  
  449      /// See `GenericPath::is_absolute` for info.
  450      ///
  451      /// A Windows Path is considered absolute only if it has a non-volume prefix,
  452      /// or if it has a volume prefix and the path starts with '\'.
  453      /// A path of `\foo` is not considered absolute because it's actually
  454      /// relative to the "current volume". A separate method `Path::is_vol_relative`
  455      /// is provided to indicate this case. Similarly a path of `C:foo` is not
  456      /// considered absolute because it's relative to the cwd on volume C:. A
  457      /// separate method `Path::is_cwd_relative` is provided to indicate this case.
  458      #[inline]
  459      fn is_absolute(&self) -> bool {
  460          match self.prefix {
  461              Some(DiskPrefix) => {
  462                  let rest = self.repr.as_slice().slice_from(self.prefix_len());
  463                  rest.len() > 0 && rest[0] == SEP_BYTE
  464              }
  465              Some(_) => true,
  466              None => false
  467          }
  468      }
  469  
  470      #[inline]
  471      fn is_relative(&self) -> bool {
  472          self.prefix.is_none() && !is_vol_relative(self)
  473      }
  474  
  475      fn is_ancestor_of(&self, other&Path) -> bool {
  476          if !self.equiv_prefix(other) {
  477              false
  478          } else if self.is_absolute() != other.is_absolute() ||
  479                    is_vol_relative(self) != is_vol_relative(other) {
  480              false
  481          } else {
  482              let mut ita = self.str_components().map(|x|x.unwrap());
  483              let mut itb = other.str_components().map(|x|x.unwrap());
  484              if "." == self.repr.as_slice() {
  485                  return itb.next() != Some("..");
  486              }
  487              loop {
  488                  match (ita.next(), itb.next()) {
  489                      (None, _) => break,
  490                      (Some(a), Some(b)) if a == b => { continue },
  491                      (Some(a), _) if a == ".." => {
  492                          // if ita contains only .. components, it's an ancestor
  493                          return ita.all(|x| x == "..");
  494                      }
  495                      _ => return false
  496                  }
  497              }
  498              true
  499          }
  500      }
  501  
  502      fn path_relative_from(&self, base&Path) -> Option<Path> {
  503          fn comp_requires_verbatim(s&str) -> bool {
  504              s == "." || s == ".." || s.contains_char(SEP2)
  505          }
  506  
  507          if !self.equiv_prefix(base) {
  508              // prefixes differ
  509              if self.is_absolute() {
  510                  Some(self.clone())
  511              } else if self.prefix == Some(DiskPrefix) && base.prefix == Some(DiskPrefix) {
  512                  // both drives, drive letters must differ or they'd be equiv
  513                  Some(self.clone())
  514              } else {
  515                  None
  516              }
  517          } else if self.is_absolute() != base.is_absolute() {
  518              if self.is_absolute() {
  519                  Some(self.clone())
  520              } else {
  521                  None
  522              }
  523          } else if is_vol_relative(self) != is_vol_relative(base) {
  524              if is_vol_relative(self) {
  525                  Some(self.clone())
  526              } else {
  527                  None
  528              }
  529          } else {
  530              let mut ita = self.str_components().map(|x|x.unwrap());
  531              let mut itb = base.str_components().map(|x|x.unwrap());
  532              let mut comps = vec![];
  533  
  534              let a_verb = is_verbatim(self);
  535              let b_verb = is_verbatim(base);
  536              loop {
  537                  match (ita.next(), itb.next()) {
  538                      (None, None) => break,
  539                      (Some(a), None) if a_verb && comp_requires_verbatim(a) => {
  540                          return Some(self.clone())
  541                      }
  542                      (Some(a), None) => {
  543                          comps.push(a);
  544                          if !a_verb {
  545                              comps.extend(ita.by_ref());
  546                              break;
  547                          }
  548                      }
  549                      (None, _) => comps.push(".."),
  550                      (Some(a), Some(b)) if comps.is_empty() && a == b => (),
  551                      (Some(a), Some(b)) if !b_verb && b == "." => {
  552                          if a_verb && comp_requires_verbatim(a) {
  553                              return Some(self.clone())
  554                          } else { comps.push(a) }
  555                      }
  556                      (Some(_), Some(b)) if !b_verb && b == ".." => return None,
  557                      (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => {
  558                          return Some(self.clone())
  559                      }
  560                      (Some(a), Some(_)) => {
  561                          comps.push("..");
  562                          for _ in itb {
  563                              comps.push("..");
  564                          }
  565                          comps.push(a);
  566                          if !a_verb {
  567                              comps.extend(ita.by_ref());
  568                              break;
  569                          }
  570                      }
  571                  }
  572              }
  573              Some(Path::new(comps.connect("\\")))
  574          }
  575      }
  576  
  577      fn ends_with_path(&self, child&Path) -> bool {
  578          if !child.is_relative() { return false; }
  579          let mut selfit = self.str_components().rev();
  580          let mut childit = child.str_components().rev();
  581          loop {
  582              match (selfit.next(), childit.next()) {
  583                  (Some(a), Some(b)) => if a != b { return false; },
  584                  (Some(_), None) => break,
  585                  (None, Some(_)) => return false,
  586                  (None, None) => break
  587              }
  588          }
  589          true
  590      }
  591  }
  592  
  593  impl Path {
  594      /// Returns a new Path from a byte vector or string
  595      ///
  596      /// # Failure
  597      ///
  598      /// Fails the task if the vector contains a NUL.
  599      /// Fails if invalid UTF-8.
  600      #[inline]
  601      pub fn new<T: BytesContainer>(pathT) -> Path {
  602          GenericPath::new(path)
  603      }
  604  
  605      /// Returns a new Path from a byte vector or string, if possible
  606      #[inline]
  607      pub fn new_opt<T: BytesContainer>(pathT) -> Option<Path> {
  608          GenericPath::new_opt(path)
  609      }
  610  
  611      /// Returns an iterator that yields each component of the path in turn as a Option<&str>.
  612      /// Every component is guaranteed to be Some.
  613      /// Does not yield the path prefix (including server/share components in UNC paths).
  614      /// Does not distinguish between volume-relative and relative paths, e.g.
  615      /// \a\b\c and a\b\c.
  616      /// Does not distinguish between absolute and cwd-relative paths, e.g.
  617      /// C:\foo and C:foo.
  618      pub fn str_components<'a>(&'a self) -> StrComponents<'a> {
  619          let repr = self.repr.as_slice();
  620          let s = match self.prefix {
  621              Some(_) => {
  622                  let plen = self.prefix_len();
  623                  if repr.len() > plen && repr[plen] == SEP_BYTE {
  624                      repr.slice_from(plen+1)
  625                  } else { repr.slice_from(plen) }
  626              }
  627              None if repr[0] == SEP_BYTE => repr.slice_from(1),
  628              None => repr
  629          };
  630          let ret = s.split_terminator(SEP).map(Some);
  631          ret
  632      }
  633  
  634      /// Returns an iterator that yields each component of the path in reverse as an Option<&str>
  635      /// See str_components() for details.
  636      #[deprecated = "replaced by .str_components().rev()"]
  637      pub fn rev_str_components<'a>(&'a self) -> Rev<StrComponents<'a>> {
  638          self.str_components().rev()
  639      }
  640  
  641      /// Returns an iterator that yields each component of the path in turn as a &[u8].
  642      /// See str_components() for details.
  643      pub fn components<'a>(&'a self) -> Components<'a> {
  644          fn convert<'a>(xOption<&'a str>) -> &'a [u8] {
  645              #![inline]
  646              x.unwrap().as_bytes()
  647          }
  648          self.str_components().map(convert)
  649      }
  650  
  651      /// Returns an iterator that yields each component of the path in reverse as a &[u8].
  652      /// See str_components() for details.
  653      #[deprecated = "replaced by .components().rev()"]
  654      pub fn rev_components<'a>(&'a self) -> Rev<Components<'a>> {
  655          self.components().rev()
  656      }
  657  
  658      fn equiv_prefix(&self, other&Path) -> bool {
  659          let s_repr = self.repr.as_slice();
  660          let o_repr = other.repr.as_slice();
  661          match (self.prefix, other.prefix) {
  662              (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
  663                  self.is_absolute() &&
  664                      s_repr[0].to_ascii().eq_ignore_case(o_repr[4].to_ascii())
  665              }
  666              (Some(VerbatimDiskPrefix), Some(DiskPrefix)) => {
  667                  other.is_absolute() &&
  668                      s_repr[4].to_ascii().eq_ignore_case(o_repr[0].to_ascii())
  669              }
  670              (Some(VerbatimDiskPrefix), Some(VerbatimDiskPrefix)) => {
  671                  s_repr[4].to_ascii().eq_ignore_case(o_repr[4].to_ascii())
  672              }
  673              (Some(UNCPrefix(_,_)), Some(VerbatimUNCPrefix(_,_))) => {
  674                  s_repr.slice(2, self.prefix_len()) == o_repr.slice(8, other.prefix_len())
  675              }
  676              (Some(VerbatimUNCPrefix(_,_)), Some(UNCPrefix(_,_))) => {
  677                  s_repr.slice(8, self.prefix_len()) == o_repr.slice(2, other.prefix_len())
  678              }
  679              (None, None) => true,
  680              (a, b) if a == b => {
  681                  s_repr.slice_to(self.prefix_len()) == o_repr.slice_to(other.prefix_len())
  682              }
  683              _ => false
  684          }
  685      }
  686  
  687      fn normalize_<S: StrAllocating>(sS) -> (Option<PathPrefix>, StrBuf) {
  688          // make borrowck happy
  689          let (prefix, val) = {
  690              let prefix = parse_prefix(s.as_slice());
  691              let path = Path::normalize__(s.as_slice(), prefix);
  692              (prefix, path)
  693          };
  694          (prefix, match val {
  695              None => s.into_strbuf(),
  696              Some(val) => val
  697          })
  698      }
  699  
  700      fn normalize__(s&str, prefixOption<PathPrefix>) -> Option<StrBuf> {
  701          if prefix_is_verbatim(prefix) {
  702              // don't do any normalization
  703              match prefix {
  704                  Some(VerbatimUNCPrefix(x, 0)) if s.len() == 8 + x => {
  705                      // the server component has no trailing '\'
  706                      let mut s = StrBuf::from_str(s);
  707                      s.push_char(SEP);
  708                      Some(s)
  709                  }
  710                  _ => None
  711              }
  712          } else {
  713              let (is_abs, comps) = normalize_helper(s, prefix);
  714              let mut comps = comps;
  715              match (comps.is_some(),prefix) {
  716                  (false, Some(DiskPrefix)) => {
  717                      if s[0] >= 'a' as u8 && s[0] <= 'z' as u8 {
  718                          comps = Some(vec![]);
  719                      }
  720                  }
  721                  (false, Some(VerbatimDiskPrefix)) => {
  722                      if s[4] >= 'a' as u8 && s[0] <= 'z' as u8 {
  723                          comps = Some(vec![]);
  724                      }
  725                  }
  726                  _ => ()
  727              }
  728              match comps {
  729                  None => None,
  730                  Some(comps) => {
  731                      if prefix.is_some() && comps.is_empty() {
  732                          match prefix.unwrap() {
  733                              DiskPrefix => {
  734                                  let len = prefix_len(prefix) + is_abs as uint;
  735                                  let mut s = StrBuf::from_str(s.slice_to(len));
  736                                  unsafe {
  737                                      let v = s.as_mut_vec();
  738                                      *v.get_mut(0) = v.get(0).to_ascii().to_upper().to_byte();
  739                                  }
  740                                  if is_abs {
  741                                      // normalize C:/ to C:\
  742                                      unsafe {
  743                                          *s.as_mut_vec().get_mut(2) = SEP_BYTE;
  744                                      }
  745                                  }
  746                                  Some(s)
  747                              }
  748                              VerbatimDiskPrefix => {
  749                                  let len = prefix_len(prefix) + is_abs as uint;
  750                                  let mut s = StrBuf::from_str(s.slice_to(len));
  751                                  unsafe {
  752                                      let v = s.as_mut_vec();
  753                                      *v.get_mut(4) = v.get(4).to_ascii().to_upper().to_byte();
  754                                  }
  755                                  Some(s)
  756                              }
  757                              _ => {
  758                                  let plen = prefix_len(prefix);
  759                                  if s.len() > plen {
  760                                      Some(StrBuf::from_str(s.slice_to(plen)))
  761                                  } else { None }
  762                              }
  763                          }
  764                      } else if is_abs && comps.is_empty() {
  765                          Some(StrBuf::from_char(1, SEP))
  766                      } else {
  767                          let prefix_ = s.slice_to(prefix_len(prefix));
  768                          let n = prefix_.len() +
  769                                  if is_abs { comps.len() } else { comps.len() - 1} +
  770                                  comps.iter().map(|v| v.len()).sum();
  771                          let mut s = StrBuf::with_capacity(n);
  772                          match prefix {
  773                              Some(DiskPrefix) => {
  774                                  s.push_char(prefix_[0].to_ascii().to_upper().to_char());
  775                                  s.push_char(':');
  776                              }
  777                              Some(VerbatimDiskPrefix) => {
  778                                  s.push_str(prefix_.slice_to(4));
  779                                  s.push_char(prefix_[4].to_ascii().to_upper().to_char());
  780                                  s.push_str(prefix_.slice_from(5));
  781                              }
  782                              Some(UNCPrefix(a,b)) => {
  783                                  s.push_str("\\\\");
  784                                  s.push_str(prefix_.slice(2, a+2));
  785                                  s.push_char(SEP);
  786                                  s.push_str(prefix_.slice(3+a, 3+a+b));
  787                              }
  788                              Some(_) => s.push_str(prefix_),
  789                              None => ()
  790                          }
  791                          let mut it = comps.move_iter();
  792                          if !is_abs {
  793                              match it.next() {
  794                                  None => (),
  795                                  Some(comp) => s.push_str(comp)
  796                              }
  797                          }
  798                          for comp in it {
  799                              s.push_char(SEP);
  800                              s.push_str(comp);
  801                          }
  802                          Some(s)
  803                      }
  804                  }
  805              }
  806          }
  807      }
  808  
  809      fn update_sepidx(&mut self) {
  810          let s = if self.has_nonsemantic_trailing_slash() {
  811                      self.repr.as_slice().slice_to(self.repr.len()-1)
  812                  } else { self.repr.as_slice() };
  813          let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
  814                            else { is_sep_verbatim });
  815          let prefixlen = self.prefix_len();
  816          self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
  817      }
  818  
  819      fn prefix_len(&self) -> uint {
  820          prefix_len(self.prefix)
  821      }
  822  
  823      // Returns a tuple (before, after, end) where before is the index of the separator
  824      // and after is the index just after the separator.
  825      // end is the length of the string, normally, or the index of the final character if it is
  826      // a non-semantic trailing separator in a verbatim string.
  827      // If the prefix is considered the separator, before and after are the same.
  828      fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> {
  829          match self.sepidx {
  830              None => match self.prefix_len() { 0 => None, x => Some((x,x,self.repr.len())) },
  831              Some(x) => {
  832                  if self.has_nonsemantic_trailing_slash() {
  833                      Some((x,x+1,self.repr.len()-1))
  834                  } else { Some((x,x+1,self.repr.len())) }
  835              }
  836          }
  837      }
  838  
  839      fn has_nonsemantic_trailing_slash(&self) -> bool {
  840          is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
  841              self.repr.as_slice()[self.repr.len()-1] == SEP_BYTE
  842      }
  843  
  844      fn update_normalized<S: Str>(&mut self, sS) {
  845          let (prefix, path) = Path::normalize_(s.as_slice());
  846          self.repr = path;
  847          self.prefix = prefix;
  848          self.update_sepidx();
  849      }
  850  }
  851  
  852  /// Returns whether the path is considered "volume-relative", which means a path
  853  /// that looks like "\foo". Paths of this form are relative to the current volume,
  854  /// but absolute within that volume.
  855  #[inline]
  856  pub fn is_vol_relative(path: &Path) -> bool {
  857      path.prefix.is_none() && is_sep_byte(&path.repr.as_slice()[0])
  858  }
  859  
  860  /// Returns whether the path is considered "cwd-relative", which means a path
  861  /// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths
  862  /// of this form are relative to the cwd on the given volume.
  863  #[inline]
  864  pub fn is_cwd_relative(path: &Path) -> bool {
  865      path.prefix == Some(DiskPrefix) && !path.is_absolute()
  866  }
  867  
  868  /// Returns the PathPrefix for this Path
  869  #[inline]
  870  pub fn prefix(path: &Path) -> Option<PathPrefix> {
  871      path.prefix
  872  }
  873  
  874  /// Returns whether the Path's prefix is a verbatim prefix, i.e. `\\?\`
  875  #[inline]
  876  pub fn is_verbatim(path: &Path) -> bool {
  877      prefix_is_verbatim(path.prefix)
  878  }
  879  
  880  /// Returns the non-verbatim equivalent of the input path, if possible.
  881  /// If the input path is a device namespace path, None is returned.
  882  /// If the input path is not verbatim, it is returned as-is.
  883  /// If the input path is verbatim, but the same path can be expressed as
  884  /// non-verbatim, the non-verbatim version is returned.
  885  /// Otherwise, None is returned.
  886  pub fn make_non_verbatim(path: &Path) -> Option<Path> {
  887      let repr = path.repr.as_slice();
  888      let new_path = match path.prefix {
  889          Some(VerbatimPrefix(_)) | Some(DeviceNSPrefix(_)) => return None,
  890          Some(UNCPrefix(_,_)) | Some(DiskPrefix) | None => return Some(path.clone()),
  891          Some(VerbatimDiskPrefix) => {
  892              // \\?\D:\
  893              Path::new(repr.slice_from(4))
  894          }
  895          Some(VerbatimUNCPrefix(_,_)) => {
  896              // \\?\UNC\server\share
  897              Path::new(format!(r"\\{}", repr.slice_from(7)))
  898          }
  899      };
  900      if new_path.prefix.is_none() {
  901          // \\?\UNC\server is a VerbatimUNCPrefix
  902          // but \\server is nothing
  903          return None;
  904      }
  905      // now ensure normalization didn't change anything
  906      if repr.slice_from(path.prefix_len()) ==
  907          new_path.repr.as_slice().slice_from(new_path.prefix_len()) {
  908          Some(new_path)
  909      } else {
  910          None
  911      }
  912  }
  913  
  914  /// The standard path separator character
  915  pub static SEP: char = '\\';
  916  /// The standard path separator byte
  917  pub static SEP_BYTE: u8 = SEP as u8;
  918  
  919  /// The alternative path separator character
  920  pub static SEP2: char = '/';
  921  /// The alternative path separator character
  922  pub static SEP2_BYTE: u8 = SEP2 as u8;
  923  
  924  /// Returns whether the given char is a path separator.
  925  /// Allows both the primary separator '\' and the alternative separator '/'.
  926  #[inline]
  927  pub fn is_sep(c: char) -> bool {
  928      c == SEP || c == SEP2
  929  }
  930  
  931  /// Returns whether the given char is a path separator.
  932  /// Only allows the primary separator '\'; use is_sep to allow '/'.
  933  #[inline]
  934  pub fn is_sep_verbatim(c: char) -> bool {
  935      c == SEP
  936  }
  937  
  938  /// Returns whether the given byte is a path separator.
  939  /// Allows both the primary separator '\' and the alternative separator '/'.
  940  #[inline]
  941  pub fn is_sep_byte(u: &u8) -> bool {
  942      *u == SEP_BYTE || *u == SEP2_BYTE
  943  }
  944  
  945  /// Returns whether the given byte is a path separator.
  946  /// Only allows the primary separator '\'; use is_sep_byte to allow '/'.
  947  #[inline]
  948  pub fn is_sep_byte_verbatim(u: &u8) -> bool {
  949      *u == SEP_BYTE
  950  }
  951  
  952  /// Prefix types for Path
  953  #[deriving(Eq, Clone)]
  954  pub enum PathPrefix {
  955      /// Prefix `\\?\`, uint is the length of the following component
  956      VerbatimPrefix(uint),
  957      /// Prefix `\\?\UNC\`, uints are the lengths of the UNC components
  958      VerbatimUNCPrefix(uint, uint),
  959      /// Prefix `\\?\C:\` (for any alphabetic character)
  960      VerbatimDiskPrefix,
  961      /// Prefix `\\.\`, uint is the length of the following component
  962      DeviceNSPrefix(uint),
  963      /// UNC prefix `\\server\share`, uints are the lengths of the server/share
  964      UNCPrefix(uint, uint),
  965      /// Prefix `C:` for any alphabetic character
  966      DiskPrefix
  967  }
  968  
  969  fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
  970      if path.starts_with("\\\\") {
  971          // \\
  972          path = path.slice_from(2);
  973          if path.starts_with("?\\") {
  974              // \\?\
  975              path = path.slice_from(2);
  976              if path.starts_with("UNC\\") {
  977                  // \\?\UNC\server\share
  978                  path = path.slice_from(4);
  979                  let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
  980                      Some(x) => x,
  981                      None => (path.len(), 0)
  982                  };
  983                  return Some(VerbatimUNCPrefix(idx_a, idx_b));
  984              } else {
  985                  // \\?\path
  986                  let idx = path.find('\\');
  987                  if idx == Some(2) && path[1] == ':' as u8 {
  988                      let c = path[0];
  989                      if c.is_ascii() && ::char::is_alphabetic(c as char) {
  990                          // \\?\C:\ path
  991                          return Some(VerbatimDiskPrefix);
  992                      }
  993                  }
  994                  let idx = idx.unwrap_or(path.len());
  995                  return Some(VerbatimPrefix(idx));
  996              }
  997          } else if path.starts_with(".\\") {
  998              // \\.\path
  999              path = path.slice_from(2);
 1000              let idx = path.find('\\').unwrap_or(path.len());
 1001              return Some(DeviceNSPrefix(idx));
 1002          }
 1003          match parse_two_comps(path, is_sep) {
 1004              Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {
 1005                  // \\server\share
 1006                  return Some(UNCPrefix(idx_a, idx_b));
 1007              }
 1008              _ => ()
 1009          }
 1010      } else if path.len() > 1 && path[1] == ':' as u8 {
 1011          // C:
 1012          let c = path[0];
 1013          if c.is_ascii() && ::char::is_alphabetic(c as char) {
 1014              return Some(DiskPrefix);
 1015          }
 1016      }
 1017      return None;
 1018  
 1019      fn parse_two_comps<'a>(mut path&'a str, f|char| -> bool)
 1020                         -> Option<(uint, uint)> {
 1021          let idx_a = match path.find(|x| f(x)) {
 1022              None => return None,
 1023              Some(x) => x
 1024          };
 1025          path = path.slice_from(idx_a+1);
 1026          let idx_b = path.find(f).unwrap_or(path.len());
 1027          Some((idx_a, idx_b))
 1028      }
 1029  }
 1030  
 1031  // None result means the string didn't need normalizing
 1032  fn normalize_helper<'a>(s: &'a str, prefixOption<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
 1033      let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
 1034      let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
 1035      let s_ = s.slice_from(prefix_len(prefix));
 1036      let s_ = if is_abs { s_.slice_from(1) } else { s_ };
 1037  
 1038      if is_abs && s_.is_empty() {
 1039          return (is_abs, match prefix {
 1040              Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
 1041                                          else { Some(vec![]) }),
 1042              Some(_) => Some(vec![]), // need to trim the trailing separator
 1043          });
 1044      }
 1045      let mut compsVec<&'a str> = vec![];
 1046      let mut n_up = 0u;
 1047      let mut changed = false;
 1048      for comp in s_.split(f) {
 1049          if comp.is_empty() { changed = true }
 1050          else if comp == "." { changed = true }
 1051          else if comp == ".." {
 1052              let has_abs_prefix = match prefix {
 1053                  Some(DiskPrefix) => false,
 1054                  Some(_) => true,
 1055                  None => false
 1056              };
 1057              if (is_abs || has_abs_prefix) && comps.is_empty() { changed = true }
 1058              else if comps.len() == n_up { comps.push(".."); n_up += 1 }
 1059              else { comps.pop().unwrap(); changed = true }
 1060          } else { comps.push(comp) }
 1061      }
 1062      if !changed && !prefix_is_verbatim(prefix) {
 1063          changed = s.find(is_sep).is_some();
 1064      }
 1065      if changed {
 1066          if comps.is_empty() && !is_abs && prefix.is_none() {
 1067              if s == "." {
 1068                  return (is_abs, None);
 1069              }
 1070              comps.push(".");
 1071          }
 1072          (is_abs, Some(comps))
 1073      } else {
 1074          (is_abs, None)
 1075      }
 1076  }
 1077  
 1078  fn prefix_is_verbatim(pOption<PathPrefix>) -> bool {
 1079      match p {
 1080          Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true,
 1081          Some(DeviceNSPrefix(_)) => true, // not really sure, but I think so
 1082          _ => false
 1083      }
 1084  }
 1085  
 1086  fn prefix_len(pOption<PathPrefix>) -> uint {
 1087      match p {
 1088          None => 0,
 1089          Some(VerbatimPrefix(x)) => 4 + x,
 1090          Some(VerbatimUNCPrefix(x,y)) => 8 + x + 1 + y,
 1091          Some(VerbatimDiskPrefix) => 6,
 1092          Some(UNCPrefix(x,y)) => 2 + x + 1 + y,
 1093          Some(DeviceNSPrefix(x)) => 4 + x,
 1094          Some(DiskPrefix) => 2
 1095      }
 1096  }
 1097  
 1098  #[cfg(test)]
 1099  mod tests {
 1100      use prelude::*;
 1101      use super::*;
 1102      use super::parse_prefix;
 1103  
 1104      macro_rules! t(
 1105          (s: $path:expr, $exp:expr) => (
 1106              {
 1107                  let path = $path;
 1108                  assert!(path.as_str() == Some($exp));
 1109              }
 1110          );
 1111          (v: $path:expr, $exp:expr) => (
 1112              {
 1113                  let path = $path;
 1114                  assert!(path.as_vec() == $exp);
 1115              }
 1116          )
 1117      )
 1118  
 1119      macro_rules! b(
 1120          ($($arg:expr),+) => (
 1121              {
 1122                  static the_bytes: &'static [u8] = bytes!($($arg),+);
 1123                  the_bytes
 1124              }
 1125          )
 1126      )
 1127  
 1128      #[test]
 1129      fn test_parse_prefix() {
 1130          macro_rules! t(
 1131              ($path:expr, $exp:expr) => (
 1132                  {
 1133                      let path = $path;
 1134                      let exp = $exp;
 1135                      let res = parse_prefix(path);
 1136                      assert!(res == exp,
 1137                              "parse_prefix(\"{}\"): expected {:?}, found {:?}", path, exp, res);
 1138                  }
 1139              )
 1140          )
 1141  
 1142          t!("\\\\SERVER\\share\\foo", Some(UNCPrefix(6,5)));
 1143          t!("\\\\", None);
 1144          t!("\\\\SERVER", None);
 1145          t!("\\\\SERVER\\", None);
 1146          t!("\\\\SERVER\\\\", None);
 1147          t!("\\\\SERVER\\\\foo", None);
 1148          t!("\\\\SERVER\\share", Some(UNCPrefix(6,5)));
 1149          t!("\\\\SERVER/share/foo", Some(UNCPrefix(6,5)));
 1150          t!("\\\\SERVER\\share/foo", Some(UNCPrefix(6,5)));
 1151          t!("//SERVER/share/foo", None);
 1152          t!("\\\\\\a\\b\\c", None);
 1153          t!("\\\\?\\a\\b\\c", Some(VerbatimPrefix(1)));
 1154          t!("\\\\?\\a/b/c", Some(VerbatimPrefix(5)));
 1155          t!("//?/a/b/c", None);
 1156          t!("\\\\.\\a\\b", Some(DeviceNSPrefix(1)));
 1157          t!("\\\\.\\a/b", Some(DeviceNSPrefix(3)));
 1158          t!("//./a/b", None);
 1159          t!("\\\\?\\UNC\\server\\share\\foo", Some(VerbatimUNCPrefix(6,5)));
 1160          t!("\\\\?\\UNC\\\\share\\foo", Some(VerbatimUNCPrefix(0,5)));
 1161          t!("\\\\?\\UNC\\", Some(VerbatimUNCPrefix(0,0)));
 1162          t!("\\\\?\\UNC\\server/share/foo", Some(VerbatimUNCPrefix(16,0)));
 1163          t!("\\\\?\\UNC\\server", Some(VerbatimUNCPrefix(6,0)));
 1164          t!("\\\\?\\UNC\\server\\", Some(VerbatimUNCPrefix(6,0)));
 1165          t!("\\\\?\\UNC/server/share", Some(VerbatimPrefix(16)));
 1166          t!("\\\\?\\UNC", Some(VerbatimPrefix(3)));
 1167          t!("\\\\?\\C:\\a\\b.txt", Some(VerbatimDiskPrefix));
 1168          t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
 1169          t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
 1170          t!("\\\\?\\C:a.txt", Some(VerbatimPrefix(7)));
 1171          t!("\\\\?\\C:a\\b.txt", Some(VerbatimPrefix(3)));
 1172          t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
 1173          t!("C:\\foo", Some(DiskPrefix));
 1174          t!("z:/foo", Some(DiskPrefix));
 1175          t!("d:", Some(DiskPrefix));
 1176          t!("ab:", None);
 1177          t!("ü:\\foo", None);
 1178          t!("3:\\foo", None);
 1179          t!(" :\\foo", None);
 1180          t!("::\\foo", None);
 1181          t!("\\\\?\\C:", Some(VerbatimPrefix(2)));
 1182          t!("\\\\?\\z:\\", Some(VerbatimDiskPrefix));
 1183          t!("\\\\?\\ab:\\", Some(VerbatimPrefix(3)));
 1184          t!("\\\\?\\C:\\a", Some(VerbatimDiskPrefix));
 1185          t!("\\\\?\\C:/a", Some(VerbatimPrefix(4)));
 1186          t!("\\\\?\\C:\\a/b", Some(VerbatimDiskPrefix));
 1187      }
 1188  
 1189      #[test]
 1190      fn test_paths() {
 1191          let empty: &[u8] = [];
 1192          t!(v: Path::new(empty), b!("."));
 1193          t!(v: Path::new(b!("\\")), b!("\\"));
 1194          t!(v: Path::new(b!("a\\b\\c")), b!("a\\b\\c"));
 1195  
 1196          t!(s: Path::new(""), ".");
 1197          t!(s: Path::new("\\"), "\\");
 1198          t!(s: Path::new("hi"), "hi");
 1199          t!(s: Path::new("hi\\"), "hi");
 1200          t!(s: Path::new("\\lib"), "\\lib");
 1201          t!(s: Path::new("\\lib\\"), "\\lib");
 1202          t!(s: Path::new("hi\\there"), "hi\\there");
 1203          t!(s: Path::new("hi\\there.txt"), "hi\\there.txt");
 1204          t!(s: Path::new("/"), "\\");
 1205          t!(s: Path::new("hi/"), "hi");
 1206          t!(s: Path::new("/lib"), "\\lib");
 1207          t!(s: Path::new("/lib/"), "\\lib");
 1208          t!(s: Path::new("hi/there"), "hi\\there");
 1209  
 1210          t!(s: Path::new("hi\\there\\"), "hi\\there");
 1211          t!(s: Path::new("hi\\..\\there"), "there");
 1212          t!(s: Path::new("hi/../there"), "there");
 1213          t!(s: Path::new("..\\hi\\there"), "..\\hi\\there");
 1214          t!(s: Path::new("\\..\\hi\\there"), "\\hi\\there");
 1215          t!(s: Path::new("/../hi/there"), "\\hi\\there");
 1216          t!(s: Path::new("foo\\.."), ".");
 1217          t!(s: Path::new("\\foo\\.."), "\\");
 1218          t!(s: Path::new("\\foo\\..\\.."), "\\");
 1219          t!(s: Path::new("\\foo\\..\\..\\bar"), "\\bar");
 1220          t!(s: Path::new("\\.\\hi\\.\\there\\."), "\\hi\\there");
 1221          t!(s: Path::new("\\.\\hi\\.\\there\\.\\.."), "\\hi");
 1222          t!(s: Path::new("foo\\..\\.."), "..");
 1223          t!(s: Path::new("foo\\..\\..\\.."), "..\\..");
 1224          t!(s: Path::new("foo\\..\\..\\bar"), "..\\bar");
 1225  
 1226          assert_eq!(Path::new(b!("foo\\bar")).into_vec().as_slice(), b!("foo\\bar"));
 1227          assert_eq!(Path::new(b!("\\foo\\..\\..\\bar")).into_vec().as_slice(), b!("\\bar"));
 1228  
 1229          t!(s: Path::new("\\\\a"), "\\a");
 1230          t!(s: Path::new("\\\\a\\"), "\\a");
 1231          t!(s: Path::new("\\\\a\\b"), "\\\\a\\b");
 1232          t!(s: Path::new("\\\\a\\b\\"), "\\\\a\\b");
 1233          t!(s: Path::new("\\\\a\\b/"), "\\\\a\\b");
 1234          t!(s: Path::new("\\\\\\b"), "\\b");
 1235          t!(s: Path::new("\\\\a\\\\b"), "\\a\\b");
 1236          t!(s: Path::new("\\\\a\\b\\c"), "\\\\a\\b\\c");
 1237          t!(s: Path::new("\\\\server\\share/path"), "\\\\server\\share\\path");
 1238          t!(s: Path::new("\\\\server/share/path"), "\\\\server\\share\\path");
 1239          t!(s: Path::new("C:a\\b.txt"), "C:a\\b.txt");
 1240          t!(s: Path::new("C:a/b.txt"), "C:a\\b.txt");
 1241          t!(s: Path::new("z:\\a\\b.txt"), "Z:\\a\\b.txt");
 1242          t!(s: Path::new("z:/a/b.txt"), "Z:\\a\\b.txt");
 1243          t!(s: Path::new("ab:/a/b.txt"), "ab:\\a\\b.txt");
 1244          t!(s: Path::new("C:\\"), "C:\\");
 1245          t!(s: Path::new("C:"), "C:");
 1246          t!(s: Path::new("q:"), "Q:");
 1247          t!(s: Path::new("C:/"), "C:\\");
 1248          t!(s: Path::new("C:\\foo\\.."), "C:\\");
 1249          t!(s: Path::new("C:foo\\.."), "C:");
 1250          t!(s: Path::new("C:\\a\\"), "C:\\a");
 1251          t!(s: Path::new("C:\\a/"), "C:\\a");
 1252          t!(s: Path::new("C:\\a\\b\\"), "C:\\a\\b");
 1253          t!(s: Path::new("C:\\a\\b/"), "C:\\a\\b");
 1254          t!(s: Path::new("C:a\\"), "C:a");
 1255          t!(s: Path::new("C:a/"), "C:a");
 1256          t!(s: Path::new("C:a\\b\\"), "C:a\\b");
 1257          t!(s: Path::new("C:a\\b/"), "C:a\\b");
 1258          t!(s: Path::new("\\\\?\\z:\\a\\b.txt"), "\\\\?\\z:\\a\\b.txt");
 1259          t!(s: Path::new("\\\\?\\C:/a/b.txt"), "\\\\?\\C:/a/b.txt");
 1260          t!(s: Path::new("\\\\?\\C:\\a/b.txt"), "\\\\?\\C:\\a/b.txt");
 1261          t!(s: Path::new("\\\\?\\test\\a\\b.txt"), "\\\\?\\test\\a\\b.txt");
 1262          t!(s: Path::new("\\\\?\\foo\\bar\\"), "\\\\?\\foo\\bar\\");
 1263          t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
 1264          t!(s: Path::new("\\\\.\\"), "\\\\.\\");
 1265          t!(s: Path::new("\\\\?\\UNC\\server\\share\\foo"), "\\\\?\\UNC\\server\\share\\foo");
 1266          t!(s: Path::new("\\\\?\\UNC\\server/share"), "\\\\?\\UNC\\server/share\\");
 1267          t!(s: Path::new("\\\\?\\UNC\\server"), "\\\\?\\UNC\\server\\");
 1268          t!(s: Path::new("\\\\?\\UNC\\"), "\\\\?\\UNC\\\\");
 1269          t!(s: Path::new("\\\\?\\UNC"), "\\\\?\\UNC");
 1270  
 1271          // I'm not sure whether \\.\foo/bar should normalize to \\.\foo\bar
 1272          // as information is sparse and this isn't really googleable.
 1273          // I'm going to err on the side of not normalizing it, as this skips the filesystem
 1274          t!(s: Path::new("\\\\.\\foo/bar"), "\\\\.\\foo/bar");
 1275          t!(s: Path::new("\\\\.\\foo\\bar"), "\\\\.\\foo\\bar");
 1276      }
 1277  
 1278      #[test]
 1279      fn test_opt_paths() {
 1280          assert!(Path::new_opt(b!("foo\\bar", 0)) == None);
 1281          assert!(Path::new_opt(b!("foo\\bar", 0x80)) == None);
 1282          t!(v: Path::new_opt(b!("foo\\bar")).unwrap(), b!("foo\\bar"));
 1283          assert!(Path::new_opt("foo\\bar\0") == None);
 1284          t!(s: Path::new_opt("foo\\bar").unwrap(), "foo\\bar");
 1285      }
 1286  
 1287      #[test]
 1288      fn test_null_byte() {
 1289          use task;
 1290          let result = task::try(proc() {
 1291              Path::new(b!("foo/bar", 0))
 1292          });
 1293          assert!(result.is_err());
 1294  
 1295          let result = task::try(proc() {
 1296              Path::new("test").set_filename(b!("f", 0, "o"))
 1297          });
 1298          assert!(result.is_err());
 1299  
 1300          let result = task::try(proc() {
 1301              Path::new("test").push(b!("f", 0, "o"));
 1302          });
 1303          assert!(result.is_err());
 1304      }
 1305  
 1306      #[test]
 1307      #[should_fail]
 1308      fn test_not_utf8_fail() {
 1309          Path::new(b!("hello", 0x80, ".txt"));
 1310      }
 1311  
 1312      #[test]
 1313      fn test_display_str() {
 1314          let path = Path::new("foo");
 1315          assert_eq!(path.display().to_str(), "foo".to_owned());
 1316          let path = Path::new(b!("\\"));
 1317          assert_eq!(path.filename_display().to_str(), "".to_owned());
 1318  
 1319          let path = Path::new("foo");
 1320          let mo = path.display().as_maybe_owned();
 1321          assert_eq!(mo.as_slice(), "foo");
 1322          let path = Path::new(b!("\\"));
 1323          let mo = path.filename_display().as_maybe_owned();
 1324          assert_eq!(mo.as_slice(), "");
 1325      }
 1326  
 1327      #[test]
 1328      fn test_display() {
 1329          macro_rules! t(
 1330              ($path:expr, $exp:expr, $expf:expr) => (
 1331                  {
 1332                      let path = Path::new($path);
 1333                      let f = format!("{}", path.display());
 1334                      assert_eq!(f.as_slice(), $exp);
 1335                      let f = format!("{}", path.filename_display());
 1336                      assert_eq!(f.as_slice(), $expf);
 1337                  }
 1338              )
 1339          )
 1340  
 1341          t!("foo", "foo", "foo");
 1342          t!("foo\\bar", "foo\\bar", "bar");
 1343          t!("\\", "\\", "");
 1344      }
 1345  
 1346      #[test]
 1347      fn test_components() {
 1348          macro_rules! t(
 1349              (s: $path:expr, $op:ident, $exp:expr) => (
 1350                  {
 1351                      let path = $path;
 1352                      let path = Path::new(path);
 1353                      assert!(path.$op() == Some($exp));
 1354                  }
 1355              );
 1356              (s: $path:expr, $op:ident, $exp:expr, opt) => (
 1357                  {
 1358                      let path = $path;
 1359                      let path = Path::new(path);
 1360                      let left = path.$op();
 1361                      assert!(left == $exp);
 1362                  }
 1363              );
 1364              (v: $path:expr, $op:ident, $exp:expr) => (
 1365                  {
 1366                      let path = $path;
 1367                      let path = Path::new(path);
 1368                      assert!(path.$op() == $exp);
 1369                  }
 1370              )
 1371          )
 1372  
 1373          t!(v: b!("a\\b\\c"), filename, Some(b!("c")));
 1374          t!(s: "a\\b\\c", filename_str, "c");
 1375          t!(s: "\\a\\b\\c", filename_str, "c");
 1376          t!(s: "a", filename_str, "a");
 1377          t!(s: "\\a", filename_str, "a");
 1378          t!(s: ".", filename_str, None, opt);
 1379          t!(s: "\\", filename_str, None, opt);
 1380          t!(s: "..", filename_str, None, opt);
 1381          t!(s: "..\\..", filename_str, None, opt);
 1382          t!(s: "c:\\foo.txt", filename_str, "foo.txt");
 1383          t!(s: "C:\\", filename_str, None, opt);
 1384          t!(s: "C:", filename_str, None, opt);
 1385          t!(s: "\\\\server\\share\\foo.txt", filename_str, "foo.txt");
 1386          t!(s: "\\\\server\\share", filename_str, None, opt);
 1387          t!(s: "\\\\server", filename_str, "server");
 1388          t!(s: "\\\\?\\bar\\foo.txt", filename_str, "foo.txt");
 1389          t!(s: "\\\\?\\bar", filename_str, None, opt);
 1390          t!(s: "\\\\?\\", filename_str, None, opt);
 1391          t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", filename_str, "foo.txt");
 1392          t!(s: "\\\\?\\UNC\\server", filename_str, None, opt);
 1393          t!(s: "\\\\?\\UNC\\", filename_str, None, opt);
 1394          t!(s: "\\\\?\\C:\\foo.txt", filename_str, "foo.txt");
 1395          t!(s: "\\\\?\\C:\\", filename_str, None, opt);
 1396          t!(s: "\\\\?\\C:", filename_str, None, opt);
 1397          t!(s: "\\\\?\\foo/bar", filename_str, None, opt);
 1398          t!(s: "\\\\?\\C:/foo", filename_str, None, opt);
 1399          t!(s: "\\\\.\\foo\\bar", filename_str, "bar");
 1400          t!(s: "\\\\.\\foo", filename_str, None, opt);
 1401          t!(s: "\\\\.\\foo/bar", filename_str, None, opt);
 1402          t!(s: "\\\\.\\foo\\bar/baz", filename_str, "bar/baz");
 1403          t!(s: "\\\\.\\", filename_str, None, opt);
 1404          t!(s: "\\\\?\\a\\b\\", filename_str, "b");
 1405  
 1406          t!(v: b!("a\\b\\c"), dirname, b!("a\\b"));
 1407          t!(s: "a\\b\\c", dirname_str, "a\\b");
 1408          t!(s: "\\a\\b\\c", dirname_str, "\\a\\b");
 1409          t!(s: "a", dirname_str, ".");
 1410          t!(s: "\\a", dirname_str, "\\");
 1411          t!(s: ".", dirname_str, ".");
 1412          t!(s: "\\", dirname_str, "\\");
 1413          t!(s: "..", dirname_str, "..");
 1414          t!(s: "..\\..", dirname_str, "..\\..");
 1415          t!(s: "c:\\foo.txt", dirname_str, "C:\\");
 1416          t!(s: "C:\\", dirname_str, "C:\\");
 1417          t!(s: "C:", dirname_str, "C:");
 1418          t!(s: "C:foo.txt", dirname_str, "C:");
 1419          t!(s: "\\\\server\\share\\foo.txt", dirname_str, "\\\\server\\share");
 1420          t!(s: "\\\\server\\share", dirname_str, "\\\\server\\share");
 1421          t!(s: "\\\\server", dirname_str, "\\");
 1422          t!(s: "\\\\?\\bar\\foo.txt", dirname_str, "\\\\?\\bar");
 1423          t!(s: "\\\\?\\bar", dirname_str, "\\\\?\\bar");
 1424          t!(s: "\\\\?\\", dirname_str, "\\\\?\\");
 1425          t!(s: "\\\\?\\UNC\\server\\share\\foo.txt", dirname_str, "\\\\?\\UNC\\server\\share");
 1426          t!(s: "\\\\?\\UNC\\server", dirname_str, "\\\\?\\UNC\\server\\");
 1427          t!(s: "\\\\?\\UNC\\", dirname_str, "\\\\?\\UNC\\\\");
 1428          t!(s: "\\\\?\\C:\\foo.txt", dirname_str, "\\\\?\\C:\\");
 1429          t!(s: "\\\\?\\C:\\", dirname_str, "\\\\?\\C:\\");
 1430          t!(s: "\\\\?\\C:", dirname_str, "\\\\?\\C:");
 1431          t!(s: "\\\\?\\C:/foo/bar", dirname_str, "\\\\?\\C:/foo/bar");
 1432          t!(s: "\\\\?\\foo/bar", dirname_str, "\\\\?\\foo/bar");
 1433          t!(s: "\\\\.\\foo\\bar", dirname_str, "\\\\.\\foo");
 1434          t!(s: "\\\\.\\foo", dirname_str, "\\\\.\\foo");
 1435          t!(s: "\\\\?\\a\\b\\", dirname_str, "\\\\?\\a");
 1436  
 1437          t!(v: b!("hi\\there.txt"), filestem, Some(b!("there")));
 1438          t!(s: "hi\\there.txt", filestem_str, "there");
 1439          t!(s: "hi\\there", filestem_str, "there");
 1440          t!(s: "there.txt", filestem_str, "there");
 1441          t!(s: "there", filestem_str, "there");
 1442          t!(s: ".", filestem_str, None, opt);
 1443          t!(s: "\\", filestem_str, None, opt);
 1444          t!(s: "foo\\.bar", filestem_str, ".bar");
 1445          t!(s: ".bar", filestem_str, ".bar");
 1446          t!(s: "..bar", filestem_str, ".");
 1447          t!(s: "hi\\there..txt", filestem_str, "there.");
 1448          t!(s: "..", filestem_str, None, opt);
 1449          t!(s: "..\\..", filestem_str, None, opt);
 1450          // filestem is based on filename, so we don't need the full set of prefix tests
 1451  
 1452          t!(v: b!("hi\\there.txt"), extension, Some(b!("txt")));
 1453          t!(v: b!("hi\\there"), extension, None);
 1454          t!(s: "hi\\there.txt", extension_str, Some("txt"), opt);
 1455          t!(s: "hi\\there", extension_str, None, opt);
 1456          t!(s: "there.txt", extension_str, Some("txt"), opt);
 1457          t!(s: "there", extension_str, None, opt);
 1458          t!(s: ".", extension_str, None, opt);
 1459          t!(s: "\\", extension_str, None, opt);
 1460          t!(s: "foo\\.bar", extension_str, None, opt);
 1461          t!(s: ".bar", extension_str, None, opt);
 1462          t!(s: "..bar", extension_str, Some("bar"), opt);
 1463          t!(s: "hi\\there..txt", extension_str, Some("txt"), opt);
 1464          t!(s: "..", extension_str, None, opt);
 1465          t!(s: "..\\..", extension_str, None, opt);
 1466          // extension is based on filename, so we don't need the full set of prefix tests
 1467      }
 1468  
 1469      #[test]
 1470      fn test_push() {
 1471          macro_rules! t(
 1472              (s: $path:expr, $join:expr) => (
 1473                  {
 1474                      let path = $path;
 1475                      let join = $join;
 1476                      let mut p1 = Path::new(path);
 1477                      let p2 = p1.clone();
 1478                      p1.push(join);
 1479                      assert!(p1 == p2.join(join));
 1480                  }
 1481              )
 1482          )
 1483  
 1484          t!(s: "a\\b\\c", "..");
 1485          t!(s: "\\a\\b\\c", "d");
 1486          t!(s: "a\\b", "c\\d");
 1487          t!(s: "a\\b", "\\c\\d");
 1488          // this is just a sanity-check test. push and join share an implementation,
 1489          // so there's no need for the full set of prefix tests
 1490  
 1491          // we do want to check one odd case though to ensure the prefix is re-parsed
 1492          let mut p = Path::new("\\\\?\\C:");
 1493          assert!(prefix(&p) == Some(VerbatimPrefix(2)));
 1494          p.push("foo");
 1495          assert!(prefix(&p) == Some(VerbatimDiskPrefix));
 1496          assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
 1497  
 1498          // and another with verbatim non-normalized paths
 1499          let mut p = Path::new("\\\\?\\C:\\a\\");
 1500          p.push("foo");
 1501          assert_eq!(p.as_str(), Some("\\\\?\\C:\\a\\foo"));
 1502      }
 1503  
 1504      #[test]
 1505      fn test_push_path() {
 1506          macro_rules! t(
 1507              (s: $path:expr, $push:expr, $exp:expr) => (
 1508                  {
 1509                      let mut p = Path::new($path);
 1510                      let push = Path::new($push);
 1511                      p.push(&push);
 1512                      assert_eq!(p.as_str(), Some($exp));
 1513                  }
 1514              )
 1515          )
 1516  
 1517          t!(s: "a\\b\\c", "d", "a\\b\\c\\d");
 1518          t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
 1519          t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
 1520          t!(s: "a\\b", "\\c\\d", "\\c\\d");
 1521          t!(s: "a\\b", ".", "a\\b");
 1522          t!(s: "a\\b", "..\\c", "a\\c");
 1523          t!(s: "a\\b", "C:a.txt", "C:a.txt");
 1524          t!(s: "a\\b", "..\\..\\..\\c", "..\\c");
 1525          t!(s: "a\\b", "C:\\a.txt", "C:\\a.txt");
 1526          t!(s: "C:\\a", "C:\\b.txt", "C:\\b.txt");
 1527          t!(s: "C:\\a\\b\\c", "C:d", "C:\\a\\b\\c\\d");
 1528          t!(s: "C:a\\b\\c", "C:d", "C:a\\b\\c\\d");
 1529          t!(s: "C:a\\b", "..\\..\\..\\c", "C:..\\c");
 1530          t!(s: "C:\\a\\b", "..\\..\\..\\c", "C:\\c");
 1531          t!(s: "C:", r"a\b\c", r"C:a\b\c");
 1532          t!(s: "C:", r"..\a", r"C:..\a");
 1533          t!(s: "\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
 1534          t!(s: "\\\\server\\share\\foo", "..\\..\\bar", "\\\\server\\share\\bar");
 1535          t!(s: "\\\\server\\share\\foo", "C:baz", "C:baz");
 1536          t!(s: "\\\\?\\C:\\a\\b", "C:c\\d", "\\\\?\\C:\\a\\b\\c\\d");
 1537          t!(s: "\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
 1538          t!(s: "\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
 1539          t!(s: "\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
 1540          t!(s: "\\\\?\\C:\\a\\b", "..\\..\\..\\c", "\\\\?\\C:\\a\\b\\..\\..\\..\\c");
 1541          t!(s: "\\\\?\\foo\\bar", "..\\..\\c", "\\\\?\\foo\\bar\\..\\..\\c");
 1542          t!(s: "\\\\?\\", "foo", "\\\\?\\\\foo");
 1543          t!(s: "\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
 1544          t!(s: "\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
 1545          t!(s: "\\\\?\\UNC\\server\\share", "C:a", "C:a");
 1546          t!(s: "\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\\\foo");
 1547          t!(s: "C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
 1548          t!(s: "\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
 1549          t!(s: "\\\\.\\foo\\bar", "C:a", "C:a");
 1550          // again, not sure about the following, but I'm assuming \\.\ should be verbatim
 1551          t!(s: "\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
 1552  
 1553          t!(s: "\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
 1554      }
 1555  
 1556      #[test]
 1557      fn test_push_many() {
 1558          macro_rules! t(
 1559              (s: $path:expr, $push:expr, $exp:expr) => (
 1560                  {
 1561                      let mut p = Path::new($path);
 1562                      p.push_many($push);
 1563                      assert_eq!(p.as_str(), Some($exp));
 1564                  }
 1565              );
 1566              (v: $path:expr, $push:expr, $exp:expr) => (
 1567                  {
 1568                      let mut p = Path::new($path);
 1569                      p.push_many($push);
 1570                      assert_eq!(p.as_vec(), $exp);
 1571                  }
 1572              )
 1573          )
 1574  
 1575          t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
 1576          t!(s: "a\\b\\c", ["d", "\\e"], "\\e");
 1577          t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
 1578          t!(s: "a\\b\\c", ["d".to_owned(), "e".to_owned()], "a\\b\\c\\d\\e");
 1579          t!(v: b!("a\\b\\c"), [b!("d"), b!("e")], b!("a\\b\\c\\d\\e"));
 1580          t!(v: b!("a\\b\\c"), [b!("d"), b!("\\e"), b!("f")], b!("\\e\\f"));
 1581          t!(v: b!("a\\b\\c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))],
 1582             b!("a\\b\\c\\d\\e"));
 1583      }
 1584  
 1585      #[test]
 1586      fn test_pop() {
 1587          macro_rules! t(
 1588              (s: $path:expr, $left:expr, $right:expr) => (
 1589                  {
 1590                      let pstr = $path;
 1591                      let mut p = Path::new(pstr);
 1592                      let result = p.pop();
 1593                      let left = $left;
 1594                      assert!(p.as_str() == Some(left),
 1595                          "`{}`.pop() failed; expected remainder `{}`, found `{}`",
 1596                          pstr, left, p.as_str().unwrap());
 1597                      assert!(result == $right);
 1598                  }
 1599              );
 1600              (v: [$($path:expr),+], [$($left:expr),+], $right:expr) => (
 1601                  {
 1602                      let mut p = Path::new(b!($($path),+));
 1603                      let result = p.pop();
 1604                      assert_eq!(p.as_vec(), b!($($left),+));
 1605                      assert!(result == $right);
 1606                  }
 1607              )
 1608          )
 1609  
 1610          t!(s: "a\\b\\c", "a\\b", true);
 1611          t!(s: "a", ".", true);
 1612          t!(s: ".", ".", false);
 1613          t!(s: "\\a", "\\", true);
 1614          t!(s: "\\", "\\", false);
 1615          t!(v: ["a\\b\\c"], ["a\\b"], true);
 1616          t!(v: ["a"], ["."], true);
 1617          t!(v: ["."], ["."], false);
 1618          t!(v: ["\\a"], ["\\"], true);
 1619          t!(v: ["\\"], ["\\"], false);
 1620  
 1621          t!(s: "C:\\a\\b", "C:\\a", true);
 1622          t!(s: "C:\\a", "C:\\", true);
 1623          t!(s: "C:\\", "C:\\", false);
 1624          t!(s: "C:a\\b", "C:a", true);
 1625          t!(s: "C:a", "C:", true);
 1626          t!(s: "C:", "C:", false);
 1627          t!(s: "\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
 1628          t!(s: "\\\\server\\share\\a", "\\\\server\\share", true);
 1629          t!(s: "\\\\server\\share", "\\\\server\\share", false);
 1630          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
 1631          t!(s: "\\\\?\\a\\b", "\\\\?\\a", true);
 1632          t!(s: "\\\\?\\a", "\\\\?\\a", false);
 1633          t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
 1634          t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\", true);
 1635          t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\", false);
 1636          t!(s: "\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
 1637          t!(s: "\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share", true);
 1638          t!(s: "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
 1639          t!(s: "\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
 1640          t!(s: "\\\\.\\a\\b", "\\\\.\\a", true);
 1641          t!(s: "\\\\.\\a", "\\\\.\\a", false);
 1642  
 1643          t!(s: "\\\\?\\a\\b\\", "\\\\?\\a", true);
 1644      }
 1645  
 1646      #[test]
 1647      fn test_root_path() {
 1648          assert!(Path::new("a\\b\\c").root_path() == None);
 1649          assert!(Path::new("\\a\\b\\c").root_path() == Some(Path::new("\\")));
 1650          assert!(Path::new("C:a").root_path() == Some(Path::new("C:")));
 1651          assert!(Path::new("C:\\a").root_path() == Some(Path::new("C:\\")));
 1652          assert!(Path::new("\\\\a\\b\\c").root_path() == Some(Path::new("\\\\a\\b")));
 1653          assert!(Path::new("\\\\?\\a\\b").root_path() == Some(Path::new("\\\\?\\a")));
 1654          assert!(Path::new("\\\\?\\C:\\a").root_path() == Some(Path::new("\\\\?\\C:\\")));
 1655          assert!(Path::new("\\\\?\\UNC\\a\\b\\c").root_path() ==
 1656                  Some(Path::new("\\\\?\\UNC\\a\\b")));
 1657          assert!(Path::new("\\\\.\\a\\b").root_path() == Some(Path::new("\\\\.\\a")));
 1658      }
 1659  
 1660      #[test]
 1661      fn test_join() {
 1662          t!(s: Path::new("a\\b\\c").join(".."), "a\\b");
 1663          t!(s: Path::new("\\a\\b\\c").join("d"), "\\a\\b\\c\\d");
 1664          t!(s: Path::new("a\\b").join("c\\d"), "a\\b\\c\\d");
 1665          t!(s: Path::new("a\\b").join("\\c\\d"), "\\c\\d");
 1666          t!(s: Path::new(".").join("a\\b"), "a\\b");
 1667          t!(s: Path::new("\\").join("a\\b"), "\\a\\b");
 1668          t!(v: Path::new(b!("a\\b\\c")).join(b!("..")), b!("a\\b"));
 1669          t!(v: Path::new(b!("\\a\\b\\c")).join(b!("d")), b!("\\a\\b\\c\\d"));
 1670          // full join testing is covered under test_push_path, so no need for
 1671          // the full set of prefix tests
 1672      }
 1673  
 1674      #[test]
 1675      fn test_join_path() {
 1676          macro_rules! t(
 1677              (s: $path:expr, $join:expr, $exp:expr) => (
 1678                  {
 1679                      let path = Path::new($path);
 1680                      let join = Path::new($join);
 1681                      let res = path.join(&join);
 1682                      assert_eq!(res.as_str(), Some($exp));
 1683                  }
 1684              )
 1685          )
 1686  
 1687          t!(s: "a\\b\\c", "..", "a\\b");
 1688          t!(s: "\\a\\b\\c", "d", "\\a\\b\\c\\d");
 1689          t!(s: "a\\b", "c\\d", "a\\b\\c\\d");
 1690          t!(s: "a\\b", "\\c\\d", "\\c\\d");
 1691          t!(s: ".", "a\\b", "a\\b");
 1692          t!(s: "\\", "a\\b", "\\a\\b");
 1693          // join is implemented using push, so there's no need for
 1694          // the full set of prefix tests
 1695      }
 1696  
 1697      #[test]
 1698      fn test_join_many() {
 1699          macro_rules! t(
 1700              (s: $path:expr, $join:expr, $exp:expr) => (
 1701                  {
 1702                      let path = Path::new($path);
 1703                      let res = path.join_many($join);
 1704                      assert_eq!(res.as_str(), Some($exp));
 1705                  }
 1706              );
 1707              (v: $path:expr, $join:expr, $exp:expr) => (
 1708                  {
 1709                      let path = Path::new($path);
 1710                      let res = path.join_many($join);
 1711                      assert_eq!(res.as_vec(), $exp);
 1712                  }
 1713              )
 1714          )
 1715  
 1716          t!(s: "a\\b\\c", ["d", "e"], "a\\b\\c\\d\\e");
 1717          t!(s: "a\\b\\c", ["..", "d"], "a\\b\\d");
 1718          t!(s: "a\\b\\c", ["d", "\\e", "f"], "\\e\\f");
 1719          t!(s: "a\\b\\c", ["d".to_owned(), "e".to_owned()], "a\\b\\c\\d\\e");
 1720          t!(v: b!("a\\b\\c"), [b!("d"), b!("e")], b!("a\\b\\c\\d\\e"));
 1721          t!(v: b!("a\\b\\c"), [Vec::from_slice(b!("d")), Vec::from_slice(b!("e"))],
 1722             b!("a\\b\\c\\d\\e"));
 1723      }
 1724  
 1725      #[test]
 1726      fn test_with_helpers() {
 1727          macro_rules! t(
 1728              (s: $path:expr, $op:ident, $arg:expr, $res:expr) => (
 1729                  {
 1730                      let pstr = $path;
 1731                      let path = Path::new(pstr);
 1732                      let arg = $arg;
 1733                      let res = path.$op(arg);
 1734                      let exp = $res;
 1735                      assert!(res.as_str() == Some(exp),
 1736                              "`{}`.{}(\"{}\"): Expected `{}`, found `{}`",
 1737                              pstr, stringify!($op), arg, exp, res.as_str().unwrap());
 1738                  }
 1739              )
 1740          )
 1741  
 1742          t!(s: "a\\b\\c", with_filename, "d", "a\\b\\d");
 1743          t!(s: ".", with_filename, "foo", "foo");
 1744          t!(s: "\\a\\b\\c", with_filename, "d", "\\a\\b\\d");
 1745          t!(s: "\\", with_filename, "foo", "\\foo");
 1746          t!(s: "\\a", with_filename, "foo", "\\foo");
 1747          t!(s: "foo", with_filename, "bar", "bar");
 1748          t!(s: "\\", with_filename, "foo\\", "\\foo");
 1749          t!(s: "\\a", with_filename, "foo\\", "\\foo");
 1750          t!(s: "a\\b\\c", with_filename, "", "a\\b");
 1751          t!(s: "a\\b\\c", with_filename, ".", "a\\b");
 1752          t!(s: "a\\b\\c", with_filename, "..", "a");
 1753          t!(s: "\\a", with_filename, "", "\\");
 1754          t!(s: "foo", with_filename, "", ".");
 1755          t!(s: "a\\b\\c", with_filename, "d\\e", "a\\b\\d\\e");
 1756          t!(s: "a\\b\\c", with_filename, "\\d", "a\\b\\d");
 1757          t!(s: "..", with_filename, "foo", "..\\foo");
 1758          t!(s: "..\\..", with_filename, "foo", "..\\..\\foo");
 1759          t!(s: "..", with_filename, "", "..");
 1760          t!(s: "..\\..", with_filename, "", "..\\..");
 1761          t!(s: "C:\\foo\\bar", with_filename, "baz", "C:\\foo\\baz");
 1762          t!(s: "C:\\foo", with_filename, "bar", "C:\\bar");
 1763          t!(s: "C:\\", with_filename, "foo", "C:\\foo");
 1764          t!(s: "C:foo\\bar", with_filename, "baz", "C:foo\\baz");
 1765          t!(s: "C:foo", with_filename, "bar", "C:bar");
 1766          t!(s: "C:", with_filename, "foo", "C:foo");
 1767          t!(s: "C:\\foo", with_filename, "", "C:\\");
 1768          t!(s: "C:foo", with_filename, "", "C:");
 1769          t!(s: "C:\\foo\\bar", with_filename, "..", "C:\\");
 1770          t!(s: "C:\\foo", with_filename, "..", "C:\\");
 1771          t!(s: "C:\\", with_filename, "..", "C:\\");
 1772          t!(s: "C:foo\\bar", with_filename, "..", "C:");
 1773          t!(s: "C:foo", with_filename, "..", "C:..");
 1774          t!(s: "C:", with_filename, "..", "C:..");
 1775          t!(s: "\\\\server\\share\\foo", with_filename, "bar", "\\\\server\\share\\bar");
 1776          t!(s: "\\\\server\\share", with_filename, "foo", "\\\\server\\share\\foo");
 1777          t!(s: "\\\\server\\share\\foo", with_filename, "", "\\\\server\\share");
 1778          t!(s: "\\\\server\\share", with_filename, "", "\\\\server\\share");
 1779          t!(s: "\\\\server\\share\\foo", with_filename, "..", "\\\\server\\share");
 1780          t!(s: "\\\\server\\share", with_filename, "..", "\\\\server\\share");
 1781          t!(s: "\\\\?\\C:\\foo\\bar", with_filename, "baz", "\\\\?\\C:\\foo\\baz");
 1782          t!(s: "\\\\?\\C:\\foo", with_filename, "bar", "\\\\?\\C:\\bar");
 1783          t!(s: "\\\\?\\C:\\", with_filename, "foo", "\\\\?\\C:\\foo");
 1784          t!(s: "\\\\?\\C:\\foo", with_filename, "..", "\\\\?\\C:\\..");
 1785          t!(s: "\\\\?\\foo\\bar", with_filename, "baz", "\\\\?\\foo\\baz");
 1786          t!(s: "\\\\?\\foo", with_filename, "bar", "\\\\?\\foo\\bar");
 1787          t!(s: "\\\\?\\", with_filename, "foo", "\\\\?\\\\foo");
 1788          t!(s: "\\\\?\\foo\\bar", with_filename, "..", "\\\\?\\foo\\..");
 1789          t!(s: "\\\\.\\foo\\bar", with_filename, "baz", "\\\\.\\foo\\baz");
 1790          t!(s: "\\\\.\\foo", with_filename, "bar", "\\\\.\\foo\\bar");
 1791          t!(s: "\\\\.\\foo\\bar", with_filename, "..", "\\\\.\\foo\\..");
 1792  
 1793          t!(s: "hi\\there.txt", with_extension, "exe", "hi\\there.exe");
 1794          t!(s: "hi\\there.txt", with_extension, "", "hi\\there");
 1795          t!(s: "hi\\there.txt", with_extension, ".", "hi\\there..");
 1796          t!(s: "hi\\there.txt", with_extension, "..", "hi\\there...");
 1797          t!(s: "hi\\there", with_extension, "txt", "hi\\there.txt");
 1798          t!(s: "hi\\there", with_extension, ".", "hi\\there..");
 1799          t!(s: "hi\\there", with_extension, "..", "hi\\there...");
 1800          t!(s: "hi\\there.", with_extension, "txt", "hi\\there.txt");
 1801          t!(s: "hi\\.foo", with_extension, "txt", "hi\\.foo.txt");
 1802          t!(s: "hi\\there.txt", with_extension, ".foo", "hi\\there..foo");
 1803          t!(s: "\\", with_extension, "txt", "\\");
 1804          t!(s: "\\", with_extension, ".", "\\");
 1805          t!(s: "\\", with_extension, "..", "\\");
 1806          t!(s: ".", with_extension, "txt", ".");
 1807          // extension setter calls filename setter internally, no need for extended tests
 1808      }
 1809  
 1810      #[test]
 1811      fn test_setters() {
 1812          macro_rules! t(
 1813              (s: $path:expr, $set:ident, $with:ident, $arg:expr) => (
 1814                  {
 1815                      let path = $path;
 1816                      let arg = $arg;
 1817                      let mut p1 = Path::new(path);
 1818                      p1.$set(arg);
 1819                      let p2 = Path::new(path);
 1820                      assert!(p1 == p2.$with(arg));
 1821                  }
 1822              );
 1823              (v: $path:expr, $set:ident, $with:ident, $arg:expr) => (
 1824                  {
 1825                      let path = $path;
 1826                      let arg = $arg;
 1827                      let mut p1 = Path::new(path);
 1828                      p1.$set(arg);
 1829                      let p2 = Path::new(path);
 1830                      assert!(p1 == p2.$with(arg));
 1831                  }
 1832              )
 1833          )
 1834  
 1835          t!(v: b!("a\\b\\c"), set_filename, with_filename, b!("d"));
 1836          t!(v: b!("\\"), set_filename, with_filename, b!("foo"));
 1837          t!(s: "a\\b\\c", set_filename, with_filename, "d");
 1838          t!(s: "\\", set_filename, with_filename, "foo");
 1839          t!(s: ".", set_filename, with_filename, "foo");
 1840          t!(s: "a\\b", set_filename, with_filename, "");
 1841          t!(s: "a", set_filename, with_filename, "");
 1842  
 1843          t!(v: b!("hi\\there.txt"), set_extension, with_extension, b!("exe"));
 1844          t!(s: "hi\\there.txt", set_extension, with_extension, "exe");
 1845          t!(s: "hi\\there.", set_extension, with_extension, "txt");
 1846          t!(s: "hi\\there", set_extension, with_extension, "txt");
 1847          t!(s: "hi\\there.txt", set_extension, with_extension, "");
 1848          t!(s: "hi\\there", set_extension, with_extension, "");
 1849          t!(s: ".", set_extension, with_extension, "txt");
 1850  
 1851          // with_ helpers use the setter internally, so the tests for the with_ helpers
 1852          // will suffice. No need for the full set of prefix tests.
 1853      }
 1854  
 1855      #[test]
 1856      fn test_getters() {
 1857          macro_rules! t(
 1858              (s: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
 1859                  {
 1860                      let path = $path;
 1861                      let filename = $filename;
 1862                      assert!(path.filename_str() == filename,
 1863                              "`{}`.filename_str(): Expected `{:?}`, found `{:?}`",
 1864                              path.as_str().unwrap(), filename, path.filename_str());
 1865                      let dirname = $dirname;
 1866                      assert!(path.dirname_str() == dirname,
 1867                              "`{}`.dirname_str(): Expected `{:?}`, found `{:?}`",
 1868                              path.as_str().unwrap(), dirname, path.dirname_str());
 1869                      let filestem = $filestem;
 1870                      assert!(path.filestem_str() == filestem,
 1871                              "`{}`.filestem_str(): Expected `{:?}`, found `{:?}`",
 1872                              path.as_str().unwrap(), filestem, path.filestem_str());
 1873                      let ext = $ext;
 1874                      assert!(path.extension_str() == ext,
 1875                              "`{}`.extension_str(): Expected `{:?}`, found `{:?}`",
 1876                              path.as_str().unwrap(), ext, path.extension_str());
 1877                  }
 1878              );
 1879              (v: $path:expr, $filename:expr, $dirname:expr, $filestem:expr, $ext:expr) => (
 1880                  {
 1881                      let path = $path;
 1882                      assert!(path.filename() == $filename);
 1883                      assert!(path.dirname() == $dirname);
 1884                      assert!(path.filestem() == $filestem);
 1885                      assert!(path.extension() == $ext);
 1886                  }
 1887              )
 1888          )
 1889  
 1890          t!(v: Path::new(b!("a\\b\\c")), Some(b!("c")), b!("a\\b"), Some(b!("c")), None);
 1891          t!(s: Path::new("a\\b\\c"), Some("c"), Some("a\\b"), Some("c"), None);
 1892          t!(s: Path::new("."), None, Some("."), None, None);
 1893          t!(s: Path::new("\\"), None, Some("\\"), None, None);
 1894          t!(s: Path::new(".."), None, Some(".."), None, None);
 1895          t!(s: Path::new("..\\.."), None, Some("..\\.."), None, None);
 1896          t!(s: Path::new("hi\\there.txt"), Some("there.txt"), Some("hi"),
 1897                Some("there"), Some("txt"));
 1898          t!(s: Path::new("hi\\there"), Some("there"), Some("hi"), Some("there"), None);
 1899          t!(s: Path::new("hi\\there."), Some("there."), Some("hi"),
 1900                Some("there"), Some(""));
 1901          t!(s: Path::new("hi\\.there"), Some(".there"), Some("hi"), Some(".there"), None);
 1902          t!(s: Path::new("hi\\..there"), Some("..there"), Some("hi"),
 1903                Some("."), Some("there"));
 1904  
 1905          // these are already tested in test_components, so no need for extended tests
 1906      }
 1907  
 1908      #[test]
 1909      fn test_dir_path() {
 1910          t!(s: Path::new("hi\\there").dir_path(), "hi");
 1911          t!(s: Path::new("hi").dir_path(), ".");
 1912          t!(s: Path::new("\\hi").dir_path(), "\\");
 1913          t!(s: Path::new("\\").dir_path(), "\\");
 1914          t!(s: Path::new("..").dir_path(), "..");
 1915          t!(s: Path::new("..\\..").dir_path(), "..\\..");
 1916  
 1917          // dir_path is just dirname interpreted as a path.
 1918          // No need for extended tests
 1919      }
 1920  
 1921      #[test]
 1922      fn test_is_absolute() {
 1923          macro_rules! t(
 1924              ($path:expr, $abs:expr, $vol:expr, $cwd:expr, $rel:expr) => (
 1925                  {
 1926                      let path = Path::new($path);
 1927                      let (abs, vol, cwd, rel) = ($abs, $vol, $cwd, $rel);
 1928                      let b = path.is_absolute();
 1929                      assert!(b == abs, "Path '{}'.is_absolute(): expected {:?}, found {:?}",
 1930                              path.as_str().unwrap(), abs, b);
 1931                      let b = is_vol_relative(&path);
 1932                      assert!(b == vol, "is_vol_relative('{}'): expected {:?}, found {:?}",
 1933                              path.as_str().unwrap(), vol, b);
 1934                      let b = is_cwd_relative(&path);
 1935                      assert!(b == cwd, "is_cwd_relative('{}'): expected {:?}, found {:?}",
 1936                              path.as_str().unwrap(), cwd, b);
 1937                      let b = path.is_relative();
 1938                      assert!(b == rel, "Path '{}'.is_relativf(): expected {:?}, found {:?}",
 1939                              path.as_str().unwrap(), rel, b);
 1940                  }
 1941              )
 1942          )
 1943          t!("a\\b\\c", false, false, false, true);
 1944          t!("\\a\\b\\c", false, true, false, false);
 1945          t!("a", false, false, false, true);
 1946          t!("\\a", false, true, false, false);
 1947          t!(".", false, false, false, true);
 1948          t!("\\", false, true, false, false);
 1949          t!("..", false, false, false, true);
 1950          t!("..\\..", false, false, false, true);
 1951          t!("C:a\\b.txt", false, false, true, false);
 1952          t!("C:\\a\\b.txt", true, false, false, false);
 1953          t!("\\\\server\\share\\a\\b.txt", true, false, false, false);
 1954          t!("\\\\?\\a\\b\\c.txt", true, false, false, false);
 1955          t!("\\\\?\\C:\\a\\b.txt", true, false, false, false);
 1956          t!("\\\\?\\C:a\\b.txt", true, false, false, false); // NB: not equivalent to C:a\b.txt
 1957          t!("\\\\?\\UNC\\server\\share\\a\\b.txt", true, false, false, false);
 1958          t!("\\\\.\\a\\b", true, false, false, false);
 1959      }
 1960  
 1961      #[test]
 1962      fn test_is_ancestor_of() {
 1963          macro_rules! t(
 1964              (s: $path:expr, $dest:expr, $exp:expr) => (
 1965                  {
 1966                      let path = Path::new($path);
 1967                      let dest = Path::new($dest);
 1968                      let exp = $exp;
 1969                      let res = path.is_ancestor_of(&dest);
 1970                      assert!(res == exp,
 1971                              "`{}`.is_ancestor_of(`{}`): Expected {:?}, found {:?}",
 1972                              path.as_str().unwrap(), dest.as_str().unwrap(), exp, res);
 1973                  }
 1974              )
 1975          )
 1976  
 1977          t!(s: "a\\b\\c", "a\\b\\c\\d", true);
 1978          t!(s: "a\\b\\c", "a\\b\\c", true);
 1979          t!(s: "a\\b\\c", "a\\b", false);
 1980          t!(s: "\\a\\b\\c", "\\a\\b\\c", true);
 1981          t!(s: "\\a\\b", "\\a\\b\\c", true);
 1982          t!(s: "\\a\\b\\c\\d", "\\a\\b\\c", false);
 1983          t!(s: "\\a\\b", "a\\b\\c", false);
 1984          t!(s: "a\\b", "\\a\\b\\c", false);
 1985          t!(s: "a\\b\\c", "a\\b\\d", false);
 1986          t!(s: "..\\a\\b\\c", "a\\b\\c", false);
 1987          t!(s: "a\\b\\c", "..\\a\\b\\c", false);
 1988          t!(s: "a\\b\\c", "a\\b\\cd", false);
 1989          t!(s: "a\\b\\cd", "a\\b\\c", false);
 1990          t!(s: "..\\a\\b", "..\\a\\b\\c", true);
 1991          t!(s: ".", "a\\b", true);
 1992          t!(s: ".", ".", true);
 1993          t!(s: "\\", "\\", true);
 1994          t!(s: "\\", "\\a\\b", true);
 1995          t!(s: "..", "a\\b", true);
 1996          t!(s: "..\\..", "a\\b", true);
 1997          t!(s: "foo\\bar", "foobar", false);
 1998          t!(s: "foobar", "foo\\bar", false);
 1999  
 2000          t!(s: "foo", "C:foo", false);
 2001          t!(s: "C:foo", "foo", false);
 2002          t!(s: "C:foo", "C:foo\\bar", true);
 2003          t!(s: "C:foo\\bar", "C:foo", false);
 2004          t!(s: "C:\\foo", "C:\\foo\\bar", true);
 2005          t!(s: "C:", "C:", true);
 2006          t!(s: "C:", "C:\\", false);
 2007          t!(s: "C:\\", "C:", false);
 2008          t!(s: "C:\\", "C:\\", true);
 2009          t!(s: "C:\\foo\\bar", "C:\\foo", false);
 2010          t!(s: "C:foo\\bar", "C:foo", false);
 2011          t!(s: "C:\\foo", "\\foo", false);
 2012          t!(s: "\\foo", "C:\\foo", false);
 2013          t!(s: "\\\\server\\share\\foo", "\\\\server\\share\\foo\\bar", true);
 2014          t!(s: "\\\\server\\share", "\\\\server\\share\\foo", true);
 2015          t!(s: "\\\\server\\share\\foo", "\\\\server\\share", false);
 2016          t!(s: "C:\\foo", "\\\\server\\share\\foo", false);
 2017          t!(s: "\\\\server\\share\\foo", "C:\\foo", false);
 2018          t!(s: "\\\\?\\foo\\bar", "\\\\?\\foo\\bar\\baz", true);
 2019          t!(s: "\\\\?\\foo\\bar\\baz", "\\\\?\\foo\\bar", false);
 2020          t!(s: "\\\\?\\foo\\bar", "\\foo\\bar\\baz", false);
 2021          t!(s: "\\foo\\bar", "\\\\?\\foo\\bar\\baz", false);
 2022          t!(s: "\\\\?\\C:\\foo\\bar", "\\\\?\\C:\\foo\\bar\\baz", true);
 2023          t!(s: "\\\\?\\C:\\foo\\bar\\baz", "\\\\?\\C:\\foo\\bar", false);
 2024          t!(s: "\\\\?\\C:\\", "\\\\?\\C:\\foo", true);
 2025          t!(s: "\\\\?\\C:", "\\\\?\\C:\\", false); // this is a weird one
 2026          t!(s: "\\\\?\\C:\\", "\\\\?\\C:", false);
 2027          t!(s: "\\\\?\\C:\\a", "\\\\?\\c:\\a\\b", true);
 2028          t!(s: "\\\\?\\c:\\a", "\\\\?\\C:\\a\\b", true);
 2029          t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a\\b", false);
 2030          t!(s: "\\\\?\\foo", "\\\\?\\foobar", false);
 2031          t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", true);
 2032          t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\", true);
 2033          t!(s: "\\\\?\\a\\b\\", "\\\\?\\a\\b", true);
 2034          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", false);
 2035          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b\\", false);
 2036          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c\\d", true);
 2037          t!(s: "\\\\?\\UNC\\a\\b\\c\\d", "\\\\?\\UNC\\a\\b\\c", false);
 2038          t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", true);
 2039          t!(s: "\\\\.\\foo\\bar", "\\\\.\\foo\\bar\\baz", true);
 2040          t!(s: "\\\\.\\foo\\bar\\baz", "\\\\.\\foo\\bar", false);
 2041          t!(s: "\\\\.\\foo", "\\\\.\\foo\\bar", true);
 2042          t!(s: "\\\\.\\foo", "\\\\.\\foobar", false);
 2043  
 2044          t!(s: "\\a\\b", "\\\\?\\a\\b", false);
 2045          t!(s: "\\\\?\\a\\b", "\\a\\b", false);
 2046          t!(s: "\\a\\b", "\\\\?\\C:\\a\\b", false);
 2047          t!(s: "\\\\?\\C:\\a\\b", "\\a\\b", false);
 2048          t!(s: "Z:\\a\\b", "\\\\?\\z:\\a\\b", true);
 2049          t!(s: "C:\\a\\b", "\\\\?\\D:\\a\\b", false);
 2050          t!(s: "a\\b", "\\\\?\\a\\b", false);
 2051          t!(s: "\\\\?\\a\\b", "a\\b", false);
 2052          t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b", true);
 2053          t!(s: "\\\\?\\C:\\a\\b", "C:\\a\\b", true);
 2054          t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", false);
 2055          t!(s: "C:a\\b", "\\\\?\\C:a\\b", false);
 2056          t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", false);
 2057          t!(s: "\\\\?\\C:a\\b", "C:a\\b", false);
 2058          t!(s: "C:\\a\\b", "\\\\?\\C:\\a\\b\\", true);
 2059          t!(s: "\\\\?\\C:\\a\\b\\", "C:\\a\\b", true);
 2060          t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b\\c", true);
 2061          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b\\c", true);
 2062      }
 2063  
 2064      #[test]
 2065      fn test_ends_with_path() {
 2066          macro_rules! t(
 2067              (s: $path:expr, $child:expr, $exp:expr) => (
 2068                  {
 2069                      let path = Path::new($path);
 2070                      let child = Path::new($child);
 2071                      assert_eq!(path.ends_with_path(&child), $exp);
 2072                  }
 2073              );
 2074          )
 2075  
 2076          t!(s: "a\\b\\c", "c", true);
 2077          t!(s: "a\\b\\c", "d", false);
 2078          t!(s: "foo\\bar\\quux", "bar", false);
 2079          t!(s: "foo\\bar\\quux", "barquux", false);
 2080          t!(s: "a\\b\\c", "b\\c", true);
 2081          t!(s: "a\\b\\c", "a\\b\\c", true);
 2082          t!(s: "a\\b\\c", "foo\\a\\b\\c", false);
 2083          t!(s: "\\a\\b\\c", "a\\b\\c", true);
 2084          t!(s: "\\a\\b\\c", "\\a\\b\\c", false); // child must be relative
 2085          t!(s: "\\a\\b\\c", "foo\\a\\b\\c", false);
 2086          t!(s: "a\\b\\c", "", false);
 2087          t!(s: "", "", true);
 2088          t!(s: "\\a\\b\\c", "d\\e\\f", false);
 2089          t!(s: "a\\b\\c", "a\\b", false);
 2090          t!(s: "a\\b\\c", "b", false);
 2091          t!(s: "C:\\a\\b", "b", true);
 2092          t!(s: "C:\\a\\b", "C:b", false);
 2093          t!(s: "C:\\a\\b", "C:a\\b", false);
 2094      }
 2095  
 2096      #[test]
 2097      fn test_path_relative_from() {
 2098          macro_rules! t(
 2099              (s: $path:expr, $other:expr, $exp:expr) => (
 2100                  {
 2101                      let path = Path::new($path);
 2102                      let other = Path::new($other);
 2103                      let res = path.path_relative_from(&other);
 2104                      let exp = $exp;
 2105                      assert!(res.as_ref().and_then(|x| x.as_str()) == exp,
 2106                              "`{}`.path_relative_from(`{}`): Expected {:?}, got {:?}",
 2107                              path.as_str().unwrap(), other.as_str().unwrap(), exp,
 2108                              res.as_ref().and_then(|x| x.as_str()));
 2109                  }
 2110              )
 2111          )
 2112  
 2113          t!(s: "a\\b\\c", "a\\b", Some("c"));
 2114          t!(s: "a\\b\\c", "a\\b\\d", Some("..\\c"));
 2115          t!(s: "a\\b\\c", "a\\b\\c\\d", Some(".."));
 2116          t!(s: "a\\b\\c", "a\\b\\c", Some("."));
 2117          t!(s: "a\\b\\c", "a\\b\\c\\d\\e", Some("..\\.."));
 2118          t!(s: "a\\b\\c", "a\\d\\e", Some("..\\..\\b\\c"));
 2119          t!(s: "a\\b\\c", "d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
 2120          t!(s: "a\\b\\c", "\\a\\b\\c", None);
 2121          t!(s: "\\a\\b\\c", "a\\b\\c", Some("\\a\\b\\c"));
 2122          t!(s: "\\a\\b\\c", "\\a\\b\\c\\d", Some(".."));
 2123          t!(s: "\\a\\b\\c", "\\a\\b", Some("c"));
 2124          t!(s: "\\a\\b\\c", "\\a\\b\\c\\d\\e", Some("..\\.."));
 2125          t!(s: "\\a\\b\\c", "\\a\\d\\e", Some("..\\..\\b\\c"));
 2126          t!(s: "\\a\\b\\c", "\\d\\e\\f", Some("..\\..\\..\\a\\b\\c"));
 2127          t!(s: "hi\\there.txt", "hi\\there", Some("..\\there.txt"));
 2128          t!(s: ".", "a", Some(".."));
 2129          t!(s: ".", "a\\b", Some("..\\.."));
 2130          t!(s: ".", ".", Some("."));
 2131          t!(s: "a", ".", Some("a"));
 2132          t!(s: "a\\b", ".", Some("a\\b"));
 2133          t!(s: "..", ".", Some(".."));
 2134          t!(s: "a\\b\\c", "a\\b\\c", Some("."));
 2135          t!(s: "\\a\\b\\c", "\\a\\b\\c", Some("."));
 2136          t!(s: "\\", "\\", Some("."));
 2137          t!(s: "\\", ".", Some("\\"));
 2138          t!(s: "..\\..\\a", "b", Some("..\\..\\..\\a"));
 2139          t!(s: "a", "..\\..\\b", None);
 2140          t!(s: "..\\..\\a", "..\\..\\b", Some("..\\a"));
 2141          t!(s: "..\\..\\a", "..\\..\\a\\b", Some(".."));
 2142          t!(s: "..\\..\\a\\b", "..\\..\\a", Some("b"));
 2143  
 2144          t!(s: "C:a\\b\\c", "C:a\\b", Some("c"));
 2145          t!(s: "C:a\\b", "C:a\\b\\c", Some(".."));
 2146          t!(s: "C:" ,"C:a\\b", Some("..\\.."));
 2147          t!(s: "C:a\\b", "C:c\\d", Some("..\\..\\a\\b"));
 2148          t!(s: "C:a\\b", "D:c\\d", Some("C:a\\b"));
 2149          t!(s: "C:a\\b", "C:..\\c", None);
 2150          t!(s: "C:..\\a", "C:b\\c", Some("..\\..\\..\\a"));
 2151          t!(s: "C:\\a\\b\\c", "C:\\a\\b", Some("c"));
 2152          t!(s: "C:\\a\\b", "C:\\a\\b\\c", Some(".."));
 2153          t!(s: "C:\\", "C:\\a\\b", Some("..\\.."));
 2154          t!(s: "C:\\a\\b", "C:\\c\\d", Some("..\\..\\a\\b"));
 2155          t!(s: "C:\\a\\b", "C:a\\b", Some("C:\\a\\b"));
 2156          t!(s: "C:a\\b", "C:\\a\\b", None);
 2157          t!(s: "\\a\\b", "C:\\a\\b", None);
 2158          t!(s: "\\a\\b", "C:a\\b", None);
 2159          t!(s: "a\\b", "C:\\a\\b", None);
 2160          t!(s: "a\\b", "C:a\\b", None);
 2161  
 2162          t!(s: "\\\\a\\b\\c", "\\\\a\\b", Some("c"));
 2163          t!(s: "\\\\a\\b", "\\\\a\\b\\c", Some(".."));
 2164          t!(s: "\\\\a\\b\\c\\e", "\\\\a\\b\\c\\d", Some("..\\e"));
 2165          t!(s: "\\\\a\\c\\d", "\\\\a\\b\\d", Some("\\\\a\\c\\d"));
 2166          t!(s: "\\\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\b\\c\\d"));
 2167          t!(s: "\\\\a\\b\\c", "\\d\\e", Some("\\\\a\\b\\c"));
 2168          t!(s: "\\d\\e", "\\\\a\\b\\c", None);
 2169          t!(s: "d\\e", "\\\\a\\b\\c", None);
 2170          t!(s: "C:\\a\\b\\c", "\\\\a\\b\\c", Some("C:\\a\\b\\c"));
 2171          t!(s: "C:\\c", "\\\\a\\b\\c", Some("C:\\c"));
 2172  
 2173          t!(s: "\\\\?\\a\\b", "\\a\\b", Some("\\\\?\\a\\b"));
 2174          t!(s: "\\\\?\\a\\b", "a\\b", Some("\\\\?\\a\\b"));
 2175          t!(s: "\\\\?\\a\\b", "\\b", Some("\\\\?\\a\\b"));
 2176          t!(s: "\\\\?\\a\\b", "b", Some("\\\\?\\a\\b"));
 2177          t!(s: "\\\\?\\a\\b", "\\\\?\\a\\b\\c", Some(".."));
 2178          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\b", Some("c"));
 2179          t!(s: "\\\\?\\a\\b", "\\\\?\\c\\d", Some("\\\\?\\a\\b"));
 2180          t!(s: "\\\\?\\a", "\\\\?\\b", Some("\\\\?\\a"));
 2181  
 2182          t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
 2183          t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
 2184          t!(s: "\\\\?\\C:\\a", "\\\\?\\C:\\b", Some("..\\a"));
 2185          t!(s: "\\\\?\\C:\\a", "\\\\?\\D:\\a", Some("\\\\?\\C:\\a"));
 2186          t!(s: "\\\\?\\C:\\a\\b", "\\\\?\\c:\\a", Some("b"));
 2187          t!(s: "\\\\?\\C:\\a\\b", "C:\\a", Some("b"));
 2188          t!(s: "\\\\?\\C:\\a", "C:\\a\\b", Some(".."));
 2189          t!(s: "C:\\a\\b", "\\\\?\\C:\\a", Some("b"));
 2190          t!(s: "C:\\a", "\\\\?\\C:\\a\\b", Some(".."));
 2191          t!(s: "\\\\?\\C:\\a", "D:\\a", Some("\\\\?\\C:\\a"));
 2192          t!(s: "\\\\?\\c:\\a\\b", "C:\\a", Some("b"));
 2193          t!(s: "\\\\?\\C:\\a\\b", "C:a\\b", Some("\\\\?\\C:\\a\\b"));
 2194          t!(s: "\\\\?\\C:\\a\\.\\b", "C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
 2195          t!(s: "\\\\?\\C:\\a\\b/c", "C:\\a", Some("\\\\?\\C:\\a\\b/c"));
 2196          t!(s: "\\\\?\\C:\\a\\..\\b", "C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
 2197          t!(s: "C:a\\b", "\\\\?\\C:\\a\\b", None);
 2198          t!(s: "\\\\?\\C:\\a\\.\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\.\\b"));
 2199          t!(s: "\\\\?\\C:\\a\\b/c", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\b/c"));
 2200          t!(s: "\\\\?\\C:\\a\\..\\b", "\\\\?\\C:\\a", Some("\\\\?\\C:\\a\\..\\b"));
 2201          t!(s: "\\\\?\\C:\\a\\b\\", "\\\\?\\C:\\a", Some("b"));
 2202          t!(s: "\\\\?\\C:\\.\\b", "\\\\?\\C:\\.", Some("b"));
 2203          t!(s: "C:\\b", "\\\\?\\C:\\.", Some("..\\b"));
 2204          t!(s: "\\\\?\\a\\.\\b\\c", "\\\\?\\a\\.\\b", Some("c"));
 2205          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\.\\d", Some("..\\..\\b\\c"));
 2206          t!(s: "\\\\?\\a\\..\\b", "\\\\?\\a\\..", Some("b"));
 2207          t!(s: "\\\\?\\a\\b\\..", "\\\\?\\a\\b", Some("\\\\?\\a\\b\\.."));
 2208          t!(s: "\\\\?\\a\\b\\c", "\\\\?\\a\\..\\b", Some("..\\..\\b\\c"));
 2209  
 2210          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
 2211          t!(s: "\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b\\c", Some(".."));
 2212          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
 2213          t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\?\\UNC\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
 2214          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
 2215          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\?\\C:\\a\\b\\c", Some("\\\\?\\UNC\\a\\b\\c"));
 2216          t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
 2217          t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
 2218          t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\?\\UNC\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
 2219          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\b", Some("c"));
 2220          t!(s: "\\\\?\\UNC\\a\\b", "\\\\a\\b\\c", Some(".."));
 2221          t!(s: "\\\\?\\UNC\\a\\b\\c", "\\\\a\\c\\d", Some("\\\\?\\UNC\\a\\b\\c"));
 2222          t!(s: "\\\\?\\UNC\\b\\c\\d", "\\\\a\\c\\d", Some("\\\\?\\UNC\\b\\c\\d"));
 2223          t!(s: "\\\\?\\UNC\\a\\b\\.", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\."));
 2224          t!(s: "\\\\?\\UNC\\a\\b\\c/d", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\c/d"));
 2225          t!(s: "\\\\?\\UNC\\a\\b\\..", "\\\\a\\b", Some("\\\\?\\UNC\\a\\b\\.."));
 2226          t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\b", Some("c"));
 2227          t!(s: "\\\\a\\b\\c", "\\\\?\\UNC\\a\\c\\d", Some("\\\\a\\b\\c"));
 2228      }
 2229  
 2230      #[test]
 2231      fn test_str_components() {
 2232          macro_rules! t(
 2233              (s: $path:expr, $exp:expr) => (
 2234                  {
 2235                      let path = Path::new($path);
 2236                      let comps = path.str_components().map(|x|x.unwrap())
 2237                                  .collect::<Vec<&str>>();
 2238                      let exp: &[&str] = $exp;
 2239                      assert_eq!(comps.as_slice(), exp);
 2240                      let comps = path.str_components().rev().map(|x|x.unwrap())
 2241                                  .collect::<Vec<&str>>();
 2242                      let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&str>>();
 2243                      assert_eq!(comps, exp);
 2244                  }
 2245              );
 2246              (v: [$($arg:expr),+], $exp:expr) => (
 2247                  {
 2248                      let path = Path::new(b!($($arg),+));
 2249                      let comps = path.str_components().map(|x|x.unwrap()).collect::<Vec<&str>>();
 2250                      let exp: &[&str] = $exp;
 2251                      assert_eq!(comps.as_slice(), exp);
 2252                      let comps = path.str_components().rev().map(|x|x.unwrap())
 2253                                  .collect::<Vec<&str>>();
 2254                      let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&str>>();
 2255                      assert_eq!(comps, exp);
 2256                  }
 2257              )
 2258          )
 2259  
 2260          t!(v: ["a\\b\\c"], ["a", "b", "c"]);
 2261          t!(s: "a\\b\\c", ["a", "b", "c"]);
 2262          t!(s: "a\\b\\d", ["a", "b", "d"]);
 2263          t!(s: "a\\b\\cd", ["a", "b", "cd"]);
 2264          t!(s: "\\a\\b\\c", ["a", "b", "c"]);
 2265          t!(s: "a", ["a"]);
 2266          t!(s: "\\a", ["a"]);
 2267          t!(s: "\\", []);
 2268          t!(s: ".", ["."]);
 2269          t!(s: "..", [".."]);
 2270          t!(s: "..\\..", ["..", ".."]);
 2271          t!(s: "..\\..\\foo", ["..", "..", "foo"]);
 2272          t!(s: "C:foo\\bar", ["foo", "bar"]);
 2273          t!(s: "C:foo", ["foo"]);
 2274          t!(s: "C:", []);
 2275          t!(s: "C:\\foo\\bar", ["foo", "bar"]);
 2276          t!(s: "C:\\foo", ["foo"]);
 2277          t!(s: "C:\\", []);
 2278          t!(s: "\\\\server\\share\\foo\\bar", ["foo", "bar"]);
 2279          t!(s: "\\\\server\\share\\foo", ["foo"]);
 2280          t!(s: "\\\\server\\share", []);
 2281          t!(s: "\\\\?\\foo\\bar\\baz", ["bar", "baz"]);
 2282          t!(s: "\\\\?\\foo\\bar", ["bar"]);
 2283          t!(s: "\\\\?\\foo", []);
 2284          t!(s: "\\\\?\\", []);
 2285          t!(s: "\\\\?\\a\\b", ["b"]);
 2286          t!(s: "\\\\?\\a\\b\\", ["b"]);
 2287          t!(s: "\\\\?\\foo\\bar\\\\baz", ["bar", "", "baz"]);
 2288          t!(s: "\\\\?\\C:\\foo\\bar", ["foo", "bar"]);
 2289          t!(s: "\\\\?\\C:\\foo", ["foo"]);
 2290          t!(s: "\\\\?\\C:\\", []);
 2291          t!(s: "\\\\?\\C:\\foo\\", ["foo"]);
 2292          t!(s: "\\\\?\\UNC\\server\\share\\foo\\bar", ["foo", "bar"]);
 2293          t!(s: "\\\\?\\UNC\\server\\share\\foo", ["foo"]);
 2294          t!(s: "\\\\?\\UNC\\server\\share", []);
 2295          t!(s: "\\\\.\\foo\\bar\\baz", ["bar", "baz"]);
 2296          t!(s: "\\\\.\\foo\\bar", ["bar"]);
 2297          t!(s: "\\\\.\\foo", []);
 2298      }
 2299  
 2300      #[test]
 2301      fn test_components_iter() {
 2302          macro_rules! t(
 2303              (s: $path:expr, $exp:expr) => (
 2304                  {
 2305                      let path = Path::new($path);
 2306                      let comps = path.components().collect::<Vec<&[u8]>>();
 2307                      let exp: &[&[u8]] = $exp;
 2308                      assert_eq!(comps.as_slice(), exp);
 2309                      let comps = path.components().rev().collect::<Vec<&[u8]>>();
 2310                      let exp = exp.iter().rev().map(|&x|x).collect::<Vec<&[u8]>>();
 2311                      assert_eq!(comps, exp);
 2312                  }
 2313              )
 2314          )
 2315  
 2316          t!(s: "a\\b\\c", [b!("a"), b!("b"), b!("c")]);
 2317          t!(s: ".", [b!(".")]);
 2318          // since this is really a wrapper around str_components, those tests suffice
 2319      }
 2320  
 2321      #[test]
 2322      fn test_make_non_verbatim() {
 2323          macro_rules! t(
 2324              ($path:expr, $exp:expr) => (
 2325                  {
 2326                      let path = Path::new($path);
 2327                      let exp: Option<&str> = $exp;
 2328                      let exp = exp.map(|s| Path::new(s));
 2329                      assert!(make_non_verbatim(&path) == exp);
 2330                  }
 2331              )
 2332          )
 2333  
 2334          t!(r"\a\b\c", Some(r"\a\b\c"));
 2335          t!(r"a\b\c", Some(r"a\b\c"));
 2336          t!(r"C:\a\b\c", Some(r"C:\a\b\c"));
 2337          t!(r"C:a\b\c", Some(r"C:a\b\c"));
 2338          t!(r"\\server\share\foo", Some(r"\\server\share\foo"));
 2339          t!(r"\\.\foo", None);
 2340          t!(r"\\?\foo", None);
 2341          t!(r"\\?\C:", None);
 2342          t!(r"\\?\C:foo", None);
 2343          t!(r"\\?\C:\", Some(r"C:\"));
 2344          t!(r"\\?\C:\foo", Some(r"C:\foo"));
 2345          t!(r"\\?\C:\foo\bar\baz", Some(r"C:\foo\bar\baz"));
 2346          t!(r"\\?\C:\foo\.\bar\baz", None);
 2347          t!(r"\\?\C:\foo\bar\..\baz", None);
 2348          t!(r"\\?\C:\foo\bar\..", None);
 2349          t!(r"\\?\UNC\server\share\foo", Some(r"\\server\share\foo"));
 2350          t!(r"\\?\UNC\server\share", Some(r"\\server\share"));
 2351          t!(r"\\?\UNC\server", None);
 2352          t!(r"\\?\UNC\server\", None);
 2353      }
 2354  }


libstd/path/windows.rs:968:1-968:1 -fn- definition:
fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
    if path.starts_with("\\\\") {
        // \\
references:- 2
689:         let (prefix, val) = {
690:             let prefix = parse_prefix(s.as_slice());
691:             let path = Path::normalize__(s.as_slice(), prefix);


libstd/path/windows.rs:43:66-43:66 -NK_AS_STR_TODO- definition:
/// Iterator that yields successive components of a Path as &[u8]
pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8],
                                    StrComponents<'a>>;
references:- 3
48: pub type RevComponents<'a> = Rev<Components<'a>>;
--
653:     #[deprecated = "replaced by .components().rev()"]
654:     pub fn rev_components<'a>(&'a self) -> Rev<Components<'a>> {
655:         self.components().rev()


libstd/path/windows.rs:953:23-953:23 -enum- definition:
pub enum PathPrefix {
    /// Prefix `\\?\`, uint is the length of the following component
    VerbatimPrefix(uint),
references:- 16
237:         }
238:         fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
239:             if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
--
687:     fn normalize_<S: StrAllocating>(s: S) -> (Option<PathPrefix>, StrBuf) {
688:         // make borrowck happy
--
952: /// Prefix types for Path
954: pub enum PathPrefix {
--
1078: fn prefix_is_verbatim(p: Option<PathPrefix>) -> bool {
1079:     match p {
--
1086: fn prefix_len(p: Option<PathPrefix>) -> uint {
1087:     match p {


libstd/path/windows.rs:1085:1-1085:1 -fn- definition:
fn prefix_len(p: Option<PathPrefix>) -> uint {
    match p {
        None => 0,
references:- 11
225:             // assume prefix is Some(DiskPrefix)
226:             let rest = path.slice_from(prefix_len(prefix));
227:             !rest.is_empty() && rest[0].is_ascii() && is_sep(rest[0] as char)
--
1033:     let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
1034:     let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
1035:     let s_ = s.slice_from(prefix_len(prefix));
--
1039:         return (is_abs, match prefix {
1040:             Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
1041:                                         else { Some(vec![]) }),


libstd/path/windows.rs:875:10-875:10 -fn- definition:
pub fn is_verbatim(path: &Path) -> bool {
    prefix_is_verbatim(path.prefix)
}
references:- 4
839:     fn has_nonsemantic_trailing_slash(&self) -> bool {
840:         is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
841:             self.repr.as_slice()[self.repr.len()-1] == SEP_BYTE


libstd/path/windows.rs:933:10-933:10 -fn- definition:
pub fn is_sep_verbatim(c: char) -> bool {
    c == SEP
}
references:- 5
238:         fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
239:             if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
240:             else { is_sep(u as char) }
--
1032: fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
1033:     let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
1034:     let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
--
1039:         return (is_abs, match prefix {
1040:             Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
1041:                                         else { Some(vec![]) }),


libstd/path/windows.rs:503:8-503:8 -fn- definition:
        fn comp_requires_verbatim(s: &str) -> bool {
            s == "." || s == ".." || s.contains_char(SEP2)
        }
references:- 3
556:                     (Some(_), Some(b)) if !b_verb && b == ".." => return None,
557:                     (Some(a), Some(_)) if a_verb && comp_requires_verbatim(a) => {
558:                         return Some(self.clone())


libstd/path/windows.rs:243:8-243:8 -fn- definition:
        fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) {
            let newpath = Path::normalize__(path, prefix);
            me.repr = match newpath {
references:- 2
284:                     // absolute path, or cwd-relative and self is not same volume
285:                     replace_path(self, path, prefix);
286:                 }
--
295:                         // we have no prefix, so nothing to be relative to
296:                         replace_path(self, path, prefix);
297:                     }


libstd/path/windows.rs:84:19-84:19 -struct- definition:
pub struct Path {
    repr: StrBuf, // assumed to never be empty
    prefix: Option<PathPrefix>,
references:- 39


libstd/path/windows.rs:926:10-926:10 -fn- definition:
pub fn is_sep(c: char) -> bool {
    c == SEP || c == SEP2
}
references:- 6
812:                 } else { self.repr.as_slice() };
813:         let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
814:                           else { is_sep_verbatim });
--
1002:         }
1003:         match parse_two_comps(path, is_sep) {
1004:             Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {
--
1062:     if !changed && !prefix_is_verbatim(prefix) {
1063:         changed = s.find(is_sep).is_some();
1064:     }


libstd/path/windows.rs:33:61-33:61 -NK_AS_STR_TODO- definition:
/// every component in WindowsPath is guaranteed to be Some.
pub type StrComponents<'a> = Map<'a, &'a str, Option<&'a str>,
                                       CharSplits<'a, char>>;
references:- 4
44: pub type Components<'a> = Map<'a, Option<&'a str>, &'a [u8],
45:                                     StrComponents<'a>>;
46: /// Iterator that yields components of a Path in reverse as &[u8]
--
636:     #[deprecated = "replaced by .str_components().rev()"]
637:     pub fn rev_str_components<'a>(&'a self) -> Rev<StrComponents<'a>> {
638:         self.str_components().rev()


libstd/path/windows.rs:1077:1-1077:1 -fn- definition:
fn prefix_is_verbatim(p: Option<PathPrefix>) -> bool {
    match p {
        Some(VerbatimPrefix(_)) | Some(VerbatimUNCPrefix(_,_)) | Some(VerbatimDiskPrefix) => true,
references:- 6
812:                 } else { self.repr.as_slice() };
813:         let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
814:                           else { is_sep_verbatim });
--
876: pub fn is_verbatim(path: &Path) -> bool {
877:     prefix_is_verbatim(path.prefix)
878: }
--
1032: fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool, Option<Vec<&'a str>>) {
1033:     let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
1034:     let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
--
1061:     }
1062:     if !changed && !prefix_is_verbatim(prefix) {
1063:         changed = s.find(is_sep).is_some();


libstd/path/windows.rs:855:10-855:10 -fn- definition:
pub fn is_vol_relative(path: &Path) -> bool {
    path.prefix.is_none() && is_sep_byte(&path.repr.as_slice()[0])
}
references:- 7
471:     fn is_relative(&self) -> bool {
472:         self.prefix.is_none() && !is_vol_relative(self)
473:     }
--
522:             }
523:         } else if is_vol_relative(self) != is_vol_relative(base) {
524:             if is_vol_relative(self) {
525:                 Some(self.clone())


libstd/path/windows.rs:1019:4-1019:4 -fn- definition:
    fn parse_two_comps<'a>(mut path: &'a str, f: |char| -> bool)
                       -> Option<(uint, uint)> {
        let idx_a = match path.find(|x| f(x)) {
references:- 2
978:                 path = path.slice_from(4);
979:                 let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
980:                     Some(x) => x,
--
1002:         }
1003:         match parse_two_comps(path, is_sep) {
1004:             Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {


libstd/path/windows.rs:252:8-252:8 -fn- definition:
        fn append_path(me: &mut Path, path: &str) {
            // appends a path that has no prefix
            // if me is verbatim, we need to pre-normalize the new path
references:- 3
292:                         self.repr.truncate(n);
293:                         append_path(self, path);
294:                     } else {
--
300:                     // relative path
301:                     append_path(self, path);
302:                 }