]> git.proxmox.com Git - rustc.git/blame - src/libstd/path.rs
Imported Upstream version 1.3.0+dfsg1
[rustc.git] / src / libstd / path.rs
CommitLineData
85aaf69f
SL
1// Copyright 2015 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//! Cross-platform path manipulation.
12//!
13//! This module provides two types, `PathBuf` and `Path` (akin to `String` and
14//! `str`), for working with paths abstractly. These types are thin wrappers
15//! around `OsString` and `OsStr` respectively, meaning that they work directly
16//! on strings according to the local platform's path syntax.
17//!
18//! ## Simple usage
19//!
c34b1796 20//! Path manipulation includes both parsing components from slices and building
85aaf69f
SL
21//! new owned paths.
22//!
23//! To parse a path, you can create a `Path` slice from a `str`
24//! slice and start asking questions:
25//!
26//! ```rust
27//! use std::path::Path;
28//!
29//! let path = Path::new("/tmp/foo/bar.txt");
30//! let file = path.file_name();
31//! let extension = path.extension();
32//! let parent_dir = path.parent();
33//! ```
34//!
35//! To build or modify paths, use `PathBuf`:
36//!
37//! ```rust
38//! use std::path::PathBuf;
39//!
c34b1796 40//! let mut path = PathBuf::from("c:\\");
85aaf69f
SL
41//! path.push("windows");
42//! path.push("system32");
43//! path.set_extension("dll");
44//! ```
45//!
46//! ## Path components and normalization
47//!
48//! The path APIs are built around the notion of "components", which roughly
49//! correspond to the substrings between path separators (`/` and, on Windows,
50//! `\`). The APIs for path parsing are largely specified in terms of the path's
51//! components, so it's important to clearly understand how those are determined.
52//!
c34b1796
AL
53//! A path can always be reconstructed into an *equivalent* path by
54//! putting together its components via `push`. Syntactically, the
55//! paths may differ by the normalization described below.
85aaf69f
SL
56//!
57//! ### Component types
58//!
59//! Components come in several types:
60//!
61//! * Normal components are the default: standard references to files or
62//! directories. The path `a/b` has two normal components, `a` and `b`.
63//!
64//! * Current directory components represent the `.` character. For example,
c34b1796 65//! `./a` has a current directory component and a normal component `a`.
85aaf69f
SL
66//!
67//! * The root directory component represents a separator that designates
68//! starting from root. For example, `/a/b` has a root directory component
69//! followed by normal components `a` and `b`.
70//!
c34b1796 71//! On Windows, an additional component type comes into play:
85aaf69f
SL
72//!
73//! * Prefix components, of which there is a large variety. For example, `C:`
74//! and `\\server\share` are prefixes. The path `C:windows` has a prefix
75//! component `C:` and a normal component `windows`; the path `C:\windows` has a
76//! prefix component `C:`, a root directory component, and a normal component
77//! `windows`.
78//!
85aaf69f
SL
79//! ### Normalization
80//!
81//! Aside from splitting on the separator(s), there is a small amount of
82//! "normalization":
83//!
84//! * Repeated separators are ignored: `a/b` and `a//b` both have components `a`
85//! and `b`.
86//!
c34b1796
AL
87//! * Occurrences of `.` are normalized away, *except* if they are at
88//! the beginning of the path (in which case they are often meaningful
89//! in terms of path searching). So, for example, `a/./b`, `a/b/`,
90//! `/a/b/.` and `a/b` all have components `a` and `b`, but `./a/b`
91//! has a leading current directory component.
85aaf69f 92//!
c34b1796
AL
93//! No other normalization takes place by default. In particular,
94//! `a/c` and `a/b/../c` are distinct, to account for the possibility
95//! that `b` is a symbolic link (so its parent isn't `a`). Further
96//! normalization is possible to build on top of the components APIs,
97//! and will be included in this library in the near future.
85aaf69f 98
c34b1796 99#![stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
100
101use core::prelude::*;
102
103use ascii::*;
c34b1796 104use borrow::{Borrow, IntoCow, ToOwned, Cow};
85aaf69f 105use cmp;
9346a6ac 106use iter;
85aaf69f
SL
107use mem;
108use ops::{self, Deref};
c34b1796 109use string::String;
85aaf69f
SL
110use vec::Vec;
111use fmt;
112
9346a6ac 113use ffi::{OsStr, OsString};
85aaf69f
SL
114
115use self::platform::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
116
117////////////////////////////////////////////////////////////////////////////////
118// GENERAL NOTES
119////////////////////////////////////////////////////////////////////////////////
120//
121// Parsing in this module is done by directly transmuting OsStr to [u8] slices,
122// taking advantage of the fact that OsStr always encodes ASCII characters
123// as-is. Eventually, this transmutation should be replaced by direct uses of
124// OsStr APIs for parsing, but it will take a while for those to become
125// available.
126
127////////////////////////////////////////////////////////////////////////////////
128// Platform-specific definitions
129////////////////////////////////////////////////////////////////////////////////
130
131// The following modules give the most basic tools for parsing paths on various
132// platforms. The bulk of the code is devoted to parsing prefixes on Windows.
133
134#[cfg(unix)]
135mod platform {
136 use super::Prefix;
137 use core::prelude::*;
138 use ffi::OsStr;
139
140 #[inline]
141 pub fn is_sep_byte(b: u8) -> bool {
142 b == b'/'
143 }
144
145 #[inline]
146 pub fn is_verbatim_sep(b: u8) -> bool {
147 b == b'/'
148 }
149
150 pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
151 None
152 }
153
154 pub const MAIN_SEP_STR: &'static str = "/";
155 pub const MAIN_SEP: char = '/';
156}
157
158#[cfg(windows)]
159mod platform {
160 use core::prelude::*;
161 use ascii::*;
162
85aaf69f
SL
163 use super::{os_str_as_u8_slice, u8_slice_as_os_str, Prefix};
164 use ffi::OsStr;
165
166 #[inline]
167 pub fn is_sep_byte(b: u8) -> bool {
168 b == b'/' || b == b'\\'
169 }
170
171 #[inline]
172 pub fn is_verbatim_sep(b: u8) -> bool {
173 b == b'\\'
174 }
175
176 pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> {
177 use super::Prefix::*;
178 unsafe {
179 // The unsafety here stems from converting between &OsStr and &[u8]
180 // and back. This is safe to do because (1) we only look at ASCII
181 // contents of the encoding and (2) new &OsStr values are produced
182 // only from ASCII-bounded slices of existing &OsStr values.
183 let mut path = os_str_as_u8_slice(path);
184
185 if path.starts_with(br"\\") {
186 // \\
187 path = &path[2..];
188 if path.starts_with(br"?\") {
189 // \\?\
190 path = &path[2..];
191 if path.starts_with(br"UNC\") {
192 // \\?\UNC\server\share
193 path = &path[4..];
194 let (server, share) = match parse_two_comps(path, is_verbatim_sep) {
195 Some((server, share)) => (u8_slice_as_os_str(server),
196 u8_slice_as_os_str(share)),
197 None => (u8_slice_as_os_str(path),
198 u8_slice_as_os_str(&[])),
199 };
200 return Some(VerbatimUNC(server, share));
201 } else {
202 // \\?\path
c1a9b12d 203 let idx = path.iter().position(|&b| b == b'\\');
85aaf69f
SL
204 if idx == Some(2) && path[1] == b':' {
205 let c = path[0];
206 if c.is_ascii() && (c as char).is_alphabetic() {
207 // \\?\C:\ path
208 return Some(VerbatimDisk(c.to_ascii_uppercase()));
209 }
210 }
211 let slice = &path[.. idx.unwrap_or(path.len())];
212 return Some(Verbatim(u8_slice_as_os_str(slice)));
213 }
214 } else if path.starts_with(b".\\") {
215 // \\.\path
216 path = &path[2..];
c1a9b12d
SL
217 let pos = path.iter().position(|&b| b == b'\\');
218 let slice = &path[..pos.unwrap_or(path.len())];
85aaf69f
SL
219 return Some(DeviceNS(u8_slice_as_os_str(slice)));
220 }
221 match parse_two_comps(path, is_sep_byte) {
9346a6ac 222 Some((server, share)) if !server.is_empty() && !share.is_empty() => {
85aaf69f
SL
223 // \\server\share
224 return Some(UNC(u8_slice_as_os_str(server),
225 u8_slice_as_os_str(share)));
226 }
227 _ => ()
228 }
229 } else if path.len() > 1 && path[1] == b':' {
230 // C:
231 let c = path[0];
232 if c.is_ascii() && (c as char).is_alphabetic() {
233 return Some(Disk(c.to_ascii_uppercase()));
234 }
235 }
236 return None;
237 }
238
239 fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> {
240 let first = match path.iter().position(|x| f(*x)) {
241 None => return None,
242 Some(x) => &path[.. x]
243 };
244 path = &path[(first.len()+1)..];
245 let idx = path.iter().position(|x| f(*x));
246 let second = &path[.. idx.unwrap_or(path.len())];
247 Some((first, second))
248 }
249 }
250
251 pub const MAIN_SEP_STR: &'static str = "\\";
252 pub const MAIN_SEP: char = '\\';
253}
254
255////////////////////////////////////////////////////////////////////////////////
256// Windows Prefixes
257////////////////////////////////////////////////////////////////////////////////
258
259/// Path prefixes (Windows only).
260///
261/// Windows uses a variety of path styles, including references to drive
62682a34 262/// volumes (like `C:`), network shared folders (like `\\server\share`) and
85aaf69f
SL
263/// others. In addition, some path prefixes are "verbatim", in which case
264/// `/` is *not* treated as a separator and essentially no normalization is
265/// performed.
266#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
c34b1796 267#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
268pub enum Prefix<'a> {
269 /// Prefix `\\?\`, together with the given component immediately following it.
c34b1796 270 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
271 Verbatim(&'a OsStr),
272
273 /// Prefix `\\?\UNC\`, with the "server" and "share" components following it.
c34b1796 274 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
275 VerbatimUNC(&'a OsStr, &'a OsStr),
276
277 /// Prefix like `\\?\C:\`, for the given drive letter
c34b1796 278 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
279 VerbatimDisk(u8),
280
281 /// Prefix `\\.\`, together with the given component immediately following it.
c34b1796 282 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
283 DeviceNS(&'a OsStr),
284
285 /// Prefix `\\server\share`, with the given "server" and "share" components.
c34b1796 286 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
287 UNC(&'a OsStr, &'a OsStr),
288
289 /// Prefix `C:` for the given disk drive.
c34b1796 290 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
291 Disk(u8),
292}
293
294impl<'a> Prefix<'a> {
295 #[inline]
296 fn len(&self) -> usize {
297 use self::Prefix::*;
298 fn os_str_len(s: &OsStr) -> usize {
299 os_str_as_u8_slice(s).len()
300 }
301 match *self {
302 Verbatim(x) => 4 + os_str_len(x),
303 VerbatimUNC(x,y) => 8 + os_str_len(x) +
304 if os_str_len(y) > 0 { 1 + os_str_len(y) }
305 else { 0 },
306 VerbatimDisk(_) => 6,
307 UNC(x,y) => 2 + os_str_len(x) +
308 if os_str_len(y) > 0 { 1 + os_str_len(y) }
309 else { 0 },
310 DeviceNS(x) => 4 + os_str_len(x),
311 Disk(_) => 2
312 }
313
314 }
315
62682a34 316 /// Determines if the prefix is verbatim, i.e. begins with `\\?\`.
85aaf69f 317 #[inline]
c34b1796 318 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
319 pub fn is_verbatim(&self) -> bool {
320 use self::Prefix::*;
321 match *self {
322 Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(_, _) => true,
62682a34 323 _ => false,
85aaf69f
SL
324 }
325 }
326
327 #[inline]
328 fn is_drive(&self) -> bool {
329 match *self {
330 Prefix::Disk(_) => true,
331 _ => false,
332 }
333 }
334
335 #[inline]
336 fn has_implicit_root(&self) -> bool {
337 !self.is_drive()
338 }
339}
340
341////////////////////////////////////////////////////////////////////////////////
342// Exposed parsing helpers
343////////////////////////////////////////////////////////////////////////////////
344
9346a6ac 345/// Determines whether the character is one of the permitted path
85aaf69f 346/// separators for the current platform.
c34b1796
AL
347///
348/// # Examples
349///
350/// ```
351/// use std::path;
352///
353/// assert!(path::is_separator('/'));
354/// assert!(!path::is_separator('❤'));
355/// ```
356#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
357pub fn is_separator(c: char) -> bool {
358 use ascii::*;
359 c.is_ascii() && is_sep_byte(c as u8)
360}
361
d9579d0f 362/// The primary separator for the current platform
c34b1796 363#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
364pub const MAIN_SEPARATOR: char = platform::MAIN_SEP;
365
366////////////////////////////////////////////////////////////////////////////////
367// Misc helpers
368////////////////////////////////////////////////////////////////////////////////
369
370// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
371// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
372// `iter` after having exhausted `prefix`.
373fn iter_after<A, I, J>(mut iter: I, mut prefix: J) -> Option<I> where
374 I: Iterator<Item=A> + Clone, J: Iterator<Item=A>, A: PartialEq
375{
376 loop {
377 let mut iter_next = iter.clone();
378 match (iter_next.next(), prefix.next()) {
379 (Some(x), Some(y)) => {
380 if x != y { return None }
381 }
382 (Some(_), None) => return Some(iter),
383 (None, None) => return Some(iter),
384 (None, Some(_)) => return None,
385 }
386 iter = iter_next;
387 }
388}
389
390// See note at the top of this module to understand why these are used:
391fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
392 unsafe { mem::transmute(s) }
393}
394unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
395 mem::transmute(s)
396}
397
398////////////////////////////////////////////////////////////////////////////////
c34b1796 399// Cross-platform, iterator-independent parsing
85aaf69f
SL
400////////////////////////////////////////////////////////////////////////////////
401
85aaf69f
SL
402/// Says whether the first byte after the prefix is a separator.
403fn has_physical_root(s: &[u8], prefix: Option<Prefix>) -> bool {
404 let path = if let Some(p) = prefix { &s[p.len()..] } else { s };
9346a6ac 405 !path.is_empty() && is_sep_byte(path[0])
85aaf69f
SL
406}
407
85aaf69f
SL
408// basic workhorse for splitting stem and extension
409#[allow(unused_unsafe)] // FIXME
410fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
411 unsafe {
412 if os_str_as_u8_slice(file) == b".." { return (Some(file), None) }
413
414 // The unsafety here stems from converting between &OsStr and &[u8]
415 // and back. This is safe to do because (1) we only look at ASCII
416 // contents of the encoding and (2) new &OsStr values are produced
417 // only from ASCII-bounded slices of existing &OsStr values.
418
c34b1796 419 let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
85aaf69f
SL
420 let after = iter.next();
421 let before = iter.next();
422 if before == Some(b"") {
423 (Some(file), None)
424 } else {
425 (before.map(|s| u8_slice_as_os_str(s)),
426 after.map(|s| u8_slice_as_os_str(s)))
427 }
428 }
429}
430
431////////////////////////////////////////////////////////////////////////////////
432// The core iterators
433////////////////////////////////////////////////////////////////////////////////
434
435/// Component parsing works by a double-ended state machine; the cursors at the
436/// front and back of the path each keep track of what parts of the path have
437/// been consumed so far.
438///
c34b1796
AL
439/// Going front to back, a path is made up of a prefix, a starting
440/// directory component, and a body (of normal components)
85aaf69f
SL
441#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
442enum State {
443 Prefix = 0, // c:
c34b1796 444 StartDir = 1, // / or . or nothing
85aaf69f 445 Body = 2, // foo/bar/baz
c34b1796
AL
446 Done = 3,
447}
448
449/// A Windows path prefix, e.g. `C:` or `\server\share`.
450///
451/// Does not occur on Unix.
452#[stable(feature = "rust1", since = "1.0.0")]
453#[derive(Copy, Clone, Eq, Hash, Debug)]
454pub struct PrefixComponent<'a> {
455 /// The prefix as an unparsed `OsStr` slice.
456 raw: &'a OsStr,
457
458 /// The parsed prefix data.
459 parsed: Prefix<'a>,
460}
461
462impl<'a> PrefixComponent<'a> {
463 /// The parsed prefix data.
464 #[stable(feature = "rust1", since = "1.0.0")]
465 pub fn kind(&self) -> Prefix<'a> {
466 self.parsed
467 }
468
469 /// The raw `OsStr` slice for this prefix.
470 #[stable(feature = "rust1", since = "1.0.0")]
471 pub fn as_os_str(&self) -> &'a OsStr {
472 self.raw
473 }
474}
475
476#[stable(feature = "rust1", since = "1.0.0")]
477impl<'a> cmp::PartialEq for PrefixComponent<'a> {
478 fn eq(&self, other: &PrefixComponent<'a>) -> bool {
479 cmp::PartialEq::eq(&self.parsed, &other.parsed)
480 }
481}
482
483#[stable(feature = "rust1", since = "1.0.0")]
484impl<'a> cmp::PartialOrd for PrefixComponent<'a> {
485 fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> {
486 cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed)
487 }
488}
489
490#[stable(feature = "rust1", since = "1.0.0")]
491impl<'a> cmp::Ord for PrefixComponent<'a> {
492 fn cmp(&self, other: &PrefixComponent<'a>) -> cmp::Ordering {
493 cmp::Ord::cmp(&self.parsed, &other.parsed)
494 }
85aaf69f
SL
495}
496
497/// A single component of a path.
498///
499/// See the module documentation for an in-depth explanation of components and
500/// their role in the API.
501#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
c34b1796 502#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
503pub enum Component<'a> {
504 /// A Windows path prefix, e.g. `C:` or `\server\share`.
505 ///
506 /// Does not occur on Unix.
c34b1796
AL
507 #[stable(feature = "rust1", since = "1.0.0")]
508 Prefix(PrefixComponent<'a>),
85aaf69f
SL
509
510 /// The root directory component, appears after any prefix and before anything else
c34b1796 511 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
512 RootDir,
513
514 /// A reference to the current directory, i.e. `.`
c34b1796 515 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
516 CurDir,
517
518 /// A reference to the parent directory, i.e. `..`
c34b1796 519 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
520 ParentDir,
521
522 /// A normal component, i.e. `a` and `b` in `a/b`
c34b1796 523 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
524 Normal(&'a OsStr),
525}
526
527impl<'a> Component<'a> {
9346a6ac 528 /// Extracts the underlying `OsStr` slice
c34b1796 529 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
530 pub fn as_os_str(self) -> &'a OsStr {
531 match self {
c34b1796
AL
532 Component::Prefix(p) => p.as_os_str(),
533 Component::RootDir => OsStr::new(MAIN_SEP_STR),
534 Component::CurDir => OsStr::new("."),
535 Component::ParentDir => OsStr::new(".."),
85aaf69f
SL
536 Component::Normal(path) => path,
537 }
538 }
539}
540
c34b1796
AL
541#[stable(feature = "rust1", since = "1.0.0")]
542impl<'a> AsRef<OsStr> for Component<'a> {
543 fn as_ref(&self) -> &OsStr {
544 self.as_os_str()
545 }
546}
547
85aaf69f
SL
548/// The core iterator giving the components of a path.
549///
550/// See the module documentation for an in-depth explanation of components and
551/// their role in the API.
c34b1796
AL
552///
553/// # Examples
554///
555/// ```
556/// use std::path::Path;
557///
558/// let path = Path::new("/tmp/foo/bar.txt");
559///
560/// for component in path.components() {
561/// println!("{:?}", component);
562/// }
563/// ```
85aaf69f 564#[derive(Clone)]
c34b1796 565#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
566pub struct Components<'a> {
567 // The path left to parse components from
568 path: &'a [u8],
569
570 // The prefix as it was originally parsed, if any
571 prefix: Option<Prefix<'a>>,
572
573 // true if path *physically* has a root separator; for most Windows
574 // prefixes, it may have a "logical" rootseparator for the purposes of
575 // normalization, e.g. \\server\share == \\server\share\.
576 has_physical_root: bool,
577
578 // The iterator is double-ended, and these two states keep track of what has
579 // been produced from either end
580 front: State,
581 back: State,
582}
583
584/// An iterator over the components of a path, as `OsStr` slices.
585#[derive(Clone)]
c34b1796 586#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
587pub struct Iter<'a> {
588 inner: Components<'a>
589}
590
591impl<'a> Components<'a> {
592 // how long is the prefix, if any?
593 #[inline]
594 fn prefix_len(&self) -> usize {
595 self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
596 }
597
598 #[inline]
599 fn prefix_verbatim(&self) -> bool {
600 self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
601 }
602
603 /// how much of the prefix is left from the point of view of iteration?
604 #[inline]
605 fn prefix_remaining(&self) -> usize {
606 if self.front == State::Prefix { self.prefix_len() }
607 else { 0 }
608 }
609
c34b1796
AL
610 // Given the iteration so far, how much of the pre-State::Body path is left?
611 #[inline]
612 fn len_before_body(&self) -> usize {
613 let root = if self.front <= State::StartDir && self.has_physical_root { 1 } else { 0 };
614 let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() { 1 } else { 0 };
615 self.prefix_remaining() + root + cur_dir
85aaf69f
SL
616 }
617
618 // is the iteration complete?
619 #[inline]
620 fn finished(&self) -> bool {
621 self.front == State::Done || self.back == State::Done || self.front > self.back
622 }
623
624 #[inline]
625 fn is_sep_byte(&self, b: u8) -> bool {
626 if self.prefix_verbatim() {
627 is_verbatim_sep(b)
628 } else {
629 is_sep_byte(b)
630 }
631 }
632
9346a6ac 633 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
c34b1796
AL
634 ///
635 /// # Examples
636 ///
637 /// ```
638 /// use std::path::Path;
639 ///
640 /// let path = Path::new("/tmp/foo/bar.txt");
641 ///
642 /// println!("{:?}", path.components().as_path());
643 /// ```
644 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
645 pub fn as_path(&self) -> &'a Path {
646 let mut comps = self.clone();
647 if comps.front == State::Body { comps.trim_left(); }
648 if comps.back == State::Body { comps.trim_right(); }
c34b1796 649 unsafe { Path::from_u8_slice(comps.path) }
85aaf69f
SL
650 }
651
652 /// Is the *original* path rooted?
653 fn has_root(&self) -> bool {
654 if self.has_physical_root { return true }
655 if let Some(p) = self.prefix {
656 if p.has_implicit_root() { return true }
657 }
658 false
659 }
660
c34b1796
AL
661 /// Should the normalized path include a leading . ?
662 fn include_cur_dir(&self) -> bool {
663 if self.has_root() { return false }
664 let mut iter = self.path[self.prefix_len()..].iter();
665 match (iter.next(), iter.next()) {
666 (Some(&b'.'), None) => true,
667 (Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
668 _ => false
669 }
670 }
671
672 // parse a given byte sequence into the corresponding path component
673 fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
674 match comp {
675 b"." if self.prefix_verbatim() => Some(Component::CurDir),
676 b"." => None, // . components are normalized away, except at
677 // the beginning of a path, which is treated
678 // separately via `include_cur_dir`
679 b".." => Some(Component::ParentDir),
680 b"" => None,
681 _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) }))
682 }
683 }
684
85aaf69f
SL
685 // parse a component from the left, saying how many bytes to consume to
686 // remove the component
687 fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
688 debug_assert!(self.front == State::Body);
689 let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) {
690 None => (0, self.path),
691 Some(i) => (1, &self.path[.. i]),
692 };
c34b1796 693 (comp.len() + extra, self.parse_single_component(comp))
85aaf69f
SL
694 }
695
696 // parse a component from the right, saying how many bytes to consume to
697 // remove the component
698 fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
699 debug_assert!(self.back == State::Body);
c34b1796 700 let start = self.len_before_body();
85aaf69f
SL
701 let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) {
702 None => (0, &self.path[start ..]),
703 Some(i) => (1, &self.path[start + i + 1 ..]),
704 };
c34b1796 705 (comp.len() + extra, self.parse_single_component(comp))
85aaf69f
SL
706 }
707
9346a6ac 708 // trim away repeated separators (i.e. empty components) on the left
85aaf69f
SL
709 fn trim_left(&mut self) {
710 while !self.path.is_empty() {
711 let (size, comp) = self.parse_next_component();
712 if comp.is_some() {
713 return;
714 } else {
715 self.path = &self.path[size ..];
716 }
717 }
718 }
719
9346a6ac 720 // trim away repeated separators (i.e. empty components) on the right
85aaf69f 721 fn trim_right(&mut self) {
c34b1796 722 while self.path.len() > self.len_before_body() {
85aaf69f
SL
723 let (size, comp) = self.parse_next_component_back();
724 if comp.is_some() {
725 return;
726 } else {
727 self.path = &self.path[.. self.path.len() - size];
728 }
729 }
730 }
731
732 /// Examine the next component without consuming it.
c34b1796 733 #[unstable(feature = "path_components_peek")]
85aaf69f
SL
734 pub fn peek(&self) -> Option<Component<'a>> {
735 self.clone().next()
736 }
737}
738
c34b1796
AL
739#[stable(feature = "rust1", since = "1.0.0")]
740impl<'a> AsRef<Path> for Components<'a> {
741 fn as_ref(&self) -> &Path {
742 self.as_path()
743 }
744}
745
746#[stable(feature = "rust1", since = "1.0.0")]
747impl<'a> AsRef<OsStr> for Components<'a> {
748 fn as_ref(&self) -> &OsStr {
749 self.as_path().as_os_str()
750 }
751}
752
85aaf69f 753impl<'a> Iter<'a> {
9346a6ac 754 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
c34b1796 755 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
756 pub fn as_path(&self) -> &'a Path {
757 self.inner.as_path()
758 }
759}
760
c34b1796
AL
761#[stable(feature = "rust1", since = "1.0.0")]
762impl<'a> AsRef<Path> for Iter<'a> {
763 fn as_ref(&self) -> &Path {
764 self.as_path()
765 }
766}
767
768#[stable(feature = "rust1", since = "1.0.0")]
769impl<'a> AsRef<OsStr> for Iter<'a> {
770 fn as_ref(&self) -> &OsStr {
771 self.as_path().as_os_str()
772 }
773}
774
775#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
776impl<'a> Iterator for Iter<'a> {
777 type Item = &'a OsStr;
778
779 fn next(&mut self) -> Option<&'a OsStr> {
780 self.inner.next().map(Component::as_os_str)
781 }
782}
783
c34b1796 784#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
785impl<'a> DoubleEndedIterator for Iter<'a> {
786 fn next_back(&mut self) -> Option<&'a OsStr> {
787 self.inner.next_back().map(Component::as_os_str)
788 }
789}
790
c34b1796 791#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
792impl<'a> Iterator for Components<'a> {
793 type Item = Component<'a>;
794
795 fn next(&mut self) -> Option<Component<'a>> {
796 while !self.finished() {
797 match self.front {
798 State::Prefix if self.prefix_len() > 0 => {
c34b1796 799 self.front = State::StartDir;
85aaf69f
SL
800 debug_assert!(self.prefix_len() <= self.path.len());
801 let raw = &self.path[.. self.prefix_len()];
802 self.path = &self.path[self.prefix_len() .. ];
c34b1796 803 return Some(Component::Prefix(PrefixComponent {
85aaf69f
SL
804 raw: unsafe { u8_slice_as_os_str(raw) },
805 parsed: self.prefix.unwrap()
c34b1796 806 }))
85aaf69f
SL
807 }
808 State::Prefix => {
c34b1796 809 self.front = State::StartDir;
85aaf69f 810 }
c34b1796 811 State::StartDir => {
85aaf69f
SL
812 self.front = State::Body;
813 if self.has_physical_root {
9346a6ac 814 debug_assert!(!self.path.is_empty());
85aaf69f
SL
815 self.path = &self.path[1..];
816 return Some(Component::RootDir)
817 } else if let Some(p) = self.prefix {
818 if p.has_implicit_root() && !p.is_verbatim() {
819 return Some(Component::RootDir)
820 }
c34b1796 821 } else if self.include_cur_dir() {
9346a6ac 822 debug_assert!(!self.path.is_empty());
c34b1796
AL
823 self.path = &self.path[1..];
824 return Some(Component::CurDir)
85aaf69f
SL
825 }
826 }
827 State::Body if !self.path.is_empty() => {
828 let (size, comp) = self.parse_next_component();
829 self.path = &self.path[size ..];
830 if comp.is_some() { return comp }
831 }
832 State::Body => {
85aaf69f 833 self.front = State::Done;
85aaf69f
SL
834 }
835 State::Done => unreachable!()
836 }
837 }
838 None
839 }
840}
841
c34b1796 842#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
843impl<'a> DoubleEndedIterator for Components<'a> {
844 fn next_back(&mut self) -> Option<Component<'a>> {
845 while !self.finished() {
846 match self.back {
c34b1796 847 State::Body if self.path.len() > self.len_before_body() => {
85aaf69f
SL
848 let (size, comp) = self.parse_next_component_back();
849 self.path = &self.path[.. self.path.len() - size];
850 if comp.is_some() { return comp }
851 }
852 State::Body => {
c34b1796 853 self.back = State::StartDir;
85aaf69f 854 }
c34b1796 855 State::StartDir => {
85aaf69f
SL
856 self.back = State::Prefix;
857 if self.has_physical_root {
858 self.path = &self.path[.. self.path.len() - 1];
859 return Some(Component::RootDir)
860 } else if let Some(p) = self.prefix {
861 if p.has_implicit_root() && !p.is_verbatim() {
862 return Some(Component::RootDir)
863 }
c34b1796
AL
864 } else if self.include_cur_dir() {
865 self.path = &self.path[.. self.path.len() - 1];
866 return Some(Component::CurDir)
85aaf69f
SL
867 }
868 }
869 State::Prefix if self.prefix_len() > 0 => {
870 self.back = State::Done;
c34b1796 871 return Some(Component::Prefix(PrefixComponent {
85aaf69f
SL
872 raw: unsafe { u8_slice_as_os_str(self.path) },
873 parsed: self.prefix.unwrap()
c34b1796 874 }))
85aaf69f
SL
875 }
876 State::Prefix => {
877 self.back = State::Done;
878 return None
879 }
880 State::Done => unreachable!()
881 }
882 }
883 None
884 }
885}
886
c34b1796 887#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
888impl<'a> cmp::PartialEq for Components<'a> {
889 fn eq(&self, other: &Components<'a>) -> bool {
890 iter::order::eq(self.clone(), other.clone())
891 }
892}
893
c34b1796 894#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
895impl<'a> cmp::Eq for Components<'a> {}
896
c34b1796 897#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
898impl<'a> cmp::PartialOrd for Components<'a> {
899 fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
900 iter::order::partial_cmp(self.clone(), other.clone())
901 }
902}
903
c34b1796 904#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
905impl<'a> cmp::Ord for Components<'a> {
906 fn cmp(&self, other: &Components<'a>) -> cmp::Ordering {
907 iter::order::cmp(self.clone(), other.clone())
908 }
909}
910
911////////////////////////////////////////////////////////////////////////////////
912// Basic types and traits
913////////////////////////////////////////////////////////////////////////////////
914
915/// An owned, mutable path (akin to `String`).
916///
917/// This type provides methods like `push` and `set_extension` that mutate the
918/// path in place. It also implements `Deref` to `Path`, meaning that all
919/// methods on `Path` slices are available on `PathBuf` values as well.
920///
921/// More details about the overall approach can be found in
922/// the module documentation.
923///
c34b1796 924/// # Examples
85aaf69f 925///
c34b1796 926/// ```
85aaf69f
SL
927/// use std::path::PathBuf;
928///
c34b1796 929/// let mut path = PathBuf::from("c:\\");
85aaf69f
SL
930/// path.push("windows");
931/// path.push("system32");
932/// path.set_extension("dll");
933/// ```
934#[derive(Clone, Hash)]
c34b1796 935#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
936pub struct PathBuf {
937 inner: OsString
938}
939
940impl PathBuf {
941 fn as_mut_vec(&mut self) -> &mut Vec<u8> {
942 unsafe { mem::transmute(self) }
943 }
944
9346a6ac 945 /// Allocates an empty `PathBuf`.
c34b1796
AL
946 #[stable(feature = "rust1", since = "1.0.0")]
947 pub fn new() -> PathBuf {
948 PathBuf { inner: OsString::new() }
949 }
950
9346a6ac 951 /// Coerces to a `Path` slice.
c34b1796
AL
952 #[stable(feature = "rust1", since = "1.0.0")]
953 pub fn as_path(&self) -> &Path {
954 self
85aaf69f
SL
955 }
956
9346a6ac 957 /// Extends `self` with `path`.
85aaf69f
SL
958 ///
959 /// If `path` is absolute, it replaces the current path.
960 ///
961 /// On Windows:
962 ///
963 /// * if `path` has a root but no prefix (e.g. `\windows`), it
964 /// replaces everything except for the prefix (if any) of `self`.
965 /// * if `path` has a prefix but no root, it replaces `self.
c34b1796
AL
966 #[stable(feature = "rust1", since = "1.0.0")]
967 pub fn push<P: AsRef<Path>>(&mut self, path: P) {
968 let path = path.as_ref();
969
85aaf69f
SL
970 // in general, a separator is needed if the rightmost byte is not a separator
971 let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
972
973 // in the special case of `C:` on Windows, do *not* add a separator
974 {
975 let comps = self.components();
976 if comps.prefix_len() > 0 &&
977 comps.prefix_len() == comps.path.len() &&
978 comps.prefix.unwrap().is_drive()
979 {
980 need_sep = false
981 }
982 }
983
85aaf69f
SL
984 // absolute `path` replaces `self`
985 if path.is_absolute() || path.prefix().is_some() {
986 self.as_mut_vec().truncate(0);
987
988 // `path` has a root but no prefix, e.g. `\windows` (Windows only)
989 } else if path.has_root() {
990 let prefix_len = self.components().prefix_remaining();
991 self.as_mut_vec().truncate(prefix_len);
992
993 // `path` is a pure relative path
994 } else if need_sep {
c34b1796 995 self.inner.push(MAIN_SEP_STR);
85aaf69f
SL
996 }
997
c34b1796 998 self.inner.push(path);
85aaf69f
SL
999 }
1000
1001 /// Truncate `self` to `self.parent()`.
1002 ///
c34b1796 1003 /// Returns false and does nothing if `self.file_name()` is `None`.
85aaf69f 1004 /// Otherwise, returns `true`.
c34b1796 1005 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1006 pub fn pop(&mut self) -> bool {
1007 match self.parent().map(|p| p.as_u8_slice().len()) {
1008 Some(len) => {
1009 self.as_mut_vec().truncate(len);
1010 true
1011 }
1012 None => false
1013 }
1014 }
1015
1016 /// Updates `self.file_name()` to `file_name`.
1017 ///
1018 /// If `self.file_name()` was `None`, this is equivalent to pushing
1019 /// `file_name`.
1020 ///
1021 /// # Examples
1022 ///
c34b1796
AL
1023 /// ```
1024 /// use std::path::PathBuf;
85aaf69f 1025 ///
c34b1796 1026 /// let mut buf = PathBuf::from("/");
85aaf69f
SL
1027 /// assert!(buf.file_name() == None);
1028 /// buf.set_file_name("bar");
c34b1796 1029 /// assert!(buf == PathBuf::from("/bar"));
85aaf69f
SL
1030 /// assert!(buf.file_name().is_some());
1031 /// buf.set_file_name("baz.txt");
c34b1796 1032 /// assert!(buf == PathBuf::from("/baz.txt"));
85aaf69f 1033 /// ```
c34b1796
AL
1034 #[stable(feature = "rust1", since = "1.0.0")]
1035 pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
1036 if self.file_name().is_some() {
1037 let popped = self.pop();
1038 debug_assert!(popped);
85aaf69f 1039 }
c34b1796 1040 self.push(file_name.as_ref());
85aaf69f
SL
1041 }
1042
1043 /// Updates `self.extension()` to `extension`.
1044 ///
1045 /// If `self.file_name()` is `None`, does nothing and returns `false`.
1046 ///
1047 /// Otherwise, returns `true`; if `self.extension()` is `None`, the extension
1048 /// is added; otherwise it is replaced.
c34b1796
AL
1049 #[stable(feature = "rust1", since = "1.0.0")]
1050 pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
85aaf69f
SL
1051 if self.file_name().is_none() { return false; }
1052
1053 let mut stem = match self.file_stem() {
1054 Some(stem) => stem.to_os_string(),
c34b1796 1055 None => OsString::new(),
85aaf69f
SL
1056 };
1057
c34b1796 1058 let extension = extension.as_ref();
9346a6ac 1059 if !os_str_as_u8_slice(extension).is_empty() {
c34b1796
AL
1060 stem.push(".");
1061 stem.push(extension);
85aaf69f
SL
1062 }
1063 self.set_file_name(&stem);
1064
1065 true
1066 }
1067
9346a6ac 1068 /// Consumes the `PathBuf`, yielding its internal `OsString` storage.
c34b1796 1069 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1070 pub fn into_os_string(self) -> OsString {
1071 self.inner
1072 }
1073}
1074
c34b1796
AL
1075#[stable(feature = "rust1", since = "1.0.0")]
1076impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf {
1077 fn from(s: &'a T) -> PathBuf {
1078 PathBuf::from(s.as_ref().to_os_string())
1079 }
1080}
1081
1082#[stable(feature = "rust1", since = "1.0.0")]
1083impl From<OsString> for PathBuf {
1084 fn from(s: OsString) -> PathBuf {
1085 PathBuf { inner: s }
1086 }
1087}
1088
1089#[stable(feature = "rust1", since = "1.0.0")]
1090impl From<String> for PathBuf {
1091 fn from(s: String) -> PathBuf {
1092 PathBuf::from(OsString::from(s))
1093 }
1094}
1095
1096#[stable(feature = "rust1", since = "1.0.0")]
1097impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
1098 fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
1099 let mut buf = PathBuf::new();
85aaf69f
SL
1100 buf.extend(iter);
1101 buf
1102 }
1103}
1104
c34b1796
AL
1105#[stable(feature = "rust1", since = "1.0.0")]
1106impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
1107 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
85aaf69f
SL
1108 for p in iter {
1109 self.push(p)
1110 }
1111 }
1112}
1113
c34b1796 1114#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1115impl fmt::Debug for PathBuf {
1116 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1117 fmt::Debug::fmt(&**self, formatter)
1118 }
1119}
1120
c34b1796 1121#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1122impl ops::Deref for PathBuf {
1123 type Target = Path;
1124
1125 fn deref(&self) -> &Path {
1126 unsafe { mem::transmute(&self.inner[..]) }
1127 }
1128}
1129
c34b1796 1130#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1131impl Borrow<Path> for PathBuf {
1132 fn borrow(&self) -> &Path {
1133 self.deref()
1134 }
1135}
1136
c34b1796
AL
1137#[stable(feature = "rust1", since = "1.0.0")]
1138impl IntoCow<'static, Path> for PathBuf {
1139 fn into_cow(self) -> Cow<'static, Path> {
1140 Cow::Owned(self)
1141 }
1142}
1143
1144#[stable(feature = "rust1", since = "1.0.0")]
1145impl<'a> IntoCow<'a, Path> for &'a Path {
1146 fn into_cow(self) -> Cow<'a, Path> {
1147 Cow::Borrowed(self)
1148 }
1149}
1150
1151#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1152impl ToOwned for Path {
1153 type Owned = PathBuf;
1154 fn to_owned(&self) -> PathBuf { self.to_path_buf() }
1155}
1156
c34b1796 1157#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1158impl cmp::PartialEq for PathBuf {
1159 fn eq(&self, other: &PathBuf) -> bool {
1160 self.components() == other.components()
1161 }
1162}
1163
c34b1796 1164#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1165impl cmp::Eq for PathBuf {}
1166
c34b1796 1167#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1168impl cmp::PartialOrd for PathBuf {
1169 fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
1170 self.components().partial_cmp(&other.components())
1171 }
1172}
1173
c34b1796 1174#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1175impl cmp::Ord for PathBuf {
1176 fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
1177 self.components().cmp(&other.components())
1178 }
1179}
1180
c34b1796
AL
1181#[stable(feature = "rust1", since = "1.0.0")]
1182impl AsRef<OsStr> for PathBuf {
1183 fn as_ref(&self) -> &OsStr {
1184 &self.inner[..]
1185 }
1186}
1187
c34b1796
AL
1188#[stable(feature = "rust1", since = "1.0.0")]
1189impl Into<OsString> for PathBuf {
1190 fn into(self) -> OsString {
1191 self.inner
1192 }
1193}
1194
85aaf69f
SL
1195/// A slice of a path (akin to `str`).
1196///
1197/// This type supports a number of operations for inspecting a path, including
1198/// breaking the path into its components (separated by `/` or `\`, depending on
1199/// the platform), extracting the file name, determining whether the path is
1200/// absolute, and so on. More details about the overall approach can be found in
1201/// the module documentation.
1202///
d9579d0f 1203/// This is an *unsized* type, meaning that it must always be used behind a
85aaf69f
SL
1204/// pointer like `&` or `Box`.
1205///
c34b1796 1206/// # Examples
85aaf69f 1207///
c34b1796 1208/// ```
85aaf69f
SL
1209/// use std::path::Path;
1210///
1211/// let path = Path::new("/tmp/foo/bar.txt");
1212/// let file = path.file_name();
1213/// let extension = path.extension();
1214/// let parent_dir = path.parent();
1215/// ```
1216///
1217#[derive(Hash)]
c34b1796 1218#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1219pub struct Path {
1220 inner: OsStr
1221}
1222
1223impl Path {
1224 // The following (private!) function allows construction of a path from a u8
1225 // slice, which is only safe when it is known to follow the OsStr encoding.
1226 unsafe fn from_u8_slice(s: &[u8]) -> &Path {
1227 mem::transmute(s)
1228 }
1229 // The following (private!) function reveals the byte encoding used for OsStr.
1230 fn as_u8_slice(&self) -> &[u8] {
1231 unsafe { mem::transmute(self) }
1232 }
1233
1234 /// Directly wrap a string slice as a `Path` slice.
1235 ///
1236 /// This is a cost-free conversion.
c34b1796
AL
1237 ///
1238 /// # Examples
1239 ///
1240 /// ```
1241 /// use std::path::Path;
1242 ///
1243 /// Path::new("foo.txt");
1244 /// ```
bd371182
AL
1245 ///
1246 /// You can create `Path`s from `String`s, or even other `Path`s:
1247 ///
1248 /// ```
1249 /// use std::path::Path;
1250 ///
62682a34
SL
1251 /// let string = String::from("foo.txt");
1252 /// let from_string = Path::new(&string);
1253 /// let from_path = Path::new(&from_string);
1254 /// assert_eq!(from_string, from_path);
bd371182 1255 /// ```
c34b1796
AL
1256 #[stable(feature = "rust1", since = "1.0.0")]
1257 pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
1258 unsafe { mem::transmute(s.as_ref()) }
1259 }
1260
9346a6ac 1261 /// Yields the underlying `OsStr` slice.
c34b1796
AL
1262 ///
1263 /// # Examples
1264 ///
1265 /// ```
1266 /// use std::path::Path;
1267 ///
1268 /// let os_str = Path::new("foo.txt").as_os_str();
62682a34 1269 /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
c34b1796
AL
1270 /// ```
1271 #[stable(feature = "rust1", since = "1.0.0")]
1272 pub fn as_os_str(&self) -> &OsStr {
1273 &self.inner
85aaf69f
SL
1274 }
1275
9346a6ac 1276 /// Yields a `&str` slice if the `Path` is valid unicode.
85aaf69f
SL
1277 ///
1278 /// This conversion may entail doing a check for UTF-8 validity.
c34b1796
AL
1279 ///
1280 /// # Examples
1281 ///
1282 /// ```
1283 /// use std::path::Path;
1284 ///
1285 /// let path_str = Path::new("foo.txt").to_str();
62682a34 1286 //// assert_eq!(path_str, Some("foo.txt"));
c34b1796
AL
1287 /// ```
1288 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1289 pub fn to_str(&self) -> Option<&str> {
1290 self.inner.to_str()
1291 }
1292
9346a6ac 1293 /// Converts a `Path` to a `Cow<str>`.
85aaf69f
SL
1294 ///
1295 /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
c34b1796
AL
1296 ///
1297 /// # Examples
1298 ///
1299 /// ```
1300 /// use std::path::Path;
1301 ///
1302 /// let path_str = Path::new("foo.txt").to_string_lossy();
62682a34 1303 /// assert_eq!(path_str, "foo.txt");
c34b1796
AL
1304 /// ```
1305 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1306 pub fn to_string_lossy(&self) -> Cow<str> {
1307 self.inner.to_string_lossy()
1308 }
1309
9346a6ac 1310 /// Converts a `Path` to an owned `PathBuf`.
c34b1796
AL
1311 ///
1312 /// # Examples
1313 ///
1314 /// ```
1315 /// use std::path::Path;
1316 ///
62682a34
SL
1317 /// let path_buf = Path::new("foo.txt").to_path_buf();
1318 /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
c34b1796
AL
1319 /// ```
1320 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1321 pub fn to_path_buf(&self) -> PathBuf {
c34b1796 1322 PathBuf::from(self.inner.to_os_string())
85aaf69f
SL
1323 }
1324
1325 /// A path is *absolute* if it is independent of the current directory.
1326 ///
1327 /// * On Unix, a path is absolute if it starts with the root, so
1328 /// `is_absolute` and `has_root` are equivalent.
1329 ///
1330 /// * On Windows, a path is absolute if it has a prefix and starts with the
1331 /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not. In
1332 /// other words, `path.is_absolute() == path.prefix().is_some() && path.has_root()`.
c34b1796
AL
1333 ///
1334 /// # Examples
1335 ///
1336 /// ```
1337 /// use std::path::Path;
1338 ///
62682a34 1339 /// assert!(!Path::new("foo.txt").is_absolute());
c34b1796
AL
1340 /// ```
1341 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1342 pub fn is_absolute(&self) -> bool {
1343 self.has_root() &&
1344 (cfg!(unix) || self.prefix().is_some())
1345 }
1346
1347 /// A path is *relative* if it is not absolute.
c34b1796
AL
1348 ///
1349 /// # Examples
1350 ///
1351 /// ```
1352 /// use std::path::Path;
1353 ///
1354 /// assert!(Path::new("foo.txt").is_relative());
1355 /// ```
1356 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1357 pub fn is_relative(&self) -> bool {
1358 !self.is_absolute()
1359 }
1360
1361 /// Returns the *prefix* of a path, if any.
1362 ///
1363 /// Prefixes are relevant only for Windows paths, and consist of volumes
1364 /// like `C:`, UNC prefixes like `\\server`, and others described in more
1365 /// detail in `std::os::windows::PathExt`.
c34b1796
AL
1366 #[unstable(feature = "path_prefix", reason = "uncertain whether to expose this convenience")]
1367 pub fn prefix(&self) -> Option<Prefix> {
1368 self.components().prefix
85aaf69f
SL
1369 }
1370
1371 /// A path has a root if the body of the path begins with the directory separator.
1372 ///
1373 /// * On Unix, a path has a root if it begins with `/`.
1374 ///
1375 /// * On Windows, a path has a root if it:
1376 /// * has no prefix and begins with a separator, e.g. `\\windows`
1377 /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows`
1378 /// * has any non-disk prefix, e.g. `\\server\share`
c34b1796
AL
1379 ///
1380 /// # Examples
1381 ///
1382 /// ```
1383 /// use std::path::Path;
1384 ///
1385 /// assert!(Path::new("/etc/passwd").has_root());
1386 /// ```
1387 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1388 pub fn has_root(&self) -> bool {
1389 self.components().has_root()
1390 }
1391
c34b1796 1392 /// The path without its final component, if any.
85aaf69f 1393 ///
c34b1796 1394 /// Returns `None` if the path terminates in a root or prefix.
85aaf69f
SL
1395 ///
1396 /// # Examples
1397 ///
c34b1796 1398 /// ```
85aaf69f
SL
1399 /// use std::path::Path;
1400 ///
1401 /// let path = Path::new("/foo/bar");
62682a34
SL
1402 /// let parent = path.parent().unwrap();
1403 /// assert_eq!(parent, Path::new("/foo"));
c34b1796 1404 ///
62682a34
SL
1405 /// let grand_parent = parent.parent().unwrap();
1406 /// assert_eq!(grand_parent, Path::new("/"));
1407 /// assert_eq!(grand_parent.parent(), None);
85aaf69f 1408 /// ```
c34b1796 1409 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1410 pub fn parent(&self) -> Option<&Path> {
1411 let mut comps = self.components();
1412 let comp = comps.next_back();
c34b1796
AL
1413 comp.and_then(|p| match p {
1414 Component::Normal(_) |
1415 Component::CurDir |
1416 Component::ParentDir => Some(comps.as_path()),
1417 _ => None
1418 })
85aaf69f
SL
1419 }
1420
1421 /// The final component of the path, if it is a normal file.
1422 ///
62682a34 1423 /// If the path terminates in `.`, `..`, or consists solely of a root of
c34b1796
AL
1424 /// prefix, `file_name` will return `None`.
1425 ///
1426 /// # Examples
1427 ///
1428 /// ```
1429 /// use std::path::Path;
62682a34 1430 /// use std::ffi::OsStr;
c34b1796 1431 ///
62682a34
SL
1432 /// let path = Path::new("foo.txt");
1433 /// let os_str = OsStr::new("foo.txt");
c34b1796 1434 ///
62682a34 1435 /// assert_eq!(Some(os_str), path.file_name());
c34b1796
AL
1436 /// ```
1437 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1438 pub fn file_name(&self) -> Option<&OsStr> {
1439 self.components().next_back().and_then(|p| match p {
c34b1796 1440 Component::Normal(p) => Some(p.as_ref()),
85aaf69f
SL
1441 _ => None
1442 })
1443 }
1444
1445 /// Returns a path that, when joined onto `base`, yields `self`.
c34b1796
AL
1446 ///
1447 /// If `base` is not a prefix of `self` (i.e. `starts_with`
1448 /// returns false), then `relative_from` returns `None`.
1449 #[unstable(feature = "path_relative_from", reason = "see #23284")]
1450 pub fn relative_from<'a, P: ?Sized + AsRef<Path>>(&'a self, base: &'a P) -> Option<&Path>
85aaf69f 1451 {
c34b1796 1452 iter_after(self.components(), base.as_ref().components()).map(|c| c.as_path())
85aaf69f
SL
1453 }
1454
1455 /// Determines whether `base` is a prefix of `self`.
c34b1796 1456 ///
d9579d0f
AL
1457 /// Only considers whole path components to match.
1458 ///
c34b1796
AL
1459 /// # Examples
1460 ///
1461 /// ```
1462 /// use std::path::Path;
1463 ///
1464 /// let path = Path::new("/etc/passwd");
1465 ///
1466 /// assert!(path.starts_with("/etc"));
d9579d0f
AL
1467 ///
1468 /// assert!(!path.starts_with("/e"));
c34b1796
AL
1469 /// ```
1470 #[stable(feature = "rust1", since = "1.0.0")]
1471 pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
1472 iter_after(self.components(), base.as_ref().components()).is_some()
85aaf69f
SL
1473 }
1474
c34b1796
AL
1475 /// Determines whether `child` is a suffix of `self`.
1476 ///
d9579d0f
AL
1477 /// Only considers whole path components to match.
1478 ///
c34b1796
AL
1479 /// # Examples
1480 ///
1481 /// ```
1482 /// use std::path::Path;
1483 ///
1484 /// let path = Path::new("/etc/passwd");
1485 ///
1486 /// assert!(path.ends_with("passwd"));
1487 /// ```
1488 #[stable(feature = "rust1", since = "1.0.0")]
1489 pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
1490 iter_after(self.components().rev(), child.as_ref().components().rev()).is_some()
85aaf69f
SL
1491 }
1492
62682a34 1493 /// Extracts the stem (non-extension) portion of `self.file_name()`.
85aaf69f
SL
1494 ///
1495 /// The stem is:
1496 ///
1497 /// * None, if there is no file name;
1498 /// * The entire file name if there is no embedded `.`;
1499 /// * The entire file name if the file name begins with `.` and has no other `.`s within;
1500 /// * Otherwise, the portion of the file name before the final `.`
c34b1796
AL
1501 ///
1502 /// # Examples
1503 ///
1504 /// ```
1505 /// use std::path::Path;
1506 ///
1507 /// let path = Path::new("foo.rs");
1508 ///
1509 /// assert_eq!("foo", path.file_stem().unwrap());
1510 /// ```
1511 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1512 pub fn file_stem(&self) -> Option<&OsStr> {
1513 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
1514 }
1515
62682a34 1516 /// Extracts the extension of `self.file_name()`, if possible.
85aaf69f
SL
1517 ///
1518 /// The extension is:
1519 ///
1520 /// * None, if there is no file name;
1521 /// * None, if there is no embedded `.`;
1522 /// * None, if the file name begins with `.` and has no other `.`s within;
1523 /// * Otherwise, the portion of the file name after the final `.`
c34b1796
AL
1524 ///
1525 /// # Examples
1526 ///
1527 /// ```
1528 /// use std::path::Path;
1529 ///
1530 /// let path = Path::new("foo.rs");
1531 ///
1532 /// assert_eq!("rs", path.extension().unwrap());
1533 /// ```
1534 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1535 pub fn extension(&self) -> Option<&OsStr> {
1536 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
1537 }
1538
1539 /// Creates an owned `PathBuf` with `path` adjoined to `self`.
1540 ///
1541 /// See `PathBuf::push` for more details on what it means to adjoin a path.
c34b1796
AL
1542 ///
1543 /// # Examples
1544 ///
1545 /// ```
62682a34 1546 /// use std::path::{Path, PathBuf};
c34b1796 1547 ///
62682a34 1548 /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
c34b1796
AL
1549 /// ```
1550 #[stable(feature = "rust1", since = "1.0.0")]
1551 pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
85aaf69f
SL
1552 let mut buf = self.to_path_buf();
1553 buf.push(path);
1554 buf
1555 }
1556
1557 /// Creates an owned `PathBuf` like `self` but with the given file name.
1558 ///
1559 /// See `PathBuf::set_file_name` for more details.
c34b1796
AL
1560 ///
1561 /// # Examples
1562 ///
1563 /// ```
62682a34 1564 /// use std::path::{Path, PathBuf};
c34b1796 1565 ///
62682a34
SL
1566 /// let path = Path::new("/tmp/foo.txt");
1567 /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
c34b1796
AL
1568 /// ```
1569 #[stable(feature = "rust1", since = "1.0.0")]
1570 pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
85aaf69f
SL
1571 let mut buf = self.to_path_buf();
1572 buf.set_file_name(file_name);
1573 buf
1574 }
1575
1576 /// Creates an owned `PathBuf` like `self` but with the given extension.
1577 ///
1578 /// See `PathBuf::set_extension` for more details.
c34b1796
AL
1579 ///
1580 /// # Examples
1581 ///
1582 /// ```
9346a6ac 1583 /// use std::path::{Path, PathBuf};
c34b1796 1584 ///
62682a34
SL
1585 /// let path = Path::new("foo.rs");
1586 /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
c34b1796
AL
1587 /// ```
1588 #[stable(feature = "rust1", since = "1.0.0")]
1589 pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
85aaf69f
SL
1590 let mut buf = self.to_path_buf();
1591 buf.set_extension(extension);
1592 buf
1593 }
1594
1595 /// Produce an iterator over the components of the path.
c34b1796
AL
1596 ///
1597 /// # Examples
1598 ///
1599 /// ```
62682a34
SL
1600 /// use std::path::{Path, Component};
1601 /// use std::ffi::OsStr;
c34b1796 1602 ///
62682a34 1603 /// let mut components = Path::new("/tmp/foo.txt").components();
c34b1796 1604 ///
62682a34
SL
1605 /// assert_eq!(components.next(), Some(Component::RootDir));
1606 /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
1607 /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
1608 /// assert_eq!(components.next(), None)
c34b1796
AL
1609 /// ```
1610 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1611 pub fn components(&self) -> Components {
1612 let prefix = parse_prefix(self.as_os_str());
1613 Components {
1614 path: self.as_u8_slice(),
1615 prefix: prefix,
1616 has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
1617 front: State::Prefix,
c34b1796 1618 back: State::Body,
85aaf69f
SL
1619 }
1620 }
1621
1622 /// Produce an iterator over the path's components viewed as `OsStr` slices.
c34b1796
AL
1623 ///
1624 /// # Examples
1625 ///
1626 /// ```
62682a34
SL
1627 /// use std::path::{self, Path};
1628 /// use std::ffi::OsStr;
1629 ///
1630 /// let mut it = Path::new("/tmp/foo.txt").iter();
1631 /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
1632 /// assert_eq!(it.next(), Some(OsStr::new("tmp")));
1633 /// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
1634 /// assert_eq!(it.next(), None)
c34b1796
AL
1635 /// ```
1636 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1637 pub fn iter(&self) -> Iter {
1638 Iter { inner: self.components() }
1639 }
1640
1641 /// Returns an object that implements `Display` for safely printing paths
1642 /// that may contain non-Unicode data.
c34b1796
AL
1643 ///
1644 /// # Examples
1645 ///
1646 /// ```
1647 /// use std::path::Path;
1648 ///
1649 /// let path = Path::new("/tmp/foo.rs");
1650 ///
1651 /// println!("{}", path.display());
1652 /// ```
1653 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1654 pub fn display(&self) -> Display {
1655 Display { path: self }
1656 }
1657}
1658
c34b1796
AL
1659#[stable(feature = "rust1", since = "1.0.0")]
1660impl AsRef<OsStr> for Path {
1661 fn as_ref(&self) -> &OsStr {
1662 &self.inner
1663 }
1664}
1665
c34b1796 1666#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1667impl fmt::Debug for Path {
1668 fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
1669 self.inner.fmt(formatter)
1670 }
1671}
1672
1673/// Helper struct for safely printing paths with `format!()` and `{}`
c34b1796 1674#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1675pub struct Display<'a> {
1676 path: &'a Path
1677}
1678
c34b1796 1679#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1680impl<'a> fmt::Debug for Display<'a> {
1681 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1682 fmt::Debug::fmt(&self.path.to_string_lossy(), f)
1683 }
1684}
1685
c34b1796 1686#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1687impl<'a> fmt::Display for Display<'a> {
1688 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1689 fmt::Display::fmt(&self.path.to_string_lossy(), f)
1690 }
1691}
1692
c34b1796 1693#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1694impl cmp::PartialEq for Path {
1695 fn eq(&self, other: &Path) -> bool {
1696 iter::order::eq(self.components(), other.components())
1697 }
1698}
1699
c34b1796 1700#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1701impl cmp::Eq for Path {}
1702
c34b1796 1703#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1704impl cmp::PartialOrd for Path {
1705 fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
1706 self.components().partial_cmp(&other.components())
1707 }
1708}
1709
c34b1796 1710#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1711impl cmp::Ord for Path {
1712 fn cmp(&self, other: &Path) -> cmp::Ordering {
1713 self.components().cmp(&other.components())
1714 }
1715}
1716
c34b1796
AL
1717#[stable(feature = "rust1", since = "1.0.0")]
1718impl AsRef<Path> for Path {
1719 fn as_ref(&self) -> &Path { self }
1720}
1721
1722#[stable(feature = "rust1", since = "1.0.0")]
1723impl AsRef<Path> for OsStr {
1724 fn as_ref(&self) -> &Path { Path::new(self) }
1725}
1726
1727#[stable(feature = "rust1", since = "1.0.0")]
1728impl AsRef<Path> for OsString {
1729 fn as_ref(&self) -> &Path { Path::new(self) }
1730}
1731
1732#[stable(feature = "rust1", since = "1.0.0")]
1733impl AsRef<Path> for str {
1734 fn as_ref(&self) -> &Path { Path::new(self) }
1735}
1736
1737#[stable(feature = "rust1", since = "1.0.0")]
1738impl AsRef<Path> for String {
1739 fn as_ref(&self) -> &Path { Path::new(self) }
1740}
1741
1742#[stable(feature = "rust1", since = "1.0.0")]
1743impl AsRef<Path> for PathBuf {
1744 fn as_ref(&self) -> &Path { self }
1745}
1746
85aaf69f
SL
1747#[cfg(test)]
1748mod tests {
1749 use super::*;
85aaf69f
SL
1750 use core::prelude::*;
1751 use string::{ToString, String};
1752 use vec::Vec;
1753
1754 macro_rules! t(
1755 ($path:expr, iter: $iter:expr) => (
1756 {
1757 let path = Path::new($path);
1758
1759 // Forward iteration
1760 let comps = path.iter()
1761 .map(|p| p.to_string_lossy().into_owned())
1762 .collect::<Vec<String>>();
1763 let exp: &[&str] = &$iter;
1764 let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
1765 assert!(comps == exps, "iter: Expected {:?}, found {:?}",
1766 exps, comps);
1767
1768 // Reverse iteration
1769 let comps = Path::new($path).iter().rev()
1770 .map(|p| p.to_string_lossy().into_owned())
1771 .collect::<Vec<String>>();
1772 let exps = exps.into_iter().rev().collect::<Vec<String>>();
1773 assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
1774 exps, comps);
1775 }
1776 );
1777
1778 ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
1779 {
1780 let path = Path::new($path);
1781
1782 let act_root = path.has_root();
1783 assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
1784 $has_root, act_root);
1785
1786 let act_abs = path.is_absolute();
1787 assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
1788 $is_absolute, act_abs);
1789 }
1790 );
1791
1792 ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
1793 {
1794 let path = Path::new($path);
1795
1796 let parent = path.parent().map(|p| p.to_str().unwrap());
1797 let exp_parent: Option<&str> = $parent;
1798 assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
1799 exp_parent, parent);
1800
1801 let file = path.file_name().map(|p| p.to_str().unwrap());
1802 let exp_file: Option<&str> = $file;
1803 assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
1804 exp_file, file);
1805 }
1806 );
1807
1808 ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
1809 {
1810 let path = Path::new($path);
1811
1812 let stem = path.file_stem().map(|p| p.to_str().unwrap());
1813 let exp_stem: Option<&str> = $file_stem;
1814 assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
1815 exp_stem, stem);
1816
1817 let ext = path.extension().map(|p| p.to_str().unwrap());
1818 let exp_ext: Option<&str> = $extension;
1819 assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
1820 exp_ext, ext);
1821 }
1822 );
1823
1824 ($path:expr, iter: $iter:expr,
1825 has_root: $has_root:expr, is_absolute: $is_absolute:expr,
1826 parent: $parent:expr, file_name: $file:expr,
1827 file_stem: $file_stem:expr, extension: $extension:expr) => (
1828 {
1829 t!($path, iter: $iter);
1830 t!($path, has_root: $has_root, is_absolute: $is_absolute);
1831 t!($path, parent: $parent, file_name: $file);
1832 t!($path, file_stem: $file_stem, extension: $extension);
1833 }
1834 );
1835 );
1836
c34b1796
AL
1837 #[test]
1838 fn into_cow() {
1839 use borrow::{Cow, IntoCow};
1840
1841 let static_path = Path::new("/home/foo");
1842 let static_cow_path: Cow<'static, Path> = static_path.into_cow();
1843 let pathbuf = PathBuf::from("/home/foo");
1844
1845 {
1846 let path: &Path = &pathbuf;
1847 let borrowed_cow_path: Cow<Path> = path.into_cow();
1848
1849 assert_eq!(static_cow_path, borrowed_cow_path);
1850 }
1851
1852 let owned_cow_path: Cow<'static, Path> = pathbuf.into_cow();
1853
1854 assert_eq!(static_cow_path, owned_cow_path);
1855 }
1856
85aaf69f
SL
1857 #[test]
1858 #[cfg(unix)]
1859 pub fn test_decompositions_unix() {
1860 t!("",
1861 iter: [],
1862 has_root: false,
1863 is_absolute: false,
1864 parent: None,
1865 file_name: None,
1866 file_stem: None,
1867 extension: None
1868 );
1869
1870 t!("foo",
1871 iter: ["foo"],
1872 has_root: false,
1873 is_absolute: false,
c34b1796 1874 parent: Some(""),
85aaf69f
SL
1875 file_name: Some("foo"),
1876 file_stem: Some("foo"),
1877 extension: None
1878 );
1879
1880 t!("/",
c34b1796 1881 iter: ["/"],
85aaf69f
SL
1882 has_root: true,
1883 is_absolute: true,
1884 parent: None,
1885 file_name: None,
1886 file_stem: None,
1887 extension: None
1888 );
1889
1890 t!("/foo",
1891 iter: ["/", "foo"],
1892 has_root: true,
1893 is_absolute: true,
1894 parent: Some("/"),
1895 file_name: Some("foo"),
1896 file_stem: Some("foo"),
1897 extension: None
1898 );
1899
1900 t!("foo/",
c34b1796 1901 iter: ["foo"],
85aaf69f
SL
1902 has_root: false,
1903 is_absolute: false,
c34b1796
AL
1904 parent: Some(""),
1905 file_name: Some("foo"),
1906 file_stem: Some("foo"),
85aaf69f
SL
1907 extension: None
1908 );
1909
1910 t!("/foo/",
c34b1796 1911 iter: ["/", "foo"],
85aaf69f
SL
1912 has_root: true,
1913 is_absolute: true,
c34b1796
AL
1914 parent: Some("/"),
1915 file_name: Some("foo"),
1916 file_stem: Some("foo"),
85aaf69f
SL
1917 extension: None
1918 );
1919
1920 t!("foo/bar",
1921 iter: ["foo", "bar"],
1922 has_root: false,
1923 is_absolute: false,
1924 parent: Some("foo"),
1925 file_name: Some("bar"),
1926 file_stem: Some("bar"),
1927 extension: None
1928 );
1929
1930 t!("/foo/bar",
1931 iter: ["/", "foo", "bar"],
1932 has_root: true,
1933 is_absolute: true,
1934 parent: Some("/foo"),
1935 file_name: Some("bar"),
1936 file_stem: Some("bar"),
1937 extension: None
1938 );
1939
1940 t!("///foo///",
c34b1796 1941 iter: ["/", "foo"],
85aaf69f
SL
1942 has_root: true,
1943 is_absolute: true,
c34b1796
AL
1944 parent: Some("/"),
1945 file_name: Some("foo"),
1946 file_stem: Some("foo"),
85aaf69f
SL
1947 extension: None
1948 );
1949
1950 t!("///foo///bar",
1951 iter: ["/", "foo", "bar"],
1952 has_root: true,
1953 is_absolute: true,
1954 parent: Some("///foo"),
1955 file_name: Some("bar"),
1956 file_stem: Some("bar"),
1957 extension: None
1958 );
1959
1960 t!("./.",
c34b1796 1961 iter: ["."],
85aaf69f
SL
1962 has_root: false,
1963 is_absolute: false,
c34b1796 1964 parent: Some(""),
85aaf69f
SL
1965 file_name: None,
1966 file_stem: None,
1967 extension: None
1968 );
1969
1970 t!("/..",
1971 iter: ["/", ".."],
1972 has_root: true,
1973 is_absolute: true,
1974 parent: Some("/"),
1975 file_name: None,
1976 file_stem: None,
1977 extension: None
1978 );
1979
1980 t!("../",
c34b1796 1981 iter: [".."],
85aaf69f
SL
1982 has_root: false,
1983 is_absolute: false,
c34b1796 1984 parent: Some(""),
85aaf69f
SL
1985 file_name: None,
1986 file_stem: None,
1987 extension: None
1988 );
1989
1990 t!("foo/.",
c34b1796 1991 iter: ["foo"],
85aaf69f
SL
1992 has_root: false,
1993 is_absolute: false,
c34b1796
AL
1994 parent: Some(""),
1995 file_name: Some("foo"),
1996 file_stem: Some("foo"),
85aaf69f
SL
1997 extension: None
1998 );
1999
2000 t!("foo/..",
2001 iter: ["foo", ".."],
2002 has_root: false,
2003 is_absolute: false,
2004 parent: Some("foo"),
2005 file_name: None,
2006 file_stem: None,
2007 extension: None
2008 );
2009
2010 t!("foo/./",
c34b1796 2011 iter: ["foo"],
85aaf69f
SL
2012 has_root: false,
2013 is_absolute: false,
c34b1796
AL
2014 parent: Some(""),
2015 file_name: Some("foo"),
2016 file_stem: Some("foo"),
85aaf69f
SL
2017 extension: None
2018 );
2019
2020 t!("foo/./bar",
c34b1796 2021 iter: ["foo", "bar"],
85aaf69f
SL
2022 has_root: false,
2023 is_absolute: false,
c34b1796 2024 parent: Some("foo"),
85aaf69f
SL
2025 file_name: Some("bar"),
2026 file_stem: Some("bar"),
2027 extension: None
2028 );
2029
2030 t!("foo/../",
c34b1796 2031 iter: ["foo", ".."],
85aaf69f
SL
2032 has_root: false,
2033 is_absolute: false,
c34b1796 2034 parent: Some("foo"),
85aaf69f
SL
2035 file_name: None,
2036 file_stem: None,
2037 extension: None
2038 );
2039
2040 t!("foo/../bar",
2041 iter: ["foo", "..", "bar"],
2042 has_root: false,
2043 is_absolute: false,
2044 parent: Some("foo/.."),
2045 file_name: Some("bar"),
2046 file_stem: Some("bar"),
2047 extension: None
2048 );
2049
2050 t!("./a",
2051 iter: [".", "a"],
2052 has_root: false,
2053 is_absolute: false,
2054 parent: Some("."),
2055 file_name: Some("a"),
2056 file_stem: Some("a"),
2057 extension: None
2058 );
2059
2060 t!(".",
2061 iter: ["."],
2062 has_root: false,
2063 is_absolute: false,
c34b1796 2064 parent: Some(""),
85aaf69f
SL
2065 file_name: None,
2066 file_stem: None,
2067 extension: None
2068 );
2069
2070 t!("./",
c34b1796 2071 iter: ["."],
85aaf69f
SL
2072 has_root: false,
2073 is_absolute: false,
c34b1796 2074 parent: Some(""),
85aaf69f
SL
2075 file_name: None,
2076 file_stem: None,
2077 extension: None
2078 );
2079
2080 t!("a/b",
2081 iter: ["a", "b"],
2082 has_root: false,
2083 is_absolute: false,
2084 parent: Some("a"),
2085 file_name: Some("b"),
2086 file_stem: Some("b"),
2087 extension: None
2088 );
2089
2090 t!("a//b",
2091 iter: ["a", "b"],
2092 has_root: false,
2093 is_absolute: false,
2094 parent: Some("a"),
2095 file_name: Some("b"),
2096 file_stem: Some("b"),
2097 extension: None
2098 );
2099
2100 t!("a/./b",
c34b1796 2101 iter: ["a", "b"],
85aaf69f
SL
2102 has_root: false,
2103 is_absolute: false,
c34b1796 2104 parent: Some("a"),
85aaf69f
SL
2105 file_name: Some("b"),
2106 file_stem: Some("b"),
2107 extension: None
2108 );
2109
2110 t!("a/b/c",
2111 iter: ["a", "b", "c"],
2112 has_root: false,
2113 is_absolute: false,
2114 parent: Some("a/b"),
2115 file_name: Some("c"),
2116 file_stem: Some("c"),
2117 extension: None
2118 );
c34b1796
AL
2119
2120 t!(".foo",
2121 iter: [".foo"],
2122 has_root: false,
2123 is_absolute: false,
2124 parent: Some(""),
2125 file_name: Some(".foo"),
2126 file_stem: Some(".foo"),
2127 extension: None
2128 );
85aaf69f
SL
2129 }
2130
2131 #[test]
2132 #[cfg(windows)]
2133 pub fn test_decompositions_windows() {
2134 t!("",
2135 iter: [],
2136 has_root: false,
2137 is_absolute: false,
2138 parent: None,
2139 file_name: None,
2140 file_stem: None,
2141 extension: None
2142 );
2143
2144 t!("foo",
2145 iter: ["foo"],
2146 has_root: false,
2147 is_absolute: false,
c34b1796 2148 parent: Some(""),
85aaf69f
SL
2149 file_name: Some("foo"),
2150 file_stem: Some("foo"),
2151 extension: None
2152 );
2153
2154 t!("/",
c34b1796 2155 iter: ["\\"],
85aaf69f
SL
2156 has_root: true,
2157 is_absolute: false,
2158 parent: None,
2159 file_name: None,
2160 file_stem: None,
2161 extension: None
2162 );
2163
2164 t!("\\",
c34b1796 2165 iter: ["\\"],
85aaf69f
SL
2166 has_root: true,
2167 is_absolute: false,
2168 parent: None,
2169 file_name: None,
2170 file_stem: None,
2171 extension: None
2172 );
2173
2174 t!("c:",
c34b1796 2175 iter: ["c:"],
85aaf69f
SL
2176 has_root: false,
2177 is_absolute: false,
2178 parent: None,
2179 file_name: None,
2180 file_stem: None,
2181 extension: None
2182 );
2183
2184 t!("c:\\",
c34b1796 2185 iter: ["c:", "\\"],
85aaf69f
SL
2186 has_root: true,
2187 is_absolute: true,
2188 parent: None,
2189 file_name: None,
2190 file_stem: None,
2191 extension: None
2192 );
2193
2194 t!("c:/",
c34b1796 2195 iter: ["c:", "\\"],
85aaf69f
SL
2196 has_root: true,
2197 is_absolute: true,
2198 parent: None,
2199 file_name: None,
2200 file_stem: None,
2201 extension: None
2202 );
2203
2204 t!("/foo",
2205 iter: ["\\", "foo"],
2206 has_root: true,
2207 is_absolute: false,
2208 parent: Some("/"),
2209 file_name: Some("foo"),
2210 file_stem: Some("foo"),
2211 extension: None
2212 );
2213
2214 t!("foo/",
c34b1796 2215 iter: ["foo"],
85aaf69f
SL
2216 has_root: false,
2217 is_absolute: false,
c34b1796
AL
2218 parent: Some(""),
2219 file_name: Some("foo"),
2220 file_stem: Some("foo"),
85aaf69f
SL
2221 extension: None
2222 );
2223
2224 t!("/foo/",
c34b1796 2225 iter: ["\\", "foo"],
85aaf69f
SL
2226 has_root: true,
2227 is_absolute: false,
c34b1796
AL
2228 parent: Some("/"),
2229 file_name: Some("foo"),
2230 file_stem: Some("foo"),
85aaf69f
SL
2231 extension: None
2232 );
2233
2234 t!("foo/bar",
2235 iter: ["foo", "bar"],
2236 has_root: false,
2237 is_absolute: false,
2238 parent: Some("foo"),
2239 file_name: Some("bar"),
2240 file_stem: Some("bar"),
2241 extension: None
2242 );
2243
2244 t!("/foo/bar",
2245 iter: ["\\", "foo", "bar"],
2246 has_root: true,
2247 is_absolute: false,
2248 parent: Some("/foo"),
2249 file_name: Some("bar"),
2250 file_stem: Some("bar"),
2251 extension: None
2252 );
2253
2254 t!("///foo///",
c34b1796 2255 iter: ["\\", "foo"],
85aaf69f
SL
2256 has_root: true,
2257 is_absolute: false,
c34b1796
AL
2258 parent: Some("/"),
2259 file_name: Some("foo"),
2260 file_stem: Some("foo"),
85aaf69f
SL
2261 extension: None
2262 );
2263
2264 t!("///foo///bar",
2265 iter: ["\\", "foo", "bar"],
2266 has_root: true,
2267 is_absolute: false,
2268 parent: Some("///foo"),
2269 file_name: Some("bar"),
2270 file_stem: Some("bar"),
2271 extension: None
2272 );
2273
2274 t!("./.",
c34b1796 2275 iter: ["."],
85aaf69f
SL
2276 has_root: false,
2277 is_absolute: false,
c34b1796 2278 parent: Some(""),
85aaf69f
SL
2279 file_name: None,
2280 file_stem: None,
2281 extension: None
2282 );
2283
2284 t!("/..",
2285 iter: ["\\", ".."],
2286 has_root: true,
2287 is_absolute: false,
2288 parent: Some("/"),
2289 file_name: None,
2290 file_stem: None,
2291 extension: None
2292 );
2293
2294 t!("../",
c34b1796 2295 iter: [".."],
85aaf69f
SL
2296 has_root: false,
2297 is_absolute: false,
c34b1796 2298 parent: Some(""),
85aaf69f
SL
2299 file_name: None,
2300 file_stem: None,
2301 extension: None
2302 );
2303
2304 t!("foo/.",
c34b1796 2305 iter: ["foo"],
85aaf69f
SL
2306 has_root: false,
2307 is_absolute: false,
c34b1796
AL
2308 parent: Some(""),
2309 file_name: Some("foo"),
2310 file_stem: Some("foo"),
85aaf69f
SL
2311 extension: None
2312 );
2313
2314 t!("foo/..",
2315 iter: ["foo", ".."],
2316 has_root: false,
2317 is_absolute: false,
2318 parent: Some("foo"),
2319 file_name: None,
2320 file_stem: None,
2321 extension: None
2322 );
2323
2324 t!("foo/./",
c34b1796 2325 iter: ["foo"],
85aaf69f
SL
2326 has_root: false,
2327 is_absolute: false,
c34b1796
AL
2328 parent: Some(""),
2329 file_name: Some("foo"),
2330 file_stem: Some("foo"),
85aaf69f
SL
2331 extension: None
2332 );
2333
2334 t!("foo/./bar",
c34b1796 2335 iter: ["foo", "bar"],
85aaf69f
SL
2336 has_root: false,
2337 is_absolute: false,
c34b1796 2338 parent: Some("foo"),
85aaf69f
SL
2339 file_name: Some("bar"),
2340 file_stem: Some("bar"),
2341 extension: None
2342 );
2343
2344 t!("foo/../",
c34b1796 2345 iter: ["foo", ".."],
85aaf69f
SL
2346 has_root: false,
2347 is_absolute: false,
c34b1796 2348 parent: Some("foo"),
85aaf69f
SL
2349 file_name: None,
2350 file_stem: None,
2351 extension: None
2352 );
2353
2354 t!("foo/../bar",
2355 iter: ["foo", "..", "bar"],
2356 has_root: false,
2357 is_absolute: false,
2358 parent: Some("foo/.."),
2359 file_name: Some("bar"),
2360 file_stem: Some("bar"),
2361 extension: None
2362 );
2363
2364 t!("./a",
2365 iter: [".", "a"],
2366 has_root: false,
2367 is_absolute: false,
2368 parent: Some("."),
2369 file_name: Some("a"),
2370 file_stem: Some("a"),
2371 extension: None
2372 );
2373
2374 t!(".",
2375 iter: ["."],
2376 has_root: false,
2377 is_absolute: false,
c34b1796 2378 parent: Some(""),
85aaf69f
SL
2379 file_name: None,
2380 file_stem: None,
2381 extension: None
2382 );
2383
2384 t!("./",
c34b1796 2385 iter: ["."],
85aaf69f
SL
2386 has_root: false,
2387 is_absolute: false,
c34b1796 2388 parent: Some(""),
85aaf69f
SL
2389 file_name: None,
2390 file_stem: None,
2391 extension: None
2392 );
2393
2394 t!("a/b",
2395 iter: ["a", "b"],
2396 has_root: false,
2397 is_absolute: false,
2398 parent: Some("a"),
2399 file_name: Some("b"),
2400 file_stem: Some("b"),
2401 extension: None
2402 );
2403
2404 t!("a//b",
2405 iter: ["a", "b"],
2406 has_root: false,
2407 is_absolute: false,
2408 parent: Some("a"),
2409 file_name: Some("b"),
2410 file_stem: Some("b"),
2411 extension: None
2412 );
2413
2414 t!("a/./b",
c34b1796 2415 iter: ["a", "b"],
85aaf69f
SL
2416 has_root: false,
2417 is_absolute: false,
c34b1796 2418 parent: Some("a"),
85aaf69f
SL
2419 file_name: Some("b"),
2420 file_stem: Some("b"),
2421 extension: None
2422 );
2423
2424 t!("a/b/c",
2425 iter: ["a", "b", "c"],
2426 has_root: false,
2427 is_absolute: false,
2428 parent: Some("a/b"),
2429 file_name: Some("c"),
2430 file_stem: Some("c"),
2431 extension: None);
2432
2433 t!("a\\b\\c",
2434 iter: ["a", "b", "c"],
2435 has_root: false,
2436 is_absolute: false,
2437 parent: Some("a\\b"),
2438 file_name: Some("c"),
2439 file_stem: Some("c"),
2440 extension: None
2441 );
2442
2443 t!("\\a",
2444 iter: ["\\", "a"],
2445 has_root: true,
2446 is_absolute: false,
2447 parent: Some("\\"),
2448 file_name: Some("a"),
2449 file_stem: Some("a"),
2450 extension: None
2451 );
2452
2453 t!("c:\\foo.txt",
2454 iter: ["c:", "\\", "foo.txt"],
2455 has_root: true,
2456 is_absolute: true,
2457 parent: Some("c:\\"),
2458 file_name: Some("foo.txt"),
2459 file_stem: Some("foo"),
2460 extension: Some("txt")
2461 );
2462
2463 t!("\\\\server\\share\\foo.txt",
2464 iter: ["\\\\server\\share", "\\", "foo.txt"],
2465 has_root: true,
2466 is_absolute: true,
2467 parent: Some("\\\\server\\share\\"),
2468 file_name: Some("foo.txt"),
2469 file_stem: Some("foo"),
2470 extension: Some("txt")
2471 );
2472
2473 t!("\\\\server\\share",
c34b1796 2474 iter: ["\\\\server\\share", "\\"],
85aaf69f
SL
2475 has_root: true,
2476 is_absolute: true,
2477 parent: None,
2478 file_name: None,
2479 file_stem: None,
2480 extension: None
2481 );
2482
2483 t!("\\\\server",
2484 iter: ["\\", "server"],
2485 has_root: true,
2486 is_absolute: false,
2487 parent: Some("\\"),
2488 file_name: Some("server"),
2489 file_stem: Some("server"),
2490 extension: None
2491 );
2492
2493 t!("\\\\?\\bar\\foo.txt",
2494 iter: ["\\\\?\\bar", "\\", "foo.txt"],
2495 has_root: true,
2496 is_absolute: true,
2497 parent: Some("\\\\?\\bar\\"),
2498 file_name: Some("foo.txt"),
2499 file_stem: Some("foo"),
2500 extension: Some("txt")
2501 );
2502
2503 t!("\\\\?\\bar",
2504 iter: ["\\\\?\\bar"],
2505 has_root: true,
2506 is_absolute: true,
2507 parent: None,
2508 file_name: None,
2509 file_stem: None,
2510 extension: None
2511 );
2512
2513 t!("\\\\?\\",
2514 iter: ["\\\\?\\"],
2515 has_root: true,
2516 is_absolute: true,
2517 parent: None,
2518 file_name: None,
2519 file_stem: None,
2520 extension: None
2521 );
2522
2523 t!("\\\\?\\UNC\\server\\share\\foo.txt",
2524 iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
2525 has_root: true,
2526 is_absolute: true,
2527 parent: Some("\\\\?\\UNC\\server\\share\\"),
2528 file_name: Some("foo.txt"),
2529 file_stem: Some("foo"),
2530 extension: Some("txt")
2531 );
2532
2533 t!("\\\\?\\UNC\\server",
2534 iter: ["\\\\?\\UNC\\server"],
2535 has_root: true,
2536 is_absolute: true,
2537 parent: None,
2538 file_name: None,
2539 file_stem: None,
2540 extension: None
2541 );
2542
2543 t!("\\\\?\\UNC\\",
2544 iter: ["\\\\?\\UNC\\"],
2545 has_root: true,
2546 is_absolute: true,
2547 parent: None,
2548 file_name: None,
2549 file_stem: None,
2550 extension: None
2551 );
2552
2553 t!("\\\\?\\C:\\foo.txt",
2554 iter: ["\\\\?\\C:", "\\", "foo.txt"],
2555 has_root: true,
2556 is_absolute: true,
2557 parent: Some("\\\\?\\C:\\"),
2558 file_name: Some("foo.txt"),
2559 file_stem: Some("foo"),
2560 extension: Some("txt")
2561 );
2562
2563
2564 t!("\\\\?\\C:\\",
c34b1796 2565 iter: ["\\\\?\\C:", "\\"],
85aaf69f
SL
2566 has_root: true,
2567 is_absolute: true,
2568 parent: None,
2569 file_name: None,
2570 file_stem: None,
2571 extension: None
2572 );
2573
2574
2575 t!("\\\\?\\C:",
2576 iter: ["\\\\?\\C:"],
2577 has_root: true,
2578 is_absolute: true,
2579 parent: None,
2580 file_name: None,
2581 file_stem: None,
2582 extension: None
2583 );
2584
2585
2586 t!("\\\\?\\foo/bar",
2587 iter: ["\\\\?\\foo/bar"],
2588 has_root: true,
2589 is_absolute: true,
2590 parent: None,
2591 file_name: None,
2592 file_stem: None,
2593 extension: None
2594 );
2595
2596
2597 t!("\\\\?\\C:/foo",
2598 iter: ["\\\\?\\C:/foo"],
2599 has_root: true,
2600 is_absolute: true,
2601 parent: None,
2602 file_name: None,
2603 file_stem: None,
2604 extension: None
2605 );
2606
2607
2608 t!("\\\\.\\foo\\bar",
2609 iter: ["\\\\.\\foo", "\\", "bar"],
2610 has_root: true,
2611 is_absolute: true,
2612 parent: Some("\\\\.\\foo\\"),
2613 file_name: Some("bar"),
2614 file_stem: Some("bar"),
2615 extension: None
2616 );
2617
2618
2619 t!("\\\\.\\foo",
c34b1796 2620 iter: ["\\\\.\\foo", "\\"],
85aaf69f
SL
2621 has_root: true,
2622 is_absolute: true,
2623 parent: None,
2624 file_name: None,
2625 file_stem: None,
2626 extension: None
2627 );
2628
2629
2630 t!("\\\\.\\foo/bar",
c34b1796 2631 iter: ["\\\\.\\foo/bar", "\\"],
85aaf69f
SL
2632 has_root: true,
2633 is_absolute: true,
2634 parent: None,
2635 file_name: None,
2636 file_stem: None,
2637 extension: None
2638 );
2639
2640
2641 t!("\\\\.\\foo\\bar/baz",
2642 iter: ["\\\\.\\foo", "\\", "bar", "baz"],
2643 has_root: true,
2644 is_absolute: true,
2645 parent: Some("\\\\.\\foo\\bar"),
2646 file_name: Some("baz"),
2647 file_stem: Some("baz"),
2648 extension: None
2649 );
2650
2651
2652 t!("\\\\.\\",
c34b1796 2653 iter: ["\\\\.\\", "\\"],
85aaf69f
SL
2654 has_root: true,
2655 is_absolute: true,
2656 parent: None,
2657 file_name: None,
2658 file_stem: None,
2659 extension: None
2660 );
2661
2662 t!("\\\\?\\a\\b\\",
c34b1796 2663 iter: ["\\\\?\\a", "\\", "b"],
85aaf69f
SL
2664 has_root: true,
2665 is_absolute: true,
c34b1796
AL
2666 parent: Some("\\\\?\\a\\"),
2667 file_name: Some("b"),
2668 file_stem: Some("b"),
85aaf69f
SL
2669 extension: None
2670 );
2671 }
2672
2673 #[test]
2674 pub fn test_stem_ext() {
2675 t!("foo",
2676 file_stem: Some("foo"),
2677 extension: None
2678 );
2679
2680 t!("foo.",
2681 file_stem: Some("foo"),
2682 extension: Some("")
2683 );
2684
2685 t!(".foo",
2686 file_stem: Some(".foo"),
2687 extension: None
2688 );
2689
2690 t!("foo.txt",
2691 file_stem: Some("foo"),
2692 extension: Some("txt")
2693 );
2694
2695 t!("foo.bar.txt",
2696 file_stem: Some("foo.bar"),
2697 extension: Some("txt")
2698 );
2699
2700 t!("foo.bar.",
2701 file_stem: Some("foo.bar"),
2702 extension: Some("")
2703 );
2704
2705 t!(".",
2706 file_stem: None,
2707 extension: None
2708 );
2709
2710 t!("..",
2711 file_stem: None,
2712 extension: None
2713 );
2714
2715 t!("",
2716 file_stem: None,
2717 extension: None
2718 );
2719 }
2720
2721 #[test]
2722 pub fn test_push() {
2723 macro_rules! tp(
2724 ($path:expr, $push:expr, $expected:expr) => ( {
c34b1796 2725 let mut actual = PathBuf::from($path);
85aaf69f
SL
2726 actual.push($push);
2727 assert!(actual.to_str() == Some($expected),
2728 "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
2729 $push, $path, $expected, actual.to_str().unwrap());
2730 });
2731 );
2732
2733 if cfg!(unix) {
2734 tp!("", "foo", "foo");
2735 tp!("foo", "bar", "foo/bar");
2736 tp!("foo/", "bar", "foo/bar");
2737 tp!("foo//", "bar", "foo//bar");
2738 tp!("foo/.", "bar", "foo/./bar");
2739 tp!("foo./.", "bar", "foo././bar");
2740 tp!("foo", "", "foo/");
2741 tp!("foo", ".", "foo/.");
2742 tp!("foo", "..", "foo/..");
2743 tp!("foo", "/", "/");
2744 tp!("/foo/bar", "/", "/");
2745 tp!("/foo/bar", "/baz", "/baz");
2746 tp!("/foo/bar", "./baz", "/foo/bar/./baz");
2747 } else {
2748 tp!("", "foo", "foo");
2749 tp!("foo", "bar", r"foo\bar");
2750 tp!("foo/", "bar", r"foo/bar");
2751 tp!(r"foo\", "bar", r"foo\bar");
2752 tp!("foo//", "bar", r"foo//bar");
2753 tp!(r"foo\\", "bar", r"foo\\bar");
2754 tp!("foo/.", "bar", r"foo/.\bar");
2755 tp!("foo./.", "bar", r"foo./.\bar");
2756 tp!(r"foo\.", "bar", r"foo\.\bar");
2757 tp!(r"foo.\.", "bar", r"foo.\.\bar");
2758 tp!("foo", "", "foo\\");
2759 tp!("foo", ".", r"foo\.");
2760 tp!("foo", "..", r"foo\..");
2761 tp!("foo", "/", "/");
2762 tp!("foo", r"\", r"\");
2763 tp!("/foo/bar", "/", "/");
2764 tp!(r"\foo\bar", r"\", r"\");
2765 tp!("/foo/bar", "/baz", "/baz");
2766 tp!("/foo/bar", r"\baz", r"\baz");
2767 tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
2768 tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
2769
2770 tp!("c:\\", "windows", "c:\\windows");
2771 tp!("c:", "windows", "c:windows");
2772
2773 tp!("a\\b\\c", "d", "a\\b\\c\\d");
2774 tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
2775 tp!("a\\b", "c\\d", "a\\b\\c\\d");
2776 tp!("a\\b", "\\c\\d", "\\c\\d");
2777 tp!("a\\b", ".", "a\\b\\.");
2778 tp!("a\\b", "..\\c", "a\\b\\..\\c");
2779 tp!("a\\b", "C:a.txt", "C:a.txt");
2780 tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
2781 tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
2782 tp!("C:\\a\\b\\c", "C:d", "C:d");
2783 tp!("C:a\\b\\c", "C:d", "C:d");
2784 tp!("C:", r"a\b\c", r"C:a\b\c");
2785 tp!("C:", r"..\a", r"C:..\a");
2786 tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar");
2787 tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
2788 tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
2789 tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
2790 tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
2791 tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
2792 tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar");
2793 tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
2794 tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
2795
2796 // Note: modified from old path API
2797 tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
2798
2799 tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share");
2800 tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
2801 tp!("\\\\.\\foo\\bar", "C:a", "C:a");
2802 // again, not sure about the following, but I'm assuming \\.\ should be verbatim
2803 tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
2804
2805 tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
2806 }
2807 }
2808
2809 #[test]
2810 pub fn test_pop() {
2811 macro_rules! tp(
2812 ($path:expr, $expected:expr, $output:expr) => ( {
c34b1796 2813 let mut actual = PathBuf::from($path);
85aaf69f
SL
2814 let output = actual.pop();
2815 assert!(actual.to_str() == Some($expected) && output == $output,
2816 "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
2817 $path, $expected, $output,
2818 actual.to_str().unwrap(), output);
2819 });
2820 );
2821
2822 tp!("", "", false);
2823 tp!("/", "/", false);
c34b1796
AL
2824 tp!("foo", "", true);
2825 tp!(".", "", true);
85aaf69f
SL
2826 tp!("/foo", "/", true);
2827 tp!("/foo/bar", "/foo", true);
2828 tp!("foo/bar", "foo", true);
c34b1796 2829 tp!("foo/.", "", true);
85aaf69f
SL
2830 tp!("foo//bar", "foo", true);
2831
2832 if cfg!(windows) {
2833 tp!("a\\b\\c", "a\\b", true);
2834 tp!("\\a", "\\", true);
2835 tp!("\\", "\\", false);
2836
2837 tp!("C:\\a\\b", "C:\\a", true);
2838 tp!("C:\\a", "C:\\", true);
2839 tp!("C:\\", "C:\\", false);
2840 tp!("C:a\\b", "C:a", true);
2841 tp!("C:a", "C:", true);
2842 tp!("C:", "C:", false);
2843 tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
2844 tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
2845 tp!("\\\\server\\share", "\\\\server\\share", false);
2846 tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
2847 tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
2848 tp!("\\\\?\\a", "\\\\?\\a", false);
2849 tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
2850 tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
2851 tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
2852 tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true);
2853 tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true);
2854 tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false);
2855 tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
2856 tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
2857 tp!("\\\\.\\a", "\\\\.\\a", false);
2858
c34b1796 2859 tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
85aaf69f
SL
2860 }
2861 }
2862
2863 #[test]
2864 pub fn test_set_file_name() {
2865 macro_rules! tfn(
2866 ($path:expr, $file:expr, $expected:expr) => ( {
c34b1796 2867 let mut p = PathBuf::from($path);
85aaf69f
SL
2868 p.set_file_name($file);
2869 assert!(p.to_str() == Some($expected),
2870 "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
2871 $path, $file, $expected,
2872 p.to_str().unwrap());
2873 });
2874 );
2875
2876 tfn!("foo", "foo", "foo");
2877 tfn!("foo", "bar", "bar");
2878 tfn!("foo", "", "");
2879 tfn!("", "foo", "foo");
2880 if cfg!(unix) {
2881 tfn!(".", "foo", "./foo");
c34b1796
AL
2882 tfn!("foo/", "bar", "bar");
2883 tfn!("foo/.", "bar", "bar");
85aaf69f
SL
2884 tfn!("..", "foo", "../foo");
2885 tfn!("foo/..", "bar", "foo/../bar");
2886 tfn!("/", "foo", "/foo");
2887 } else {
2888 tfn!(".", "foo", r".\foo");
c34b1796
AL
2889 tfn!(r"foo\", "bar", r"bar");
2890 tfn!(r"foo\.", "bar", r"bar");
85aaf69f
SL
2891 tfn!("..", "foo", r"..\foo");
2892 tfn!(r"foo\..", "bar", r"foo\..\bar");
2893 tfn!(r"\", "foo", r"\foo");
2894 }
2895 }
2896
2897 #[test]
2898 pub fn test_set_extension() {
2899 macro_rules! tfe(
2900 ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
c34b1796 2901 let mut p = PathBuf::from($path);
85aaf69f
SL
2902 let output = p.set_extension($ext);
2903 assert!(p.to_str() == Some($expected) && output == $output,
2904 "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
2905 $path, $ext, $expected, $output,
2906 p.to_str().unwrap(), output);
2907 });
2908 );
2909
2910 tfe!("foo", "txt", "foo.txt", true);
2911 tfe!("foo.bar", "txt", "foo.txt", true);
2912 tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
2913 tfe!(".test", "txt", ".test.txt", true);
2914 tfe!("foo.txt", "", "foo", true);
2915 tfe!("foo", "", "foo", true);
2916 tfe!("", "foo", "", false);
2917 tfe!(".", "foo", ".", false);
c34b1796
AL
2918 tfe!("foo/", "bar", "foo.bar", true);
2919 tfe!("foo/.", "bar", "foo.bar", true);
85aaf69f
SL
2920 tfe!("..", "foo", "..", false);
2921 tfe!("foo/..", "bar", "foo/..", false);
2922 tfe!("/", "foo", "/", false);
2923 }
2924
2925 #[test]
2926 pub fn test_compare() {
2927 macro_rules! tc(
2928 ($path1:expr, $path2:expr, eq: $eq:expr,
2929 starts_with: $starts_with:expr, ends_with: $ends_with:expr,
2930 relative_from: $relative_from:expr) => ({
2931 let path1 = Path::new($path1);
2932 let path2 = Path::new($path2);
2933
2934 let eq = path1 == path2;
2935 assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
2936 $path1, $path2, $eq, eq);
2937
2938 let starts_with = path1.starts_with(path2);
2939 assert!(starts_with == $starts_with,
2940 "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
2941 $starts_with, starts_with);
2942
2943 let ends_with = path1.ends_with(path2);
2944 assert!(ends_with == $ends_with,
2945 "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
2946 $ends_with, ends_with);
2947
2948 let relative_from = path1.relative_from(path2).map(|p| p.to_str().unwrap());
2949 let exp: Option<&str> = $relative_from;
2950 assert!(relative_from == exp,
2951 "{:?}.relative_from({:?}), expected {:?}, got {:?}", $path1, $path2,
2952 exp, relative_from);
2953 });
2954 );
2955
2956 tc!("", "",
2957 eq: true,
2958 starts_with: true,
2959 ends_with: true,
2960 relative_from: Some("")
2961 );
2962
2963 tc!("foo", "",
2964 eq: false,
2965 starts_with: true,
2966 ends_with: true,
2967 relative_from: Some("foo")
2968 );
2969
2970 tc!("", "foo",
2971 eq: false,
2972 starts_with: false,
2973 ends_with: false,
2974 relative_from: None
2975 );
2976
2977 tc!("foo", "foo",
2978 eq: true,
2979 starts_with: true,
2980 ends_with: true,
2981 relative_from: Some("")
2982 );
2983
2984 tc!("foo/", "foo",
c34b1796 2985 eq: true,
85aaf69f 2986 starts_with: true,
c34b1796
AL
2987 ends_with: true,
2988 relative_from: Some("")
85aaf69f
SL
2989 );
2990
2991 tc!("foo/bar", "foo",
2992 eq: false,
2993 starts_with: true,
2994 ends_with: false,
2995 relative_from: Some("bar")
2996 );
2997
2998 tc!("foo/bar/baz", "foo/bar",
2999 eq: false,
3000 starts_with: true,
3001 ends_with: false,
3002 relative_from: Some("baz")
3003 );
3004
3005 tc!("foo/bar", "foo/bar/baz",
3006 eq: false,
3007 starts_with: false,
3008 ends_with: false,
3009 relative_from: None
3010 );
3011
3012 tc!("./foo/bar/", ".",
3013 eq: false,
3014 starts_with: true,
c34b1796
AL
3015 ends_with: false,
3016 relative_from: Some("foo/bar")
85aaf69f 3017 );
c34b1796
AL
3018
3019 if cfg!(windows) {
3020 tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
3021 r"c:\src\rust\cargo-test\test",
3022 eq: false,
3023 starts_with: true,
3024 ends_with: false,
3025 relative_from: Some("Cargo.toml")
3026 );
3027
3028 tc!(r"c:\foo", r"C:\foo",
3029 eq: true,
3030 starts_with: true,
3031 ends_with: true,
3032 relative_from: Some("")
3033 );
3034 }
85aaf69f
SL
3035 }
3036}