]> git.proxmox.com Git - rustc.git/blame - src/libstd/path.rs
New upstream version 1.28.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//!
32a655c1
SL
13//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`]
14//! and [`str`]), for working with paths abstractly. These types are thin wrappers
15//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly
85aaf69f
SL
16//! on strings according to the local platform's path syntax.
17//!
cc61c64b
XL
18//! Paths can be parsed into [`Component`]s by iterating over the structure
19//! returned by the [`components`] method on [`Path`]. [`Component`]s roughly
20//! correspond to the substrings between path separators (`/` or `\`). You can
21//! reconstruct an equivalent path from components with the [`push`] method on
22//! [`PathBuf`]; note that the paths may differ syntactically by the
23//! normalization described in the documentation for the [`components`] method.
24//!
85aaf69f
SL
25//! ## Simple usage
26//!
c34b1796 27//! Path manipulation includes both parsing components from slices and building
85aaf69f
SL
28//! new owned paths.
29//!
32a655c1 30//! To parse a path, you can create a [`Path`] slice from a [`str`]
85aaf69f
SL
31//! slice and start asking questions:
32//!
32a655c1 33//! ```
85aaf69f 34//! use std::path::Path;
476ff2be 35//! use std::ffi::OsStr;
85aaf69f
SL
36//!
37//! let path = Path::new("/tmp/foo/bar.txt");
476ff2be
SL
38//!
39//! let parent = path.parent();
40//! assert_eq!(parent, Some(Path::new("/tmp/foo")));
41//!
42//! let file_stem = path.file_stem();
43//! assert_eq!(file_stem, Some(OsStr::new("bar")));
44//!
85aaf69f 45//! let extension = path.extension();
476ff2be 46//! assert_eq!(extension, Some(OsStr::new("txt")));
85aaf69f
SL
47//! ```
48//!
32a655c1 49//! To build or modify paths, use [`PathBuf`]:
85aaf69f 50//!
32a655c1 51//! ```
85aaf69f
SL
52//! use std::path::PathBuf;
53//!
7cac9316 54//! // This way works...
c34b1796 55//! let mut path = PathBuf::from("c:\\");
7cac9316 56//!
85aaf69f
SL
57//! path.push("windows");
58//! path.push("system32");
7cac9316 59//!
85aaf69f 60//! path.set_extension("dll");
7cac9316
XL
61//!
62//! // ... but push is best used if you don't know everything up
63//! // front. If you do, this way is better:
64//! let path: PathBuf = ["c:\\", "windows", "system32.dll"].iter().collect();
85aaf69f
SL
65//! ```
66//!
cc61c64b
XL
67//! [`Component`]: ../../std/path/enum.Component.html
68//! [`components`]: ../../std/path/struct.Path.html#method.components
32a655c1
SL
69//! [`PathBuf`]: ../../std/path/struct.PathBuf.html
70//! [`Path`]: ../../std/path/struct.Path.html
cc61c64b 71//! [`push`]: ../../std/path/struct.PathBuf.html#method.push
32a655c1 72//! [`String`]: ../../std/string/struct.String.html
7cac9316 73//!
32a655c1
SL
74//! [`str`]: ../../std/primitive.str.html
75//! [`OsString`]: ../../std/ffi/struct.OsString.html
76//! [`OsStr`]: ../../std/ffi/struct.OsStr.html
85aaf69f 77
c34b1796 78#![stable(feature = "rust1", since = "1.0.0")]
85aaf69f 79
9e0c209e 80use borrow::{Borrow, Cow};
85aaf69f 81use cmp;
9cc50fc6 82use error::Error;
b039eaaf
SL
83use fmt;
84use fs;
92a42be0 85use hash::{Hash, Hasher};
b039eaaf 86use io;
9e0c209e 87use iter::{self, FusedIterator};
85aaf69f 88use ops::{self, Deref};
ff7c6d11
XL
89use rc::Rc;
90use sync::Arc;
85aaf69f 91
9346a6ac 92use ffi::{OsStr, OsString};
85aaf69f 93
c30ab7b3 94use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix};
85aaf69f
SL
95
96////////////////////////////////////////////////////////////////////////////////
97// GENERAL NOTES
98////////////////////////////////////////////////////////////////////////////////
99//
100// Parsing in this module is done by directly transmuting OsStr to [u8] slices,
101// taking advantage of the fact that OsStr always encodes ASCII characters
102// as-is. Eventually, this transmutation should be replaced by direct uses of
103// OsStr APIs for parsing, but it will take a while for those to become
104// available.
105
85aaf69f
SL
106////////////////////////////////////////////////////////////////////////////////
107// Windows Prefixes
108////////////////////////////////////////////////////////////////////////////////
109
cc61c64b 110/// Windows path prefixes, e.g. `C:` or `\\server\share`.
85aaf69f 111///
cc61c64b
XL
112/// Windows uses a variety of path prefix styles, including references to drive
113/// volumes (like `C:`), network shared folders (like `\\server\share`), and
114/// others. In addition, some path prefixes are "verbatim" (i.e. prefixed with
115/// `\\?\`), in which case `/` is *not* treated as a separator and essentially
116/// no normalization is performed.
117///
118/// # Examples
119///
120/// ```
121/// use std::path::{Component, Path, Prefix};
122/// use std::path::Prefix::*;
123/// use std::ffi::OsStr;
124///
125/// fn get_path_prefix(s: &str) -> Prefix {
126/// let path = Path::new(s);
127/// match path.components().next().unwrap() {
128/// Component::Prefix(prefix_component) => prefix_component.kind(),
129/// _ => panic!(),
130/// }
131/// }
132///
133/// # if cfg!(windows) {
134/// assert_eq!(Verbatim(OsStr::new("pictures")),
135/// get_path_prefix(r"\\?\pictures\kittens"));
136/// assert_eq!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")),
137/// get_path_prefix(r"\\?\UNC\server\share"));
041b39d2 138/// assert_eq!(VerbatimDisk(b'C'), get_path_prefix(r"\\?\c:\"));
cc61c64b
XL
139/// assert_eq!(DeviceNS(OsStr::new("BrainInterface")),
140/// get_path_prefix(r"\\.\BrainInterface"));
141/// assert_eq!(UNC(OsStr::new("server"), OsStr::new("share")),
142/// get_path_prefix(r"\\server\share"));
041b39d2 143/// assert_eq!(Disk(b'C'), get_path_prefix(r"C:\Users\Rust\Pictures\Ferris"));
cc61c64b
XL
144/// # }
145/// ```
85aaf69f 146#[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)]
c34b1796 147#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 148pub enum Prefix<'a> {
cc61c64b
XL
149 /// Verbatim prefix, e.g. `\\?\cat_pics`.
150 ///
151 /// Verbatim prefixes consist of `\\?\` immediately followed by the given
152 /// component.
c34b1796 153 #[stable(feature = "rust1", since = "1.0.0")]
7453a54e 154 Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
85aaf69f 155
cc61c64b
XL
156 /// Verbatim prefix using Windows' _**U**niform **N**aming **C**onvention_,
157 /// e.g. `\\?\UNC\server\share`.
158 ///
159 /// Verbatim UNC prefixes consist of `\\?\UNC\` immediately followed by the
160 /// server's hostname and a share name.
c34b1796 161 #[stable(feature = "rust1", since = "1.0.0")]
9cc50fc6 162 VerbatimUNC(
7453a54e
SL
163 #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
164 #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
9cc50fc6 165 ),
85aaf69f 166
cc61c64b
XL
167 /// Verbatim disk prefix, e.g. `\\?\C:\`.
168 ///
169 /// Verbatim disk prefixes consist of `\\?\` immediately followed by the
170 /// drive letter and `:\`.
c34b1796 171 #[stable(feature = "rust1", since = "1.0.0")]
7453a54e 172 VerbatimDisk(#[stable(feature = "rust1", since = "1.0.0")] u8),
85aaf69f 173
cc61c64b
XL
174 /// Device namespace prefix, e.g. `\\.\COM42`.
175 ///
176 /// Device namespace prefixes consist of `\\.\` immediately followed by the
177 /// device name.
c34b1796 178 #[stable(feature = "rust1", since = "1.0.0")]
7453a54e 179 DeviceNS(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
85aaf69f 180
cc61c64b
XL
181 /// Prefix using Windows' _**U**niform **N**aming **C**onvention_, e.g.
182 /// `\\server\share`.
183 ///
184 /// UNC prefixes consist of the server's hostname and a share name.
c34b1796 185 #[stable(feature = "rust1", since = "1.0.0")]
9cc50fc6 186 UNC(
7453a54e
SL
187 #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
188 #[stable(feature = "rust1", since = "1.0.0")] &'a OsStr,
9cc50fc6 189 ),
85aaf69f
SL
190
191 /// Prefix `C:` for the given disk drive.
c34b1796 192 #[stable(feature = "rust1", since = "1.0.0")]
7453a54e 193 Disk(#[stable(feature = "rust1", since = "1.0.0")] u8),
85aaf69f
SL
194}
195
196impl<'a> Prefix<'a> {
197 #[inline]
198 fn len(&self) -> usize {
199 use self::Prefix::*;
200 fn os_str_len(s: &OsStr) -> usize {
201 os_str_as_u8_slice(s).len()
202 }
203 match *self {
204 Verbatim(x) => 4 + os_str_len(x),
92a42be0
SL
205 VerbatimUNC(x, y) => {
206 8 + os_str_len(x) +
207 if os_str_len(y) > 0 {
208 1 + os_str_len(y)
209 } else {
210 0
211 }
212 },
85aaf69f 213 VerbatimDisk(_) => 6,
92a42be0
SL
214 UNC(x, y) => {
215 2 + os_str_len(x) +
216 if os_str_len(y) > 0 {
217 1 + os_str_len(y)
218 } else {
219 0
220 }
221 },
85aaf69f 222 DeviceNS(x) => 4 + os_str_len(x),
92a42be0 223 Disk(_) => 2,
85aaf69f
SL
224 }
225
226 }
227
62682a34 228 /// Determines if the prefix is verbatim, i.e. begins with `\\?\`.
cc61c64b
XL
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// use std::path::Prefix::*;
234 /// use std::ffi::OsStr;
235 ///
236 /// assert!(Verbatim(OsStr::new("pictures")).is_verbatim());
237 /// assert!(VerbatimUNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
041b39d2 238 /// assert!(VerbatimDisk(b'C').is_verbatim());
cc61c64b
XL
239 /// assert!(!DeviceNS(OsStr::new("BrainInterface")).is_verbatim());
240 /// assert!(!UNC(OsStr::new("server"), OsStr::new("share")).is_verbatim());
041b39d2 241 /// assert!(!Disk(b'C').is_verbatim());
cc61c64b 242 /// ```
85aaf69f 243 #[inline]
c34b1796 244 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
245 pub fn is_verbatim(&self) -> bool {
246 use self::Prefix::*;
247 match *self {
9e0c209e 248 Verbatim(_) | VerbatimDisk(_) | VerbatimUNC(..) => true,
62682a34 249 _ => false,
85aaf69f
SL
250 }
251 }
252
253 #[inline]
254 fn is_drive(&self) -> bool {
255 match *self {
256 Prefix::Disk(_) => true,
257 _ => false,
258 }
259 }
260
261 #[inline]
262 fn has_implicit_root(&self) -> bool {
263 !self.is_drive()
264 }
265}
266
267////////////////////////////////////////////////////////////////////////////////
268// Exposed parsing helpers
269////////////////////////////////////////////////////////////////////////////////
270
9346a6ac 271/// Determines whether the character is one of the permitted path
85aaf69f 272/// separators for the current platform.
c34b1796
AL
273///
274/// # Examples
275///
276/// ```
277/// use std::path;
278///
041b39d2 279/// assert!(path::is_separator('/')); // '/' works for both Unix and Windows
c34b1796
AL
280/// assert!(!path::is_separator('❤'));
281/// ```
282#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 283pub fn is_separator(c: char) -> bool {
85aaf69f
SL
284 c.is_ascii() && is_sep_byte(c as u8)
285}
286
476ff2be
SL
287/// The primary separator of path components for the current platform.
288///
289/// For example, `/` on Unix and `\` on Windows.
c34b1796 290#[stable(feature = "rust1", since = "1.0.0")]
c30ab7b3 291pub const MAIN_SEPARATOR: char = ::sys::path::MAIN_SEP;
85aaf69f
SL
292
293////////////////////////////////////////////////////////////////////////////////
294// Misc helpers
295////////////////////////////////////////////////////////////////////////////////
296
297// Iterate through `iter` while it matches `prefix`; return `None` if `prefix`
298// is not a prefix of `iter`, otherwise return `Some(iter_after_prefix)` giving
299// `iter` after having exhausted `prefix`.
83c7162d
XL
300fn iter_after<'a, 'b, I, J>(mut iter: I, mut prefix: J) -> Option<I>
301 where I: Iterator<Item = Component<'a>> + Clone,
302 J: Iterator<Item = Component<'b>>,
85aaf69f
SL
303{
304 loop {
305 let mut iter_next = iter.clone();
306 match (iter_next.next(), prefix.next()) {
7453a54e
SL
307 (Some(ref x), Some(ref y)) if x == y => (),
308 (Some(_), Some(_)) => return None,
85aaf69f
SL
309 (Some(_), None) => return Some(iter),
310 (None, None) => return Some(iter),
311 (None, Some(_)) => return None,
312 }
313 iter = iter_next;
314 }
315}
316
317// See note at the top of this module to understand why these are used:
318fn os_str_as_u8_slice(s: &OsStr) -> &[u8] {
ea8adc8c 319 unsafe { &*(s as *const OsStr as *const [u8]) }
85aaf69f
SL
320}
321unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr {
ea8adc8c 322 &*(s as *const [u8] as *const OsStr)
85aaf69f
SL
323}
324
3b2f2976
XL
325// Detect scheme on Redox
326fn has_redox_scheme(s: &[u8]) -> bool {
327 cfg!(target_os = "redox") && s.split(|b| *b == b'/').next().unwrap_or(b"").contains(&b':')
328}
329
85aaf69f 330////////////////////////////////////////////////////////////////////////////////
c34b1796 331// Cross-platform, iterator-independent parsing
85aaf69f
SL
332////////////////////////////////////////////////////////////////////////////////
333
85aaf69f
SL
334/// Says whether the first byte after the prefix is a separator.
335fn has_physical_root(s: &[u8], prefix: Option<Prefix>) -> bool {
92a42be0
SL
336 let path = if let Some(p) = prefix {
337 &s[p.len()..]
338 } else {
339 s
340 };
9346a6ac 341 !path.is_empty() && is_sep_byte(path[0])
85aaf69f
SL
342}
343
85aaf69f 344// basic workhorse for splitting stem and extension
85aaf69f
SL
345fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
346 unsafe {
92a42be0
SL
347 if os_str_as_u8_slice(file) == b".." {
348 return (Some(file), None);
349 }
85aaf69f
SL
350
351 // The unsafety here stems from converting between &OsStr and &[u8]
352 // and back. This is safe to do because (1) we only look at ASCII
353 // contents of the encoding and (2) new &OsStr values are produced
354 // only from ASCII-bounded slices of existing &OsStr values.
355
c34b1796 356 let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.');
85aaf69f
SL
357 let after = iter.next();
358 let before = iter.next();
359 if before == Some(b"") {
360 (Some(file), None)
361 } else {
362 (before.map(|s| u8_slice_as_os_str(s)),
363 after.map(|s| u8_slice_as_os_str(s)))
364 }
365 }
366}
367
368////////////////////////////////////////////////////////////////////////////////
369// The core iterators
370////////////////////////////////////////////////////////////////////////////////
371
372/// Component parsing works by a double-ended state machine; the cursors at the
373/// front and back of the path each keep track of what parts of the path have
374/// been consumed so far.
375///
c34b1796
AL
376/// Going front to back, a path is made up of a prefix, a starting
377/// directory component, and a body (of normal components)
85aaf69f
SL
378#[derive(Copy, Clone, PartialEq, PartialOrd, Debug)]
379enum State {
380 Prefix = 0, // c:
c34b1796 381 StartDir = 1, // / or . or nothing
85aaf69f 382 Body = 2, // foo/bar/baz
c34b1796
AL
383 Done = 3,
384}
385
cc61c64b
XL
386/// A structure wrapping a Windows path prefix as well as its unparsed string
387/// representation.
388///
389/// In addition to the parsed [`Prefix`] information returned by [`kind`],
390/// `PrefixComponent` also holds the raw and unparsed [`OsStr`] slice,
391/// returned by [`as_os_str`].
392///
393/// Instances of this `struct` can be obtained by matching against the
394/// [`Prefix` variant] on [`Component`].
c34b1796
AL
395///
396/// Does not occur on Unix.
cc61c64b
XL
397///
398/// # Examples
399///
400/// ```
401/// # if cfg!(windows) {
402/// use std::path::{Component, Path, Prefix};
403/// use std::ffi::OsStr;
404///
405/// let path = Path::new(r"c:\you\later\");
406/// match path.components().next().unwrap() {
407/// Component::Prefix(prefix_component) => {
041b39d2 408/// assert_eq!(Prefix::Disk(b'C'), prefix_component.kind());
cc61c64b
XL
409/// assert_eq!(OsStr::new("c:"), prefix_component.as_os_str());
410/// }
411/// _ => unreachable!(),
412/// }
413/// # }
414/// ```
415///
416/// [`as_os_str`]: #method.as_os_str
417/// [`Component`]: enum.Component.html
418/// [`kind`]: #method.kind
419/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
420/// [`Prefix` variant]: enum.Component.html#variant.Prefix
421/// [`Prefix`]: enum.Prefix.html
c34b1796 422#[stable(feature = "rust1", since = "1.0.0")]
92a42be0 423#[derive(Copy, Clone, Eq, Debug)]
c34b1796
AL
424pub struct PrefixComponent<'a> {
425 /// The prefix as an unparsed `OsStr` slice.
426 raw: &'a OsStr,
427
428 /// The parsed prefix data.
429 parsed: Prefix<'a>,
430}
431
432impl<'a> PrefixComponent<'a> {
cc61c64b
XL
433 /// Returns the parsed prefix data.
434 ///
435 /// See [`Prefix`]'s documentation for more information on the different
436 /// kinds of prefixes.
437 ///
438 /// [`Prefix`]: enum.Prefix.html
c34b1796
AL
439 #[stable(feature = "rust1", since = "1.0.0")]
440 pub fn kind(&self) -> Prefix<'a> {
441 self.parsed
442 }
443
cc61c64b
XL
444 /// Returns the raw [`OsStr`] slice for this prefix.
445 ///
446 /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
c34b1796
AL
447 #[stable(feature = "rust1", since = "1.0.0")]
448 pub fn as_os_str(&self) -> &'a OsStr {
449 self.raw
450 }
451}
452
453#[stable(feature = "rust1", since = "1.0.0")]
454impl<'a> cmp::PartialEq for PrefixComponent<'a> {
455 fn eq(&self, other: &PrefixComponent<'a>) -> bool {
456 cmp::PartialEq::eq(&self.parsed, &other.parsed)
457 }
458}
459
460#[stable(feature = "rust1", since = "1.0.0")]
461impl<'a> cmp::PartialOrd for PrefixComponent<'a> {
462 fn partial_cmp(&self, other: &PrefixComponent<'a>) -> Option<cmp::Ordering> {
463 cmp::PartialOrd::partial_cmp(&self.parsed, &other.parsed)
464 }
465}
466
467#[stable(feature = "rust1", since = "1.0.0")]
468impl<'a> cmp::Ord for PrefixComponent<'a> {
469 fn cmp(&self, other: &PrefixComponent<'a>) -> cmp::Ordering {
470 cmp::Ord::cmp(&self.parsed, &other.parsed)
471 }
85aaf69f
SL
472}
473
92a42be0
SL
474#[stable(feature = "rust1", since = "1.0.0")]
475impl<'a> Hash for PrefixComponent<'a> {
476 fn hash<H: Hasher>(&self, h: &mut H) {
477 self.parsed.hash(h);
478 }
479}
480
85aaf69f
SL
481/// A single component of a path.
482///
3b2f2976 483/// A `Component` roughly corresponds to a substring between path separators
cc61c64b 484/// (`/` or `\`).
3157f602 485///
cc61c64b
XL
486/// This `enum` is created by iterating over [`Components`], which in turn is
487/// created by the [`components`][`Path::components`] method on [`Path`].
3157f602
XL
488///
489/// # Examples
490///
491/// ```rust
492/// use std::path::{Component, Path};
493///
494/// let path = Path::new("/tmp/foo/bar.txt");
495/// let components = path.components().collect::<Vec<_>>();
496/// assert_eq!(&components, &[
497/// Component::RootDir,
498/// Component::Normal("tmp".as_ref()),
499/// Component::Normal("foo".as_ref()),
500/// Component::Normal("bar.txt".as_ref()),
501/// ]);
502/// ```
503///
cc61c64b
XL
504/// [`Components`]: struct.Components.html
505/// [`Path`]: struct.Path.html
506/// [`Path::components`]: struct.Path.html#method.components
85aaf69f 507#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
c34b1796 508#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 509pub enum Component<'a> {
a7813a04 510 /// A Windows path prefix, e.g. `C:` or `\\server\share`.
85aaf69f 511 ///
cc61c64b
XL
512 /// There is a large variety of prefix types, see [`Prefix`]'s documentation
513 /// for more.
514 ///
85aaf69f 515 /// Does not occur on Unix.
cc61c64b
XL
516 ///
517 /// [`Prefix`]: enum.Prefix.html
c34b1796 518 #[stable(feature = "rust1", since = "1.0.0")]
9cc50fc6 519 Prefix(
7453a54e 520 #[stable(feature = "rust1", since = "1.0.0")] PrefixComponent<'a>
9cc50fc6 521 ),
85aaf69f 522
cc61c64b
XL
523 /// The root directory component, appears after any prefix and before anything else.
524 ///
525 /// It represents a separator that designates that a path starts from root.
c34b1796 526 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
527 RootDir,
528
cc61c64b 529 /// A reference to the current directory, i.e. `.`.
c34b1796 530 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
531 CurDir,
532
cc61c64b 533 /// A reference to the parent directory, i.e. `..`.
c34b1796 534 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
535 ParentDir,
536
cc61c64b
XL
537 /// A normal component, e.g. `a` and `b` in `a/b`.
538 ///
539 /// This variant is the most common one, it represents references to files
540 /// or directories.
c34b1796 541 #[stable(feature = "rust1", since = "1.0.0")]
7453a54e 542 Normal(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr),
85aaf69f
SL
543}
544
545impl<'a> Component<'a> {
cc61c64b 546 /// Extracts the underlying [`OsStr`] slice.
476ff2be
SL
547 ///
548 /// # Examples
549 ///
550 /// ```
551 /// use std::path::Path;
552 ///
553 /// let path = Path::new("./tmp/foo/bar.txt");
554 /// let components: Vec<_> = path.components().map(|comp| comp.as_os_str()).collect();
555 /// assert_eq!(&components, &[".", "tmp", "foo", "bar.txt"]);
556 /// ```
cc61c64b
XL
557 ///
558 /// [`OsStr`]: ../../std/ffi/struct.OsStr.html
c34b1796 559 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
560 pub fn as_os_str(self) -> &'a OsStr {
561 match self {
c34b1796
AL
562 Component::Prefix(p) => p.as_os_str(),
563 Component::RootDir => OsStr::new(MAIN_SEP_STR),
564 Component::CurDir => OsStr::new("."),
565 Component::ParentDir => OsStr::new(".."),
85aaf69f
SL
566 Component::Normal(path) => path,
567 }
568 }
569}
570
c34b1796
AL
571#[stable(feature = "rust1", since = "1.0.0")]
572impl<'a> AsRef<OsStr> for Component<'a> {
573 fn as_ref(&self) -> &OsStr {
574 self.as_os_str()
575 }
576}
577
0531ce1d 578#[stable(feature = "path_component_asref", since = "1.25.0")]
2c00a5a8
XL
579impl<'a> AsRef<Path> for Component<'a> {
580 fn as_ref(&self) -> &Path {
581 self.as_os_str().as_ref()
582 }
583}
584
3b2f2976 585/// An iterator over the [`Component`]s of a [`Path`].
c34b1796 586///
cc61c64b
XL
587/// This `struct` is created by the [`components`] method on [`Path`].
588/// See its documentation for more.
3157f602 589///
c34b1796
AL
590/// # Examples
591///
592/// ```
593/// use std::path::Path;
594///
595/// let path = Path::new("/tmp/foo/bar.txt");
596///
597/// for component in path.components() {
598/// println!("{:?}", component);
599/// }
600/// ```
3157f602 601///
cc61c64b
XL
602/// [`Component`]: enum.Component.html
603/// [`components`]: struct.Path.html#method.components
604/// [`Path`]: struct.Path.html
85aaf69f 605#[derive(Clone)]
c34b1796 606#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
607pub struct Components<'a> {
608 // The path left to parse components from
609 path: &'a [u8],
610
611 // The prefix as it was originally parsed, if any
612 prefix: Option<Prefix<'a>>,
613
614 // true if path *physically* has a root separator; for most Windows
615 // prefixes, it may have a "logical" rootseparator for the purposes of
616 // normalization, e.g. \\server\share == \\server\share\.
617 has_physical_root: bool,
618
619 // The iterator is double-ended, and these two states keep track of what has
620 // been produced from either end
621 front: State,
622 back: State,
623}
624
cc61c64b 625/// An iterator over the [`Component`]s of a [`Path`], as [`OsStr`] slices.
32a655c1 626///
cc61c64b
XL
627/// This `struct` is created by the [`iter`] method on [`Path`].
628/// See its documentation for more.
629///
630/// [`Component`]: enum.Component.html
631/// [`iter`]: struct.Path.html#method.iter
32a655c1 632/// [`OsStr`]: ../../std/ffi/struct.OsStr.html
cc61c64b 633/// [`Path`]: struct.Path.html
85aaf69f 634#[derive(Clone)]
c34b1796 635#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 636pub struct Iter<'a> {
92a42be0 637 inner: Components<'a>,
85aaf69f
SL
638}
639
9e0c209e
SL
640#[stable(feature = "path_components_debug", since = "1.13.0")]
641impl<'a> fmt::Debug for Components<'a> {
642 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
643 struct DebugHelper<'a>(&'a Path);
644
645 impl<'a> fmt::Debug for DebugHelper<'a> {
646 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
647 f.debug_list()
648 .entries(self.0.components())
649 .finish()
650 }
651 }
652
653 f.debug_tuple("Components")
654 .field(&DebugHelper(self.as_path()))
655 .finish()
656 }
657}
658
85aaf69f
SL
659impl<'a> Components<'a> {
660 // how long is the prefix, if any?
661 #[inline]
662 fn prefix_len(&self) -> usize {
663 self.prefix.as_ref().map(Prefix::len).unwrap_or(0)
664 }
665
666 #[inline]
667 fn prefix_verbatim(&self) -> bool {
668 self.prefix.as_ref().map(Prefix::is_verbatim).unwrap_or(false)
669 }
670
671 /// how much of the prefix is left from the point of view of iteration?
672 #[inline]
673 fn prefix_remaining(&self) -> usize {
e9174d1e
SL
674 if self.front == State::Prefix {
675 self.prefix_len()
676 } else {
677 0
678 }
85aaf69f
SL
679 }
680
c34b1796
AL
681 // Given the iteration so far, how much of the pre-State::Body path is left?
682 #[inline]
683 fn len_before_body(&self) -> usize {
92a42be0
SL
684 let root = if self.front <= State::StartDir && self.has_physical_root {
685 1
686 } else {
687 0
688 };
689 let cur_dir = if self.front <= State::StartDir && self.include_cur_dir() {
690 1
691 } else {
692 0
693 };
c34b1796 694 self.prefix_remaining() + root + cur_dir
85aaf69f
SL
695 }
696
697 // is the iteration complete?
698 #[inline]
699 fn finished(&self) -> bool {
700 self.front == State::Done || self.back == State::Done || self.front > self.back
701 }
702
703 #[inline]
704 fn is_sep_byte(&self, b: u8) -> bool {
705 if self.prefix_verbatim() {
706 is_verbatim_sep(b)
707 } else {
708 is_sep_byte(b)
709 }
710 }
711
9346a6ac 712 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
c34b1796
AL
713 ///
714 /// # Examples
715 ///
716 /// ```
717 /// use std::path::Path;
718 ///
e9174d1e
SL
719 /// let mut components = Path::new("/tmp/foo/bar.txt").components();
720 /// components.next();
721 /// components.next();
c34b1796 722 ///
e9174d1e 723 /// assert_eq!(Path::new("foo/bar.txt"), components.as_path());
c34b1796
AL
724 /// ```
725 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
726 pub fn as_path(&self) -> &'a Path {
727 let mut comps = self.clone();
92a42be0
SL
728 if comps.front == State::Body {
729 comps.trim_left();
730 }
731 if comps.back == State::Body {
732 comps.trim_right();
733 }
c34b1796 734 unsafe { Path::from_u8_slice(comps.path) }
85aaf69f
SL
735 }
736
737 /// Is the *original* path rooted?
738 fn has_root(&self) -> bool {
92a42be0
SL
739 if self.has_physical_root {
740 return true;
741 }
85aaf69f 742 if let Some(p) = self.prefix {
92a42be0
SL
743 if p.has_implicit_root() {
744 return true;
745 }
85aaf69f
SL
746 }
747 false
748 }
749
c34b1796
AL
750 /// Should the normalized path include a leading . ?
751 fn include_cur_dir(&self) -> bool {
92a42be0
SL
752 if self.has_root() {
753 return false;
754 }
c34b1796
AL
755 let mut iter = self.path[self.prefix_len()..].iter();
756 match (iter.next(), iter.next()) {
757 (Some(&b'.'), None) => true,
758 (Some(&b'.'), Some(&b)) => self.is_sep_byte(b),
92a42be0 759 _ => false,
c34b1796
AL
760 }
761 }
762
763 // parse a given byte sequence into the corresponding path component
764 fn parse_single_component<'b>(&self, comp: &'b [u8]) -> Option<Component<'b>> {
765 match comp {
766 b"." if self.prefix_verbatim() => Some(Component::CurDir),
767 b"." => None, // . components are normalized away, except at
768 // the beginning of a path, which is treated
769 // separately via `include_cur_dir`
770 b".." => Some(Component::ParentDir),
771 b"" => None,
92a42be0 772 _ => Some(Component::Normal(unsafe { u8_slice_as_os_str(comp) })),
c34b1796
AL
773 }
774 }
775
85aaf69f
SL
776 // parse a component from the left, saying how many bytes to consume to
777 // remove the component
778 fn parse_next_component(&self) -> (usize, Option<Component<'a>>) {
779 debug_assert!(self.front == State::Body);
780 let (extra, comp) = match self.path.iter().position(|b| self.is_sep_byte(*b)) {
781 None => (0, self.path),
92a42be0 782 Some(i) => (1, &self.path[..i]),
85aaf69f 783 };
c34b1796 784 (comp.len() + extra, self.parse_single_component(comp))
85aaf69f
SL
785 }
786
787 // parse a component from the right, saying how many bytes to consume to
788 // remove the component
789 fn parse_next_component_back(&self) -> (usize, Option<Component<'a>>) {
790 debug_assert!(self.back == State::Body);
c34b1796 791 let start = self.len_before_body();
85aaf69f 792 let (extra, comp) = match self.path[start..].iter().rposition(|b| self.is_sep_byte(*b)) {
92a42be0
SL
793 None => (0, &self.path[start..]),
794 Some(i) => (1, &self.path[start + i + 1..]),
85aaf69f 795 };
c34b1796 796 (comp.len() + extra, self.parse_single_component(comp))
85aaf69f
SL
797 }
798
9346a6ac 799 // trim away repeated separators (i.e. empty components) on the left
85aaf69f
SL
800 fn trim_left(&mut self) {
801 while !self.path.is_empty() {
802 let (size, comp) = self.parse_next_component();
803 if comp.is_some() {
804 return;
805 } else {
92a42be0 806 self.path = &self.path[size..];
85aaf69f
SL
807 }
808 }
809 }
810
9346a6ac 811 // trim away repeated separators (i.e. empty components) on the right
85aaf69f 812 fn trim_right(&mut self) {
c34b1796 813 while self.path.len() > self.len_before_body() {
85aaf69f
SL
814 let (size, comp) = self.parse_next_component_back();
815 if comp.is_some() {
816 return;
817 } else {
92a42be0 818 self.path = &self.path[..self.path.len() - size];
85aaf69f
SL
819 }
820 }
821 }
85aaf69f
SL
822}
823
c34b1796
AL
824#[stable(feature = "rust1", since = "1.0.0")]
825impl<'a> AsRef<Path> for Components<'a> {
826 fn as_ref(&self) -> &Path {
827 self.as_path()
828 }
829}
830
831#[stable(feature = "rust1", since = "1.0.0")]
832impl<'a> AsRef<OsStr> for Components<'a> {
833 fn as_ref(&self) -> &OsStr {
834 self.as_path().as_os_str()
835 }
836}
837
9e0c209e
SL
838#[stable(feature = "path_iter_debug", since = "1.13.0")]
839impl<'a> fmt::Debug for Iter<'a> {
840 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
841 struct DebugHelper<'a>(&'a Path);
842
843 impl<'a> fmt::Debug for DebugHelper<'a> {
844 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
845 f.debug_list()
846 .entries(self.0.iter())
847 .finish()
848 }
849 }
850
851 f.debug_tuple("Iter")
852 .field(&DebugHelper(self.as_path()))
853 .finish()
854 }
855}
856
85aaf69f 857impl<'a> Iter<'a> {
9346a6ac 858 /// Extracts a slice corresponding to the portion of the path remaining for iteration.
cc61c64b
XL
859 ///
860 /// # Examples
861 ///
862 /// ```
863 /// use std::path::Path;
864 ///
865 /// let mut iter = Path::new("/tmp/foo/bar.txt").iter();
866 /// iter.next();
867 /// iter.next();
868 ///
869 /// assert_eq!(Path::new("foo/bar.txt"), iter.as_path());
870 /// ```
c34b1796 871 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
872 pub fn as_path(&self) -> &'a Path {
873 self.inner.as_path()
874 }
875}
876
c34b1796
AL
877#[stable(feature = "rust1", since = "1.0.0")]
878impl<'a> AsRef<Path> for Iter<'a> {
879 fn as_ref(&self) -> &Path {
880 self.as_path()
881 }
882}
883
884#[stable(feature = "rust1", since = "1.0.0")]
885impl<'a> AsRef<OsStr> for Iter<'a> {
886 fn as_ref(&self) -> &OsStr {
887 self.as_path().as_os_str()
888 }
889}
890
891#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
892impl<'a> Iterator for Iter<'a> {
893 type Item = &'a OsStr;
894
895 fn next(&mut self) -> Option<&'a OsStr> {
896 self.inner.next().map(Component::as_os_str)
897 }
898}
899
c34b1796 900#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
901impl<'a> DoubleEndedIterator for Iter<'a> {
902 fn next_back(&mut self) -> Option<&'a OsStr> {
903 self.inner.next_back().map(Component::as_os_str)
904 }
905}
906
0531ce1d 907#[stable(feature = "fused", since = "1.26.0")]
9e0c209e
SL
908impl<'a> FusedIterator for Iter<'a> {}
909
c34b1796 910#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
911impl<'a> Iterator for Components<'a> {
912 type Item = Component<'a>;
913
914 fn next(&mut self) -> Option<Component<'a>> {
915 while !self.finished() {
916 match self.front {
917 State::Prefix if self.prefix_len() > 0 => {
c34b1796 918 self.front = State::StartDir;
85aaf69f 919 debug_assert!(self.prefix_len() <= self.path.len());
92a42be0
SL
920 let raw = &self.path[..self.prefix_len()];
921 self.path = &self.path[self.prefix_len()..];
c34b1796 922 return Some(Component::Prefix(PrefixComponent {
85aaf69f 923 raw: unsafe { u8_slice_as_os_str(raw) },
92a42be0
SL
924 parsed: self.prefix.unwrap(),
925 }));
85aaf69f
SL
926 }
927 State::Prefix => {
c34b1796 928 self.front = State::StartDir;
85aaf69f 929 }
c34b1796 930 State::StartDir => {
85aaf69f
SL
931 self.front = State::Body;
932 if self.has_physical_root {
9346a6ac 933 debug_assert!(!self.path.is_empty());
85aaf69f 934 self.path = &self.path[1..];
92a42be0 935 return Some(Component::RootDir);
85aaf69f
SL
936 } else if let Some(p) = self.prefix {
937 if p.has_implicit_root() && !p.is_verbatim() {
92a42be0 938 return Some(Component::RootDir);
85aaf69f 939 }
c34b1796 940 } else if self.include_cur_dir() {
9346a6ac 941 debug_assert!(!self.path.is_empty());
c34b1796 942 self.path = &self.path[1..];
92a42be0 943 return Some(Component::CurDir);
85aaf69f
SL
944 }
945 }
946 State::Body if !self.path.is_empty() => {
947 let (size, comp) = self.parse_next_component();
92a42be0
SL
948 self.path = &self.path[size..];
949 if comp.is_some() {
950 return comp;
951 }
85aaf69f
SL
952 }
953 State::Body => {
85aaf69f 954 self.front = State::Done;
85aaf69f 955 }
92a42be0 956 State::Done => unreachable!(),
85aaf69f
SL
957 }
958 }
959 None
960 }
961}
962
c34b1796 963#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
964impl<'a> DoubleEndedIterator for Components<'a> {
965 fn next_back(&mut self) -> Option<Component<'a>> {
966 while !self.finished() {
967 match self.back {
c34b1796 968 State::Body if self.path.len() > self.len_before_body() => {
85aaf69f 969 let (size, comp) = self.parse_next_component_back();
92a42be0
SL
970 self.path = &self.path[..self.path.len() - size];
971 if comp.is_some() {
972 return comp;
973 }
85aaf69f
SL
974 }
975 State::Body => {
c34b1796 976 self.back = State::StartDir;
85aaf69f 977 }
c34b1796 978 State::StartDir => {
85aaf69f
SL
979 self.back = State::Prefix;
980 if self.has_physical_root {
92a42be0
SL
981 self.path = &self.path[..self.path.len() - 1];
982 return Some(Component::RootDir);
85aaf69f
SL
983 } else if let Some(p) = self.prefix {
984 if p.has_implicit_root() && !p.is_verbatim() {
92a42be0 985 return Some(Component::RootDir);
85aaf69f 986 }
c34b1796 987 } else if self.include_cur_dir() {
92a42be0
SL
988 self.path = &self.path[..self.path.len() - 1];
989 return Some(Component::CurDir);
85aaf69f
SL
990 }
991 }
992 State::Prefix if self.prefix_len() > 0 => {
993 self.back = State::Done;
c34b1796 994 return Some(Component::Prefix(PrefixComponent {
85aaf69f 995 raw: unsafe { u8_slice_as_os_str(self.path) },
92a42be0
SL
996 parsed: self.prefix.unwrap(),
997 }));
85aaf69f
SL
998 }
999 State::Prefix => {
1000 self.back = State::Done;
92a42be0 1001 return None;
85aaf69f 1002 }
92a42be0 1003 State::Done => unreachable!(),
85aaf69f
SL
1004 }
1005 }
1006 None
1007 }
1008}
1009
0531ce1d 1010#[stable(feature = "fused", since = "1.26.0")]
9e0c209e
SL
1011impl<'a> FusedIterator for Components<'a> {}
1012
c34b1796 1013#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1014impl<'a> cmp::PartialEq for Components<'a> {
1015 fn eq(&self, other: &Components<'a>) -> bool {
e9174d1e 1016 Iterator::eq(self.clone(), other.clone())
85aaf69f
SL
1017 }
1018}
1019
c34b1796 1020#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1021impl<'a> cmp::Eq for Components<'a> {}
1022
c34b1796 1023#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1024impl<'a> cmp::PartialOrd for Components<'a> {
1025 fn partial_cmp(&self, other: &Components<'a>) -> Option<cmp::Ordering> {
e9174d1e 1026 Iterator::partial_cmp(self.clone(), other.clone())
85aaf69f
SL
1027 }
1028}
1029
c34b1796 1030#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1031impl<'a> cmp::Ord for Components<'a> {
1032 fn cmp(&self, other: &Components<'a>) -> cmp::Ordering {
e9174d1e 1033 Iterator::cmp(self.clone(), other.clone())
85aaf69f
SL
1034 }
1035}
1036
0531ce1d
XL
1037/// An iterator over [`Path`] and its ancestors.
1038///
1039/// This `struct` is created by the [`ancestors`] method on [`Path`].
1040/// See its documentation for more.
1041///
1042/// # Examples
1043///
1044/// ```
0531ce1d
XL
1045/// use std::path::Path;
1046///
1047/// let path = Path::new("/foo/bar");
1048///
1049/// for ancestor in path.ancestors() {
1050/// println!("{}", ancestor.display());
1051/// }
1052/// ```
1053///
1054/// [`ancestors`]: struct.Path.html#method.ancestors
1055/// [`Path`]: struct.Path.html
1056#[derive(Copy, Clone, Debug)]
94b46f34 1057#[stable(feature = "path_ancestors", since = "1.28.0")]
0531ce1d
XL
1058pub struct Ancestors<'a> {
1059 next: Option<&'a Path>,
1060}
1061
94b46f34 1062#[stable(feature = "path_ancestors", since = "1.28.0")]
0531ce1d
XL
1063impl<'a> Iterator for Ancestors<'a> {
1064 type Item = &'a Path;
1065
1066 fn next(&mut self) -> Option<Self::Item> {
1067 let next = self.next;
1068 self.next = match next {
1069 Some(path) => path.parent(),
1070 None => None,
1071 };
1072 next
1073 }
1074}
1075
94b46f34 1076#[stable(feature = "path_ancestors", since = "1.28.0")]
0531ce1d
XL
1077impl<'a> FusedIterator for Ancestors<'a> {}
1078
85aaf69f
SL
1079////////////////////////////////////////////////////////////////////////////////
1080// Basic types and traits
1081////////////////////////////////////////////////////////////////////////////////
1082
9e0c209e
SL
1083/// An owned, mutable path (akin to [`String`]).
1084///
1085/// This type provides methods like [`push`] and [`set_extension`] that mutate
1086/// the path in place. It also implements [`Deref`] to [`Path`], meaning that
1087/// all methods on [`Path`] slices are available on `PathBuf` values as well.
85aaf69f 1088///
9e0c209e
SL
1089/// [`String`]: ../string/struct.String.html
1090/// [`Path`]: struct.Path.html
1091/// [`push`]: struct.PathBuf.html#method.push
1092/// [`set_extension`]: struct.PathBuf.html#method.set_extension
c30ab7b3 1093/// [`Deref`]: ../ops/trait.Deref.html
85aaf69f
SL
1094///
1095/// More details about the overall approach can be found in
041b39d2 1096/// the [module documentation](index.html).
85aaf69f 1097///
c34b1796 1098/// # Examples
85aaf69f 1099///
7cac9316
XL
1100/// You can use [`push`] to build up a `PathBuf` from
1101/// components:
1102///
c34b1796 1103/// ```
85aaf69f
SL
1104/// use std::path::PathBuf;
1105///
7cac9316
XL
1106/// let mut path = PathBuf::new();
1107///
1108/// path.push(r"C:\");
85aaf69f
SL
1109/// path.push("windows");
1110/// path.push("system32");
7cac9316 1111///
85aaf69f
SL
1112/// path.set_extension("dll");
1113/// ```
7cac9316
XL
1114///
1115/// However, [`push`] is best used for dynamic situations. This is a better way
1116/// to do this when you know all of the components ahead of time:
1117///
1118/// ```
1119/// use std::path::PathBuf;
1120///
1121/// let path: PathBuf = [r"C:\", "windows", "system32.dll"].iter().collect();
1122/// ```
1123///
1124/// We can still do better than this! Since these are all strings, we can use
1125/// `From::from`:
1126///
1127/// ```
1128/// use std::path::PathBuf;
1129///
1130/// let path = PathBuf::from(r"C:\windows\system32.dll");
1131/// ```
1132///
1133/// Which method works best depends on what kind of situation you're in.
92a42be0 1134#[derive(Clone)]
c34b1796 1135#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1136pub struct PathBuf {
92a42be0 1137 inner: OsString,
85aaf69f
SL
1138}
1139
1140impl PathBuf {
1141 fn as_mut_vec(&mut self) -> &mut Vec<u8> {
e9174d1e 1142 unsafe { &mut *(self as *mut PathBuf as *mut Vec<u8>) }
85aaf69f
SL
1143 }
1144
9346a6ac 1145 /// Allocates an empty `PathBuf`.
9e0c209e
SL
1146 ///
1147 /// # Examples
1148 ///
1149 /// ```
1150 /// use std::path::PathBuf;
1151 ///
1152 /// let path = PathBuf::new();
1153 /// ```
c34b1796
AL
1154 #[stable(feature = "rust1", since = "1.0.0")]
1155 pub fn new() -> PathBuf {
1156 PathBuf { inner: OsString::new() }
1157 }
1158
9e0c209e
SL
1159 /// Coerces to a [`Path`] slice.
1160 ///
1161 /// [`Path`]: struct.Path.html
1162 ///
1163 /// # Examples
1164 ///
1165 /// ```
1166 /// use std::path::{Path, PathBuf};
1167 ///
1168 /// let p = PathBuf::from("/test");
1169 /// assert_eq!(Path::new("/test"), p.as_path());
1170 /// ```
c34b1796
AL
1171 #[stable(feature = "rust1", since = "1.0.0")]
1172 pub fn as_path(&self) -> &Path {
1173 self
85aaf69f
SL
1174 }
1175
9346a6ac 1176 /// Extends `self` with `path`.
85aaf69f
SL
1177 ///
1178 /// If `path` is absolute, it replaces the current path.
1179 ///
1180 /// On Windows:
1181 ///
1182 /// * if `path` has a root but no prefix (e.g. `\windows`), it
1183 /// replaces everything except for the prefix (if any) of `self`.
e9174d1e 1184 /// * if `path` has a prefix but no root, it replaces `self`.
92a42be0
SL
1185 ///
1186 /// # Examples
1187 ///
476ff2be
SL
1188 /// Pushing a relative path extends the existing path:
1189 ///
92a42be0
SL
1190 /// ```
1191 /// use std::path::PathBuf;
1192 ///
476ff2be 1193 /// let mut path = PathBuf::from("/tmp");
92a42be0
SL
1194 /// path.push("file.bk");
1195 /// assert_eq!(path, PathBuf::from("/tmp/file.bk"));
476ff2be
SL
1196 /// ```
1197 ///
1198 /// Pushing an absolute path replaces the existing path:
1199 ///
1200 /// ```
1201 /// use std::path::PathBuf;
92a42be0 1202 ///
476ff2be
SL
1203 /// let mut path = PathBuf::from("/tmp");
1204 /// path.push("/etc");
1205 /// assert_eq!(path, PathBuf::from("/etc"));
92a42be0 1206 /// ```
c34b1796
AL
1207 #[stable(feature = "rust1", since = "1.0.0")]
1208 pub fn push<P: AsRef<Path>>(&mut self, path: P) {
e9174d1e
SL
1209 self._push(path.as_ref())
1210 }
c34b1796 1211
e9174d1e 1212 fn _push(&mut self, path: &Path) {
85aaf69f
SL
1213 // in general, a separator is needed if the rightmost byte is not a separator
1214 let mut need_sep = self.as_mut_vec().last().map(|c| !is_sep_byte(*c)).unwrap_or(false);
1215
1216 // in the special case of `C:` on Windows, do *not* add a separator
1217 {
1218 let comps = self.components();
92a42be0
SL
1219 if comps.prefix_len() > 0 && comps.prefix_len() == comps.path.len() &&
1220 comps.prefix.unwrap().is_drive() {
85aaf69f
SL
1221 need_sep = false
1222 }
1223 }
1224
85aaf69f
SL
1225 // absolute `path` replaces `self`
1226 if path.is_absolute() || path.prefix().is_some() {
1227 self.as_mut_vec().truncate(0);
1228
1229 // `path` has a root but no prefix, e.g. `\windows` (Windows only)
1230 } else if path.has_root() {
1231 let prefix_len = self.components().prefix_remaining();
1232 self.as_mut_vec().truncate(prefix_len);
1233
1234 // `path` is a pure relative path
1235 } else if need_sep {
c34b1796 1236 self.inner.push(MAIN_SEP_STR);
85aaf69f
SL
1237 }
1238
c34b1796 1239 self.inner.push(path);
85aaf69f
SL
1240 }
1241
041b39d2 1242 /// Truncates `self` to [`self.parent`].
85aaf69f 1243 ///
cc61c64b 1244 /// Returns `false` and does nothing if [`self.file_name`] is [`None`].
85aaf69f 1245 /// Otherwise, returns `true`.
9e0c209e 1246 ///
cc61c64b
XL
1247 /// [`None`]: ../../std/option/enum.Option.html#variant.None
1248 /// [`self.parent`]: struct.PathBuf.html#method.parent
1249 /// [`self.file_name`]: struct.PathBuf.html#method.file_name
9e0c209e
SL
1250 ///
1251 /// # Examples
1252 ///
1253 /// ```
1254 /// use std::path::{Path, PathBuf};
1255 ///
1256 /// let mut p = PathBuf::from("/test/test.rs");
1257 ///
1258 /// p.pop();
1259 /// assert_eq!(Path::new("/test"), p);
1260 /// p.pop();
1261 /// assert_eq!(Path::new("/"), p);
1262 /// ```
c34b1796 1263 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1264 pub fn pop(&mut self) -> bool {
1265 match self.parent().map(|p| p.as_u8_slice().len()) {
1266 Some(len) => {
1267 self.as_mut_vec().truncate(len);
1268 true
1269 }
92a42be0 1270 None => false,
85aaf69f
SL
1271 }
1272 }
1273
cc61c64b 1274 /// Updates [`self.file_name`] to `file_name`.
85aaf69f 1275 ///
cc61c64b 1276 /// If [`self.file_name`] was [`None`], this is equivalent to pushing
85aaf69f
SL
1277 /// `file_name`.
1278 ///
cc61c64b
XL
1279 /// Otherwise it is equivalent to calling [`pop`] and then pushing
1280 /// `file_name`. The new path will be a sibling of the original path.
1281 /// (That is, it will have the same parent.)
1282 ///
1283 /// [`self.file_name`]: struct.PathBuf.html#method.file_name
32a655c1 1284 /// [`None`]: ../../std/option/enum.Option.html#variant.None
cc61c64b 1285 /// [`pop`]: struct.PathBuf.html#method.pop
9e0c209e 1286 ///
85aaf69f
SL
1287 /// # Examples
1288 ///
c34b1796
AL
1289 /// ```
1290 /// use std::path::PathBuf;
85aaf69f 1291 ///
c34b1796 1292 /// let mut buf = PathBuf::from("/");
85aaf69f
SL
1293 /// assert!(buf.file_name() == None);
1294 /// buf.set_file_name("bar");
c34b1796 1295 /// assert!(buf == PathBuf::from("/bar"));
85aaf69f
SL
1296 /// assert!(buf.file_name().is_some());
1297 /// buf.set_file_name("baz.txt");
c34b1796 1298 /// assert!(buf == PathBuf::from("/baz.txt"));
85aaf69f 1299 /// ```
c34b1796
AL
1300 #[stable(feature = "rust1", since = "1.0.0")]
1301 pub fn set_file_name<S: AsRef<OsStr>>(&mut self, file_name: S) {
e9174d1e
SL
1302 self._set_file_name(file_name.as_ref())
1303 }
1304
1305 fn _set_file_name(&mut self, file_name: &OsStr) {
c34b1796
AL
1306 if self.file_name().is_some() {
1307 let popped = self.pop();
1308 debug_assert!(popped);
85aaf69f 1309 }
e9174d1e 1310 self.push(file_name);
85aaf69f
SL
1311 }
1312
cc61c64b 1313 /// Updates [`self.extension`] to `extension`.
9e0c209e 1314 ///
cc61c64b
XL
1315 /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
1316 /// returns `true` and updates the extension otherwise.
9e0c209e 1317 ///
cc61c64b
XL
1318 /// If [`self.extension`] is [`None`], the extension is added; otherwise
1319 /// it is replaced.
85aaf69f 1320 ///
cc61c64b
XL
1321 /// [`self.file_name`]: struct.PathBuf.html#method.file_name
1322 /// [`self.extension`]: struct.PathBuf.html#method.extension
32a655c1 1323 /// [`None`]: ../../std/option/enum.Option.html#variant.None
85aaf69f 1324 ///
9e0c209e
SL
1325 /// # Examples
1326 ///
1327 /// ```
1328 /// use std::path::{Path, PathBuf};
1329 ///
1330 /// let mut p = PathBuf::from("/feel/the");
1331 ///
1332 /// p.set_extension("force");
1333 /// assert_eq!(Path::new("/feel/the.force"), p.as_path());
1334 ///
1335 /// p.set_extension("dark_side");
1336 /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
1337 /// ```
c34b1796
AL
1338 #[stable(feature = "rust1", since = "1.0.0")]
1339 pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
e9174d1e
SL
1340 self._set_extension(extension.as_ref())
1341 }
1342
1343 fn _set_extension(&mut self, extension: &OsStr) -> bool {
92a42be0
SL
1344 if self.file_name().is_none() {
1345 return false;
1346 }
85aaf69f
SL
1347
1348 let mut stem = match self.file_stem() {
1349 Some(stem) => stem.to_os_string(),
c34b1796 1350 None => OsString::new(),
85aaf69f
SL
1351 };
1352
9346a6ac 1353 if !os_str_as_u8_slice(extension).is_empty() {
c34b1796
AL
1354 stem.push(".");
1355 stem.push(extension);
85aaf69f
SL
1356 }
1357 self.set_file_name(&stem);
1358
1359 true
1360 }
1361
9e0c209e
SL
1362 /// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
1363 ///
1364 /// [`OsString`]: ../ffi/struct.OsString.html
1365 ///
1366 /// # Examples
1367 ///
1368 /// ```
1369 /// use std::path::PathBuf;
1370 ///
1371 /// let p = PathBuf::from("/the/head");
1372 /// let os_str = p.into_os_string();
1373 /// ```
c34b1796 1374 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1375 pub fn into_os_string(self) -> OsString {
1376 self.inner
1377 }
8bb4bdeb 1378
cc61c64b
XL
1379 /// Converts this `PathBuf` into a [boxed][`Box`] [`Path`].
1380 ///
1381 /// [`Box`]: ../../std/boxed/struct.Box.html
1382 /// [`Path`]: struct.Path.html
041b39d2 1383 #[stable(feature = "into_boxed_path", since = "1.20.0")]
8bb4bdeb 1384 pub fn into_boxed_path(self) -> Box<Path> {
ea8adc8c
XL
1385 let rw = Box::into_raw(self.inner.into_boxed_os_str()) as *mut Path;
1386 unsafe { Box::from_raw(rw) }
8bb4bdeb
XL
1387 }
1388}
1389
1390#[stable(feature = "box_from_path", since = "1.17.0")]
1391impl<'a> From<&'a Path> for Box<Path> {
1392 fn from(path: &'a Path) -> Box<Path> {
1393 let boxed: Box<OsStr> = path.inner.into();
ea8adc8c
XL
1394 let rw = Box::into_raw(boxed) as *mut Path;
1395 unsafe { Box::from_raw(rw) }
8bb4bdeb 1396 }
85aaf69f
SL
1397}
1398
7cac9316
XL
1399#[stable(feature = "path_buf_from_box", since = "1.18.0")]
1400impl From<Box<Path>> for PathBuf {
cc61c64b
XL
1401 fn from(boxed: Box<Path>) -> PathBuf {
1402 boxed.into_path_buf()
1403 }
1404}
1405
041b39d2
XL
1406#[stable(feature = "box_from_path_buf", since = "1.20.0")]
1407impl From<PathBuf> for Box<Path> {
1408 fn from(p: PathBuf) -> Box<Path> {
1409 p.into_boxed_path()
cc61c64b
XL
1410 }
1411}
1412
c34b1796
AL
1413#[stable(feature = "rust1", since = "1.0.0")]
1414impl<'a, T: ?Sized + AsRef<OsStr>> From<&'a T> for PathBuf {
1415 fn from(s: &'a T) -> PathBuf {
1416 PathBuf::from(s.as_ref().to_os_string())
1417 }
1418}
1419
1420#[stable(feature = "rust1", since = "1.0.0")]
1421impl From<OsString> for PathBuf {
1422 fn from(s: OsString) -> PathBuf {
1423 PathBuf { inner: s }
1424 }
1425}
1426
c30ab7b3
SL
1427#[stable(feature = "from_path_buf_for_os_string", since = "1.14.0")]
1428impl From<PathBuf> for OsString {
1429 fn from(path_buf : PathBuf) -> OsString {
1430 path_buf.inner
1431 }
1432}
1433
c34b1796
AL
1434#[stable(feature = "rust1", since = "1.0.0")]
1435impl From<String> for PathBuf {
1436 fn from(s: String) -> PathBuf {
1437 PathBuf::from(OsString::from(s))
1438 }
1439}
1440
1441#[stable(feature = "rust1", since = "1.0.0")]
1442impl<P: AsRef<Path>> iter::FromIterator<P> for PathBuf {
1443 fn from_iter<I: IntoIterator<Item = P>>(iter: I) -> PathBuf {
1444 let mut buf = PathBuf::new();
85aaf69f
SL
1445 buf.extend(iter);
1446 buf
1447 }
1448}
1449
c34b1796
AL
1450#[stable(feature = "rust1", since = "1.0.0")]
1451impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
1452 fn extend<I: IntoIterator<Item = P>>(&mut self, iter: I) {
85aaf69f 1453 for p in iter {
e9174d1e 1454 self.push(p.as_ref())
85aaf69f
SL
1455 }
1456 }
1457}
1458
c34b1796 1459#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1460impl fmt::Debug for PathBuf {
94b46f34 1461 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
85aaf69f
SL
1462 fmt::Debug::fmt(&**self, formatter)
1463 }
1464}
1465
c34b1796 1466#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1467impl ops::Deref for PathBuf {
1468 type Target = Path;
1469
1470 fn deref(&self) -> &Path {
e9174d1e 1471 Path::new(&self.inner)
85aaf69f
SL
1472 }
1473}
1474
c34b1796 1475#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1476impl Borrow<Path> for PathBuf {
1477 fn borrow(&self) -> &Path {
1478 self.deref()
1479 }
1480}
1481
7cac9316 1482#[stable(feature = "default_for_pathbuf", since = "1.17.0")]
8bb4bdeb
XL
1483impl Default for PathBuf {
1484 fn default() -> Self {
1485 PathBuf::new()
1486 }
1487}
1488
92a42be0
SL
1489#[stable(feature = "cow_from_path", since = "1.6.0")]
1490impl<'a> From<&'a Path> for Cow<'a, Path> {
1491 #[inline]
1492 fn from(s: &'a Path) -> Cow<'a, Path> {
1493 Cow::Borrowed(s)
1494 }
1495}
1496
1497#[stable(feature = "cow_from_path", since = "1.6.0")]
1498impl<'a> From<PathBuf> for Cow<'a, Path> {
1499 #[inline]
1500 fn from(s: PathBuf) -> Cow<'a, Path> {
1501 Cow::Owned(s)
1502 }
1503}
1504
94b46f34
XL
1505#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
1506impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
1507 #[inline]
1508 fn from(p: &'a PathBuf) -> Cow<'a, Path> {
1509 Cow::Borrowed(p.as_path())
1510 }
1511}
1512
1513#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
1514impl<'a> From<Cow<'a, Path>> for PathBuf {
1515 #[inline]
1516 fn from(p: Cow<'a, Path>) -> Self {
1517 p.into_owned()
1518 }
1519}
1520
2c00a5a8 1521#[stable(feature = "shared_from_slice2", since = "1.24.0")]
ff7c6d11
XL
1522impl From<PathBuf> for Arc<Path> {
1523 #[inline]
1524 fn from(s: PathBuf) -> Arc<Path> {
1525 let arc: Arc<OsStr> = Arc::from(s.into_os_string());
1526 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1527 }
1528}
1529
2c00a5a8 1530#[stable(feature = "shared_from_slice2", since = "1.24.0")]
ff7c6d11
XL
1531impl<'a> From<&'a Path> for Arc<Path> {
1532 #[inline]
1533 fn from(s: &Path) -> Arc<Path> {
1534 let arc: Arc<OsStr> = Arc::from(s.as_os_str());
1535 unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
1536 }
1537}
1538
2c00a5a8 1539#[stable(feature = "shared_from_slice2", since = "1.24.0")]
ff7c6d11
XL
1540impl From<PathBuf> for Rc<Path> {
1541 #[inline]
1542 fn from(s: PathBuf) -> Rc<Path> {
1543 let rc: Rc<OsStr> = Rc::from(s.into_os_string());
1544 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1545 }
1546}
1547
2c00a5a8 1548#[stable(feature = "shared_from_slice2", since = "1.24.0")]
ff7c6d11
XL
1549impl<'a> From<&'a Path> for Rc<Path> {
1550 #[inline]
1551 fn from(s: &Path) -> Rc<Path> {
1552 let rc: Rc<OsStr> = Rc::from(s.as_os_str());
1553 unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
1554 }
1555}
1556
c34b1796 1557#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1558impl ToOwned for Path {
1559 type Owned = PathBuf;
92a42be0
SL
1560 fn to_owned(&self) -> PathBuf {
1561 self.to_path_buf()
1562 }
cc61c64b
XL
1563 fn clone_into(&self, target: &mut PathBuf) {
1564 self.inner.clone_into(&mut target.inner);
1565 }
85aaf69f
SL
1566}
1567
c34b1796 1568#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1569impl cmp::PartialEq for PathBuf {
1570 fn eq(&self, other: &PathBuf) -> bool {
1571 self.components() == other.components()
1572 }
1573}
1574
92a42be0
SL
1575#[stable(feature = "rust1", since = "1.0.0")]
1576impl Hash for PathBuf {
1577 fn hash<H: Hasher>(&self, h: &mut H) {
1578 self.as_path().hash(h)
1579 }
1580}
1581
c34b1796 1582#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1583impl cmp::Eq for PathBuf {}
1584
c34b1796 1585#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1586impl cmp::PartialOrd for PathBuf {
1587 fn partial_cmp(&self, other: &PathBuf) -> Option<cmp::Ordering> {
e9174d1e 1588 self.components().partial_cmp(other.components())
85aaf69f
SL
1589 }
1590}
1591
c34b1796 1592#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1593impl cmp::Ord for PathBuf {
1594 fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
e9174d1e 1595 self.components().cmp(other.components())
85aaf69f
SL
1596 }
1597}
1598
c34b1796
AL
1599#[stable(feature = "rust1", since = "1.0.0")]
1600impl AsRef<OsStr> for PathBuf {
1601 fn as_ref(&self) -> &OsStr {
1602 &self.inner[..]
1603 }
1604}
1605
9e0c209e 1606/// A slice of a path (akin to [`str`]).
85aaf69f
SL
1607///
1608/// This type supports a number of operations for inspecting a path, including
041b39d2
XL
1609/// breaking the path into its components (separated by `/` on Unix and by either
1610/// `/` or `\` on Windows), extracting the file name, determining whether the path
1611/// is absolute, and so on.
85aaf69f 1612///
d9579d0f 1613/// This is an *unsized* type, meaning that it must always be used behind a
c30ab7b3
SL
1614/// pointer like `&` or [`Box`]. For an owned version of this type,
1615/// see [`PathBuf`].
9e0c209e
SL
1616///
1617/// [`str`]: ../primitive.str.html
1618/// [`Box`]: ../boxed/struct.Box.html
c30ab7b3
SL
1619/// [`PathBuf`]: struct.PathBuf.html
1620///
1621/// More details about the overall approach can be found in
041b39d2 1622/// the [module documentation](index.html).
85aaf69f 1623///
c34b1796 1624/// # Examples
85aaf69f 1625///
c34b1796 1626/// ```
85aaf69f 1627/// use std::path::Path;
476ff2be 1628/// use std::ffi::OsStr;
85aaf69f 1629///
041b39d2
XL
1630/// // Note: this example does work on Windows
1631/// let path = Path::new("./foo/bar.txt");
476ff2be
SL
1632///
1633/// let parent = path.parent();
041b39d2 1634/// assert_eq!(parent, Some(Path::new("./foo")));
476ff2be
SL
1635///
1636/// let file_stem = path.file_stem();
1637/// assert_eq!(file_stem, Some(OsStr::new("bar")));
1638///
85aaf69f 1639/// let extension = path.extension();
476ff2be 1640/// assert_eq!(extension, Some(OsStr::new("txt")));
85aaf69f 1641/// ```
c34b1796 1642#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1643pub struct Path {
92a42be0 1644 inner: OsStr,
85aaf69f
SL
1645}
1646
cc61c64b
XL
1647/// An error returned from [`Path::strip_prefix`][`strip_prefix`] if the prefix
1648/// was not found.
1649///
1650/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
1651/// See its documentation for more.
32a655c1 1652///
cc61c64b
XL
1653/// [`strip_prefix`]: struct.Path.html#method.strip_prefix
1654/// [`Path`]: struct.Path.html
9cc50fc6
SL
1655#[derive(Debug, Clone, PartialEq, Eq)]
1656#[stable(since = "1.7.0", feature = "strip_prefix")]
1657pub struct StripPrefixError(());
1658
85aaf69f
SL
1659impl Path {
1660 // The following (private!) function allows construction of a path from a u8
1661 // slice, which is only safe when it is known to follow the OsStr encoding.
1662 unsafe fn from_u8_slice(s: &[u8]) -> &Path {
e9174d1e 1663 Path::new(u8_slice_as_os_str(s))
85aaf69f
SL
1664 }
1665 // The following (private!) function reveals the byte encoding used for OsStr.
1666 fn as_u8_slice(&self) -> &[u8] {
e9174d1e 1667 os_str_as_u8_slice(&self.inner)
85aaf69f
SL
1668 }
1669
cc61c64b 1670 /// Directly wraps a string slice as a `Path` slice.
85aaf69f
SL
1671 ///
1672 /// This is a cost-free conversion.
c34b1796
AL
1673 ///
1674 /// # Examples
1675 ///
1676 /// ```
1677 /// use std::path::Path;
1678 ///
1679 /// Path::new("foo.txt");
1680 /// ```
bd371182
AL
1681 ///
1682 /// You can create `Path`s from `String`s, or even other `Path`s:
1683 ///
1684 /// ```
1685 /// use std::path::Path;
1686 ///
62682a34
SL
1687 /// let string = String::from("foo.txt");
1688 /// let from_string = Path::new(&string);
1689 /// let from_path = Path::new(&from_string);
1690 /// assert_eq!(from_string, from_path);
bd371182 1691 /// ```
c34b1796
AL
1692 #[stable(feature = "rust1", since = "1.0.0")]
1693 pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path {
ea8adc8c 1694 unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
c34b1796
AL
1695 }
1696
9e0c209e
SL
1697 /// Yields the underlying [`OsStr`] slice.
1698 ///
1699 /// [`OsStr`]: ../ffi/struct.OsStr.html
c34b1796
AL
1700 ///
1701 /// # Examples
1702 ///
1703 /// ```
1704 /// use std::path::Path;
1705 ///
1706 /// let os_str = Path::new("foo.txt").as_os_str();
62682a34 1707 /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
c34b1796
AL
1708 /// ```
1709 #[stable(feature = "rust1", since = "1.0.0")]
1710 pub fn as_os_str(&self) -> &OsStr {
1711 &self.inner
85aaf69f
SL
1712 }
1713
9e0c209e 1714 /// Yields a [`&str`] slice if the `Path` is valid unicode.
85aaf69f
SL
1715 ///
1716 /// This conversion may entail doing a check for UTF-8 validity.
c34b1796 1717 ///
9e0c209e
SL
1718 /// [`&str`]: ../primitive.str.html
1719 ///
c34b1796
AL
1720 /// # Examples
1721 ///
1722 /// ```
1723 /// use std::path::Path;
1724 ///
32a655c1
SL
1725 /// let path = Path::new("foo.txt");
1726 /// assert_eq!(path.to_str(), Some("foo.txt"));
c34b1796
AL
1727 /// ```
1728 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1729 pub fn to_str(&self) -> Option<&str> {
1730 self.inner.to_str()
1731 }
1732
9e0c209e 1733 /// Converts a `Path` to a [`Cow<str>`].
85aaf69f
SL
1734 ///
1735 /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER.
c34b1796 1736 ///
9e0c209e
SL
1737 /// [`Cow<str>`]: ../borrow/enum.Cow.html
1738 ///
c34b1796
AL
1739 /// # Examples
1740 ///
32a655c1
SL
1741 /// Calling `to_string_lossy` on a `Path` with valid unicode:
1742 ///
c34b1796
AL
1743 /// ```
1744 /// use std::path::Path;
1745 ///
32a655c1
SL
1746 /// let path = Path::new("foo.txt");
1747 /// assert_eq!(path.to_string_lossy(), "foo.txt");
c34b1796 1748 /// ```
32a655c1 1749 ///
cc61c64b 1750 /// Had `path` contained invalid unicode, the `to_string_lossy` call might
32a655c1 1751 /// have returned `"fo�.txt"`.
c34b1796 1752 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1753 pub fn to_string_lossy(&self) -> Cow<str> {
1754 self.inner.to_string_lossy()
1755 }
1756
9e0c209e
SL
1757 /// Converts a `Path` to an owned [`PathBuf`].
1758 ///
1759 /// [`PathBuf`]: struct.PathBuf.html
c34b1796
AL
1760 ///
1761 /// # Examples
1762 ///
1763 /// ```
1764 /// use std::path::Path;
1765 ///
62682a34
SL
1766 /// let path_buf = Path::new("foo.txt").to_path_buf();
1767 /// assert_eq!(path_buf, std::path::PathBuf::from("foo.txt"));
c34b1796 1768 /// ```
2c00a5a8 1769 #[rustc_conversion_suggestion]
c34b1796 1770 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1771 pub fn to_path_buf(&self) -> PathBuf {
c34b1796 1772 PathBuf::from(self.inner.to_os_string())
85aaf69f
SL
1773 }
1774
cc61c64b
XL
1775 /// Returns `true` if the `Path` is absolute, i.e. if it is independent of
1776 /// the current directory.
85aaf69f
SL
1777 ///
1778 /// * On Unix, a path is absolute if it starts with the root, so
cc61c64b 1779 /// `is_absolute` and [`has_root`] are equivalent.
85aaf69f
SL
1780 ///
1781 /// * On Windows, a path is absolute if it has a prefix and starts with the
3157f602 1782 /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
c34b1796
AL
1783 ///
1784 /// # Examples
1785 ///
1786 /// ```
1787 /// use std::path::Path;
1788 ///
62682a34 1789 /// assert!(!Path::new("foo.txt").is_absolute());
c34b1796 1790 /// ```
cc61c64b
XL
1791 ///
1792 /// [`has_root`]: #method.has_root
c34b1796 1793 #[stable(feature = "rust1", since = "1.0.0")]
9cc50fc6 1794 #[allow(deprecated)]
85aaf69f 1795 pub fn is_absolute(&self) -> bool {
abe05a73 1796 if cfg!(target_os = "redox") {
3b2f2976 1797 // FIXME: Allow Redox prefixes
abe05a73
XL
1798 self.has_root() || has_redox_scheme(self.as_u8_slice())
1799 } else {
1800 self.has_root() && (cfg!(unix) || self.prefix().is_some())
3b2f2976 1801 }
85aaf69f
SL
1802 }
1803
041b39d2 1804 /// Returns `true` if the `Path` is relative, i.e. not absolute.
cc61c64b
XL
1805 ///
1806 /// See [`is_absolute`]'s documentation for more details.
c34b1796
AL
1807 ///
1808 /// # Examples
1809 ///
1810 /// ```
1811 /// use std::path::Path;
1812 ///
1813 /// assert!(Path::new("foo.txt").is_relative());
1814 /// ```
cc61c64b
XL
1815 ///
1816 /// [`is_absolute`]: #method.is_absolute
c34b1796 1817 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1818 pub fn is_relative(&self) -> bool {
1819 !self.is_absolute()
1820 }
1821
54a0048b 1822 fn prefix(&self) -> Option<Prefix> {
c34b1796 1823 self.components().prefix
85aaf69f
SL
1824 }
1825
cc61c64b 1826 /// Returns `true` if the `Path` has a root.
85aaf69f
SL
1827 ///
1828 /// * On Unix, a path has a root if it begins with `/`.
1829 ///
1830 /// * On Windows, a path has a root if it:
1831 /// * has no prefix and begins with a separator, e.g. `\\windows`
1832 /// * has a prefix followed by a separator, e.g. `c:\windows` but not `c:windows`
1833 /// * has any non-disk prefix, e.g. `\\server\share`
c34b1796
AL
1834 ///
1835 /// # Examples
1836 ///
1837 /// ```
1838 /// use std::path::Path;
1839 ///
1840 /// assert!(Path::new("/etc/passwd").has_root());
1841 /// ```
1842 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1843 pub fn has_root(&self) -> bool {
92a42be0 1844 self.components().has_root()
85aaf69f
SL
1845 }
1846
cc61c64b 1847 /// Returns the `Path` without its final component, if there is one.
85aaf69f 1848 ///
32a655c1
SL
1849 /// Returns [`None`] if the path terminates in a root or prefix.
1850 ///
1851 /// [`None`]: ../../std/option/enum.Option.html#variant.None
85aaf69f
SL
1852 ///
1853 /// # Examples
1854 ///
c34b1796 1855 /// ```
85aaf69f
SL
1856 /// use std::path::Path;
1857 ///
1858 /// let path = Path::new("/foo/bar");
62682a34
SL
1859 /// let parent = path.parent().unwrap();
1860 /// assert_eq!(parent, Path::new("/foo"));
c34b1796 1861 ///
62682a34
SL
1862 /// let grand_parent = parent.parent().unwrap();
1863 /// assert_eq!(grand_parent, Path::new("/"));
1864 /// assert_eq!(grand_parent.parent(), None);
85aaf69f 1865 /// ```
c34b1796 1866 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
1867 pub fn parent(&self) -> Option<&Path> {
1868 let mut comps = self.components();
1869 let comp = comps.next_back();
92a42be0
SL
1870 comp.and_then(|p| {
1871 match p {
1872 Component::Normal(_) |
1873 Component::CurDir |
1874 Component::ParentDir => Some(comps.as_path()),
1875 _ => None,
1876 }
c34b1796 1877 })
85aaf69f
SL
1878 }
1879
0531ce1d
XL
1880 /// Produces an iterator over `Path` and its ancestors.
1881 ///
1882 /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
1883 /// or more times. That means, the iterator will yield `&self`, `&self.parent().unwrap()`,
1884 /// `&self.parent().unwrap().parent().unwrap()` and so on. If the [`parent`] method returns
1885 /// [`None`], the iterator will do likewise. The iterator will always yield at least one value,
1886 /// namely `&self`.
1887 ///
1888 /// # Examples
1889 ///
1890 /// ```
0531ce1d
XL
1891 /// use std::path::Path;
1892 ///
1893 /// let mut ancestors = Path::new("/foo/bar").ancestors();
1894 /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
1895 /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
1896 /// assert_eq!(ancestors.next(), Some(Path::new("/")));
1897 /// assert_eq!(ancestors.next(), None);
1898 /// ```
1899 ///
1900 /// [`None`]: ../../std/option/enum.Option.html#variant.None
1901 /// [`parent`]: struct.Path.html#method.parent
94b46f34 1902 #[stable(feature = "path_ancestors", since = "1.28.0")]
0531ce1d
XL
1903 pub fn ancestors(&self) -> Ancestors {
1904 Ancestors {
1905 next: Some(&self),
1906 }
1907 }
1908
cc61c64b 1909 /// Returns the final component of the `Path`, if there is one.
85aaf69f 1910 ///
cc61c64b
XL
1911 /// If the path is a normal file, this is the file name. If it's the path of a directory, this
1912 /// is the directory name.
1913 ///
0531ce1d 1914 /// Returns [`None`] if the path terminates in `..`.
32a655c1
SL
1915 ///
1916 /// [`None`]: ../../std/option/enum.Option.html#variant.None
c34b1796
AL
1917 ///
1918 /// # Examples
1919 ///
1920 /// ```
1921 /// use std::path::Path;
62682a34 1922 /// use std::ffi::OsStr;
c34b1796 1923 ///
cc61c64b
XL
1924 /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
1925 /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
5bcae85e
SL
1926 /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
1927 /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
1928 /// assert_eq!(None, Path::new("foo.txt/..").file_name());
cc61c64b 1929 /// assert_eq!(None, Path::new("/").file_name());
5bcae85e 1930 /// ```
c34b1796 1931 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 1932 pub fn file_name(&self) -> Option<&OsStr> {
92a42be0
SL
1933 self.components().next_back().and_then(|p| {
1934 match p {
1935 Component::Normal(p) => Some(p.as_ref()),
1936 _ => None,
1937 }
85aaf69f
SL
1938 })
1939 }
1940
9cc50fc6
SL
1941 /// Returns a path that, when joined onto `base`, yields `self`.
1942 ///
7453a54e
SL
1943 /// # Errors
1944 ///
32a655c1
SL
1945 /// If `base` is not a prefix of `self` (i.e. [`starts_with`]
1946 /// returns `false`), returns [`Err`].
1947 ///
1948 /// [`starts_with`]: #method.starts_with
1949 /// [`Err`]: ../../std/result/enum.Result.html#variant.Err
9e0c209e
SL
1950 ///
1951 /// # Examples
1952 ///
1953 /// ```
83c7162d 1954 /// use std::path::{Path, PathBuf};
9e0c209e
SL
1955 ///
1956 /// let path = Path::new("/test/haha/foo.txt");
1957 ///
2c00a5a8 1958 /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
9e0c209e 1959 /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
2c00a5a8
XL
1960 /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
1961 /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
1962 /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
9e0c209e
SL
1963 /// assert_eq!(path.strip_prefix("test").is_ok(), false);
1964 /// assert_eq!(path.strip_prefix("/haha").is_ok(), false);
83c7162d
XL
1965 ///
1966 /// let prefix = PathBuf::from("/test/");
1967 /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
9e0c209e 1968 /// ```
9cc50fc6 1969 #[stable(since = "1.7.0", feature = "path_strip_prefix")]
83c7162d
XL
1970 pub fn strip_prefix<P>(&self, base: P)
1971 -> Result<&Path, StripPrefixError>
9cc50fc6
SL
1972 where P: AsRef<Path>
1973 {
1974 self._strip_prefix(base.as_ref())
e9174d1e
SL
1975 }
1976
83c7162d
XL
1977 fn _strip_prefix(&self, base: &Path)
1978 -> Result<&Path, StripPrefixError> {
9cc50fc6
SL
1979 iter_after(self.components(), base.components())
1980 .map(|c| c.as_path())
1981 .ok_or(StripPrefixError(()))
85aaf69f
SL
1982 }
1983
1984 /// Determines whether `base` is a prefix of `self`.
c34b1796 1985 ///
d9579d0f
AL
1986 /// Only considers whole path components to match.
1987 ///
c34b1796
AL
1988 /// # Examples
1989 ///
1990 /// ```
1991 /// use std::path::Path;
1992 ///
1993 /// let path = Path::new("/etc/passwd");
1994 ///
1995 /// assert!(path.starts_with("/etc"));
2c00a5a8
XL
1996 /// assert!(path.starts_with("/etc/"));
1997 /// assert!(path.starts_with("/etc/passwd"));
1998 /// assert!(path.starts_with("/etc/passwd/"));
d9579d0f
AL
1999 ///
2000 /// assert!(!path.starts_with("/e"));
c34b1796
AL
2001 /// ```
2002 #[stable(feature = "rust1", since = "1.0.0")]
2003 pub fn starts_with<P: AsRef<Path>>(&self, base: P) -> bool {
e9174d1e
SL
2004 self._starts_with(base.as_ref())
2005 }
2006
2007 fn _starts_with(&self, base: &Path) -> bool {
2008 iter_after(self.components(), base.components()).is_some()
85aaf69f
SL
2009 }
2010
c34b1796
AL
2011 /// Determines whether `child` is a suffix of `self`.
2012 ///
d9579d0f
AL
2013 /// Only considers whole path components to match.
2014 ///
c34b1796
AL
2015 /// # Examples
2016 ///
2017 /// ```
2018 /// use std::path::Path;
2019 ///
2020 /// let path = Path::new("/etc/passwd");
2021 ///
2022 /// assert!(path.ends_with("passwd"));
2023 /// ```
2024 #[stable(feature = "rust1", since = "1.0.0")]
2025 pub fn ends_with<P: AsRef<Path>>(&self, child: P) -> bool {
e9174d1e
SL
2026 self._ends_with(child.as_ref())
2027 }
2028
2029 fn _ends_with(&self, child: &Path) -> bool {
2030 iter_after(self.components().rev(), child.components().rev()).is_some()
85aaf69f
SL
2031 }
2032
cc61c64b 2033 /// Extracts the stem (non-extension) portion of [`self.file_name`].
9e0c209e 2034 ///
cc61c64b 2035 /// [`self.file_name`]: struct.Path.html#method.file_name
85aaf69f
SL
2036 ///
2037 /// The stem is:
2038 ///
32a655c1 2039 /// * [`None`], if there is no file name;
85aaf69f
SL
2040 /// * The entire file name if there is no embedded `.`;
2041 /// * The entire file name if the file name begins with `.` and has no other `.`s within;
2042 /// * Otherwise, the portion of the file name before the final `.`
c34b1796 2043 ///
32a655c1
SL
2044 /// [`None`]: ../../std/option/enum.Option.html#variant.None
2045 ///
c34b1796
AL
2046 /// # Examples
2047 ///
2048 /// ```
2049 /// use std::path::Path;
2050 ///
2051 /// let path = Path::new("foo.rs");
2052 ///
2053 /// assert_eq!("foo", path.file_stem().unwrap());
2054 /// ```
2055 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2056 pub fn file_stem(&self) -> Option<&OsStr> {
2057 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.or(after))
2058 }
2059
cc61c64b 2060 /// Extracts the extension of [`self.file_name`], if possible.
9e0c209e 2061 ///
85aaf69f
SL
2062 /// The extension is:
2063 ///
32a655c1
SL
2064 /// * [`None`], if there is no file name;
2065 /// * [`None`], if there is no embedded `.`;
2066 /// * [`None`], if the file name begins with `.` and has no other `.`s within;
85aaf69f 2067 /// * Otherwise, the portion of the file name after the final `.`
c34b1796 2068 ///
cc61c64b 2069 /// [`self.file_name`]: struct.Path.html#method.file_name
32a655c1
SL
2070 /// [`None`]: ../../std/option/enum.Option.html#variant.None
2071 ///
c34b1796
AL
2072 /// # Examples
2073 ///
2074 /// ```
2075 /// use std::path::Path;
2076 ///
2077 /// let path = Path::new("foo.rs");
2078 ///
2079 /// assert_eq!("rs", path.extension().unwrap());
2080 /// ```
2081 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2082 pub fn extension(&self) -> Option<&OsStr> {
2083 self.file_name().map(split_file_at_dot).and_then(|(before, after)| before.and(after))
2084 }
2085
9e0c209e
SL
2086 /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
2087 ///
2088 /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
85aaf69f 2089 ///
9e0c209e
SL
2090 /// [`PathBuf`]: struct.PathBuf.html
2091 /// [`PathBuf::push`]: struct.PathBuf.html#method.push
c34b1796
AL
2092 ///
2093 /// # Examples
2094 ///
2095 /// ```
62682a34 2096 /// use std::path::{Path, PathBuf};
c34b1796 2097 ///
62682a34 2098 /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
c34b1796
AL
2099 /// ```
2100 #[stable(feature = "rust1", since = "1.0.0")]
2101 pub fn join<P: AsRef<Path>>(&self, path: P) -> PathBuf {
e9174d1e
SL
2102 self._join(path.as_ref())
2103 }
2104
2105 fn _join(&self, path: &Path) -> PathBuf {
85aaf69f
SL
2106 let mut buf = self.to_path_buf();
2107 buf.push(path);
2108 buf
2109 }
2110
9e0c209e
SL
2111 /// Creates an owned [`PathBuf`] like `self` but with the given file name.
2112 ///
2113 /// See [`PathBuf::set_file_name`] for more details.
85aaf69f 2114 ///
9e0c209e
SL
2115 /// [`PathBuf`]: struct.PathBuf.html
2116 /// [`PathBuf::set_file_name`]: struct.PathBuf.html#method.set_file_name
c34b1796
AL
2117 ///
2118 /// # Examples
2119 ///
2120 /// ```
62682a34 2121 /// use std::path::{Path, PathBuf};
c34b1796 2122 ///
62682a34
SL
2123 /// let path = Path::new("/tmp/foo.txt");
2124 /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
cc61c64b
XL
2125 ///
2126 /// let path = Path::new("/tmp");
2127 /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
c34b1796
AL
2128 /// ```
2129 #[stable(feature = "rust1", since = "1.0.0")]
2130 pub fn with_file_name<S: AsRef<OsStr>>(&self, file_name: S) -> PathBuf {
e9174d1e
SL
2131 self._with_file_name(file_name.as_ref())
2132 }
2133
2134 fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
85aaf69f
SL
2135 let mut buf = self.to_path_buf();
2136 buf.set_file_name(file_name);
2137 buf
2138 }
2139
9e0c209e 2140 /// Creates an owned [`PathBuf`] like `self` but with the given extension.
85aaf69f 2141 ///
9e0c209e
SL
2142 /// See [`PathBuf::set_extension`] for more details.
2143 ///
2144 /// [`PathBuf`]: struct.PathBuf.html
2145 /// [`PathBuf::set_extension`]: struct.PathBuf.html#method.set_extension
c34b1796
AL
2146 ///
2147 /// # Examples
2148 ///
2149 /// ```
9346a6ac 2150 /// use std::path::{Path, PathBuf};
c34b1796 2151 ///
62682a34
SL
2152 /// let path = Path::new("foo.rs");
2153 /// assert_eq!(path.with_extension("txt"), PathBuf::from("foo.txt"));
c34b1796
AL
2154 /// ```
2155 #[stable(feature = "rust1", since = "1.0.0")]
2156 pub fn with_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
e9174d1e
SL
2157 self._with_extension(extension.as_ref())
2158 }
2159
2160 fn _with_extension(&self, extension: &OsStr) -> PathBuf {
85aaf69f
SL
2161 let mut buf = self.to_path_buf();
2162 buf.set_extension(extension);
2163 buf
2164 }
2165
cc61c64b
XL
2166 /// Produces an iterator over the [`Component`]s of the path.
2167 ///
2168 /// When parsing the path, there is a small amount of normalization:
2169 ///
2170 /// * Repeated separators are ignored, so `a/b` and `a//b` both have
2171 /// `a` and `b` as components.
2172 ///
3b2f2976 2173 /// * Occurrences of `.` are normalized away, except if they are at the
cc61c64b
XL
2174 /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
2175 /// `a/b` all have `a` and `b` as components, but `./a/b` starts with
2176 /// an additional [`CurDir`] component.
2177 ///
2178 /// Note that no other normalization takes place; in particular, `a/c`
2179 /// and `a/b/../c` are distinct, to account for the possibility that `b`
2180 /// is a symbolic link (so its parent isn't `a`).
c34b1796
AL
2181 ///
2182 /// # Examples
2183 ///
2184 /// ```
62682a34
SL
2185 /// use std::path::{Path, Component};
2186 /// use std::ffi::OsStr;
c34b1796 2187 ///
62682a34 2188 /// let mut components = Path::new("/tmp/foo.txt").components();
c34b1796 2189 ///
62682a34
SL
2190 /// assert_eq!(components.next(), Some(Component::RootDir));
2191 /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
2192 /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
2193 /// assert_eq!(components.next(), None)
c34b1796 2194 /// ```
cc61c64b
XL
2195 ///
2196 /// [`Component`]: enum.Component.html
2197 /// [`CurDir`]: enum.Component.html#variant.CurDir
c34b1796 2198 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2199 pub fn components(&self) -> Components {
2200 let prefix = parse_prefix(self.as_os_str());
2201 Components {
2202 path: self.as_u8_slice(),
3b2f2976
XL
2203 prefix,
2204 has_physical_root: has_physical_root(self.as_u8_slice(), prefix) ||
2205 has_redox_scheme(self.as_u8_slice()),
85aaf69f 2206 front: State::Prefix,
c34b1796 2207 back: State::Body,
85aaf69f
SL
2208 }
2209 }
2210
cc61c64b
XL
2211 /// Produces an iterator over the path's components viewed as [`OsStr`]
2212 /// slices.
2213 ///
2214 /// For more information about the particulars of how the path is separated
2215 /// into components, see [`components`].
9e0c209e 2216 ///
cc61c64b 2217 /// [`components`]: #method.components
9e0c209e 2218 /// [`OsStr`]: ../ffi/struct.OsStr.html
c34b1796
AL
2219 ///
2220 /// # Examples
2221 ///
2222 /// ```
62682a34
SL
2223 /// use std::path::{self, Path};
2224 /// use std::ffi::OsStr;
2225 ///
2226 /// let mut it = Path::new("/tmp/foo.txt").iter();
2227 /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
2228 /// assert_eq!(it.next(), Some(OsStr::new("tmp")));
2229 /// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
2230 /// assert_eq!(it.next(), None)
c34b1796
AL
2231 /// ```
2232 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2233 pub fn iter(&self) -> Iter {
2234 Iter { inner: self.components() }
2235 }
2236
9e0c209e 2237 /// Returns an object that implements [`Display`] for safely printing paths
85aaf69f 2238 /// that may contain non-Unicode data.
c34b1796 2239 ///
9e0c209e
SL
2240 /// [`Display`]: ../fmt/trait.Display.html
2241 ///
c34b1796
AL
2242 /// # Examples
2243 ///
2244 /// ```
2245 /// use std::path::Path;
2246 ///
2247 /// let path = Path::new("/tmp/foo.rs");
2248 ///
2249 /// println!("{}", path.display());
2250 /// ```
2251 #[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2252 pub fn display(&self) -> Display {
2253 Display { path: self }
2254 }
b039eaaf 2255
cc61c64b 2256 /// Queries the file system to get information about a file, directory, etc.
b039eaaf 2257 ///
7453a54e
SL
2258 /// This function will traverse symbolic links to query information about the
2259 /// destination file.
b039eaaf 2260 ///
3157f602
XL
2261 /// This is an alias to [`fs::metadata`].
2262 ///
2263 /// [`fs::metadata`]: ../fs/fn.metadata.html
32a655c1
SL
2264 ///
2265 /// # Examples
2266 ///
2267 /// ```no_run
2268 /// use std::path::Path;
2269 ///
2270 /// let path = Path::new("/Minas/tirith");
2271 /// let metadata = path.metadata().expect("metadata call failed");
2272 /// println!("{:?}", metadata.file_type());
2273 /// ```
b039eaaf
SL
2274 #[stable(feature = "path_ext", since = "1.5.0")]
2275 pub fn metadata(&self) -> io::Result<fs::Metadata> {
2276 fs::metadata(self)
2277 }
2278
cc61c64b 2279 /// Queries the metadata about a file without following symlinks.
b039eaaf 2280 ///
3157f602
XL
2281 /// This is an alias to [`fs::symlink_metadata`].
2282 ///
2283 /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html
32a655c1
SL
2284 ///
2285 /// # Examples
2286 ///
2287 /// ```no_run
2288 /// use std::path::Path;
2289 ///
2290 /// let path = Path::new("/Minas/tirith");
2291 /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
2292 /// println!("{:?}", metadata.file_type());
2293 /// ```
b039eaaf
SL
2294 #[stable(feature = "path_ext", since = "1.5.0")]
2295 pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> {
2296 fs::symlink_metadata(self)
2297 }
2298
94b46f34
XL
2299 /// Returns the canonical, absolute form of the path with all intermediate
2300 /// components normalized and symbolic links resolved.
b039eaaf 2301 ///
3157f602
XL
2302 /// This is an alias to [`fs::canonicalize`].
2303 ///
2304 /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html
32a655c1
SL
2305 ///
2306 /// # Examples
2307 ///
2308 /// ```no_run
2309 /// use std::path::{Path, PathBuf};
2310 ///
2311 /// let path = Path::new("/foo/test/../test/bar.rs");
2312 /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
2313 /// ```
b039eaaf
SL
2314 #[stable(feature = "path_ext", since = "1.5.0")]
2315 pub fn canonicalize(&self) -> io::Result<PathBuf> {
2316 fs::canonicalize(self)
2317 }
2318
7453a54e 2319 /// Reads a symbolic link, returning the file that the link points to.
b039eaaf 2320 ///
3157f602
XL
2321 /// This is an alias to [`fs::read_link`].
2322 ///
2323 /// [`fs::read_link`]: ../fs/fn.read_link.html
32a655c1
SL
2324 ///
2325 /// # Examples
2326 ///
2327 /// ```no_run
2328 /// use std::path::Path;
2329 ///
2330 /// let path = Path::new("/laputa/sky_castle.rs");
2331 /// let path_link = path.read_link().expect("read_link call failed");
2332 /// ```
b039eaaf
SL
2333 #[stable(feature = "path_ext", since = "1.5.0")]
2334 pub fn read_link(&self) -> io::Result<PathBuf> {
2335 fs::read_link(self)
2336 }
2337
7453a54e 2338 /// Returns an iterator over the entries within a directory.
b039eaaf 2339 ///
9e0c209e
SL
2340 /// The iterator will yield instances of [`io::Result`]`<`[`DirEntry`]`>`. New
2341 /// errors may be encountered after an iterator is initially constructed.
7453a54e 2342 ///
3157f602
XL
2343 /// This is an alias to [`fs::read_dir`].
2344 ///
9e0c209e
SL
2345 /// [`io::Result`]: ../io/type.Result.html
2346 /// [`DirEntry`]: ../fs/struct.DirEntry.html
3157f602 2347 /// [`fs::read_dir`]: ../fs/fn.read_dir.html
32a655c1
SL
2348 ///
2349 /// # Examples
2350 ///
2351 /// ```no_run
2352 /// use std::path::Path;
2353 ///
2354 /// let path = Path::new("/laputa");
2355 /// for entry in path.read_dir().expect("read_dir call failed") {
2356 /// if let Ok(entry) = entry {
2357 /// println!("{:?}", entry.path());
2358 /// }
2359 /// }
2360 /// ```
b039eaaf
SL
2361 #[stable(feature = "path_ext", since = "1.5.0")]
2362 pub fn read_dir(&self) -> io::Result<fs::ReadDir> {
2363 fs::read_dir(self)
2364 }
2365
7453a54e
SL
2366 /// Returns whether the path points at an existing entity.
2367 ///
2368 /// This function will traverse symbolic links to query information about the
2369 /// destination file. In case of broken symbolic links this will return `false`.
2370 ///
041b39d2
XL
2371 /// If you cannot access the directory containing the file, e.g. because of a
2372 /// permission error, this will return `false`.
2373 ///
7453a54e
SL
2374 /// # Examples
2375 ///
2376 /// ```no_run
2377 /// use std::path::Path;
2378 /// assert_eq!(Path::new("does_not_exist.txt").exists(), false);
2379 /// ```
041b39d2
XL
2380 ///
2381 /// # See Also
2382 ///
2383 /// This is a convenience function that coerces errors to false. If you want to
2384 /// check errors, call [fs::metadata].
2385 ///
2386 /// [fs::metadata]: ../../std/fs/fn.metadata.html
b039eaaf
SL
2387 #[stable(feature = "path_ext", since = "1.5.0")]
2388 pub fn exists(&self) -> bool {
2389 fs::metadata(self).is_ok()
2390 }
2391
3b2f2976 2392 /// Returns whether the path exists on disk and is pointing at a regular file.
7453a54e
SL
2393 ///
2394 /// This function will traverse symbolic links to query information about the
2395 /// destination file. In case of broken symbolic links this will return `false`.
2396 ///
041b39d2
XL
2397 /// If you cannot access the directory containing the file, e.g. because of a
2398 /// permission error, this will return `false`.
2399 ///
7453a54e
SL
2400 /// # Examples
2401 ///
2402 /// ```no_run
2403 /// use std::path::Path;
2404 /// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
2405 /// assert_eq!(Path::new("a_file.txt").is_file(), true);
2406 /// ```
041b39d2
XL
2407 ///
2408 /// # See Also
2409 ///
2410 /// This is a convenience function that coerces errors to false. If you want to
2411 /// check errors, call [fs::metadata] and handle its Result. Then call
2412 /// [fs::Metadata::is_file] if it was Ok.
2413 ///
2414 /// [fs::metadata]: ../../std/fs/fn.metadata.html
2415 /// [fs::Metadata::is_file]: ../../std/fs/struct.Metadata.html#method.is_file
b039eaaf
SL
2416 #[stable(feature = "path_ext", since = "1.5.0")]
2417 pub fn is_file(&self) -> bool {
2418 fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
2419 }
2420
3b2f2976 2421 /// Returns whether the path exists on disk and is pointing at a directory.
7453a54e
SL
2422 ///
2423 /// This function will traverse symbolic links to query information about the
2424 /// destination file. In case of broken symbolic links this will return `false`.
2425 ///
041b39d2
XL
2426 /// If you cannot access the directory containing the file, e.g. because of a
2427 /// permission error, this will return `false`.
2428 ///
7453a54e
SL
2429 /// # Examples
2430 ///
2431 /// ```no_run
2432 /// use std::path::Path;
2433 /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
2434 /// assert_eq!(Path::new("a_file.txt").is_dir(), false);
2435 /// ```
041b39d2
XL
2436 ///
2437 /// # See Also
2438 ///
2439 /// This is a convenience function that coerces errors to false. If you want to
2440 /// check errors, call [fs::metadata] and handle its Result. Then call
2441 /// [fs::Metadata::is_dir] if it was Ok.
2442 ///
2443 /// [fs::metadata]: ../../std/fs/fn.metadata.html
2444 /// [fs::Metadata::is_dir]: ../../std/fs/struct.Metadata.html#method.is_dir
b039eaaf
SL
2445 #[stable(feature = "path_ext", since = "1.5.0")]
2446 pub fn is_dir(&self) -> bool {
2447 fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
2448 }
cc61c64b
XL
2449
2450 /// Converts a [`Box<Path>`][`Box`] into a [`PathBuf`] without copying or
2451 /// allocating.
2452 ///
2453 /// [`Box`]: ../../std/boxed/struct.Box.html
2454 /// [`PathBuf`]: struct.PathBuf.html
041b39d2 2455 #[stable(feature = "into_boxed_path", since = "1.20.0")]
cc61c64b 2456 pub fn into_path_buf(self: Box<Path>) -> PathBuf {
ea8adc8c
XL
2457 let rw = Box::into_raw(self) as *mut OsStr;
2458 let inner = unsafe { Box::from_raw(rw) };
cc61c64b
XL
2459 PathBuf { inner: OsString::from(inner) }
2460 }
85aaf69f
SL
2461}
2462
c34b1796
AL
2463#[stable(feature = "rust1", since = "1.0.0")]
2464impl AsRef<OsStr> for Path {
2465 fn as_ref(&self) -> &OsStr {
2466 &self.inner
2467 }
2468}
2469
c34b1796 2470#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 2471impl fmt::Debug for Path {
041b39d2
XL
2472 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
2473 fmt::Debug::fmt(&self.inner, formatter)
85aaf69f
SL
2474 }
2475}
2476
cc61c64b
XL
2477/// Helper struct for safely printing paths with [`format!`] and `{}`.
2478///
2479/// A [`Path`] might contain non-Unicode data. This `struct` implements the
2480/// [`Display`] trait in a way that mitigates that. It is created by the
2481/// [`display`][`Path::display`] method on [`Path`].
2482///
2483/// # Examples
2484///
2485/// ```
2486/// use std::path::Path;
2487///
2488/// let path = Path::new("/tmp/foo.rs");
2489///
2490/// println!("{}", path.display());
2491/// ```
2492///
2493/// [`Display`]: ../../std/fmt/trait.Display.html
2494/// [`format!`]: ../../std/macro.format.html
2495/// [`Path`]: struct.Path.html
2496/// [`Path::display`]: struct.Path.html#method.display
c34b1796 2497#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f 2498pub struct Display<'a> {
92a42be0 2499 path: &'a Path,
85aaf69f
SL
2500}
2501
c34b1796 2502#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2503impl<'a> fmt::Debug for Display<'a> {
2504 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
041b39d2 2505 fmt::Debug::fmt(&self.path, f)
85aaf69f
SL
2506 }
2507}
2508
c34b1796 2509#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2510impl<'a> fmt::Display for Display<'a> {
2511 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
041b39d2 2512 self.path.inner.display(f)
85aaf69f
SL
2513 }
2514}
2515
c34b1796 2516#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2517impl cmp::PartialEq for Path {
2518 fn eq(&self, other: &Path) -> bool {
e9174d1e 2519 self.components().eq(other.components())
85aaf69f
SL
2520 }
2521}
2522
92a42be0
SL
2523#[stable(feature = "rust1", since = "1.0.0")]
2524impl Hash for Path {
2525 fn hash<H: Hasher>(&self, h: &mut H) {
2526 for component in self.components() {
2527 component.hash(h);
2528 }
2529 }
2530}
2531
c34b1796 2532#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2533impl cmp::Eq for Path {}
2534
c34b1796 2535#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2536impl cmp::PartialOrd for Path {
2537 fn partial_cmp(&self, other: &Path) -> Option<cmp::Ordering> {
e9174d1e 2538 self.components().partial_cmp(other.components())
85aaf69f
SL
2539 }
2540}
2541
c34b1796 2542#[stable(feature = "rust1", since = "1.0.0")]
85aaf69f
SL
2543impl cmp::Ord for Path {
2544 fn cmp(&self, other: &Path) -> cmp::Ordering {
e9174d1e 2545 self.components().cmp(other.components())
85aaf69f
SL
2546 }
2547}
2548
c34b1796
AL
2549#[stable(feature = "rust1", since = "1.0.0")]
2550impl AsRef<Path> for Path {
92a42be0
SL
2551 fn as_ref(&self) -> &Path {
2552 self
2553 }
c34b1796
AL
2554}
2555
2556#[stable(feature = "rust1", since = "1.0.0")]
2557impl AsRef<Path> for OsStr {
92a42be0
SL
2558 fn as_ref(&self) -> &Path {
2559 Path::new(self)
2560 }
c34b1796
AL
2561}
2562
7453a54e
SL
2563#[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")]
2564impl<'a> AsRef<Path> for Cow<'a, OsStr> {
2565 fn as_ref(&self) -> &Path {
2566 Path::new(self)
2567 }
2568}
2569
c34b1796
AL
2570#[stable(feature = "rust1", since = "1.0.0")]
2571impl AsRef<Path> for OsString {
92a42be0
SL
2572 fn as_ref(&self) -> &Path {
2573 Path::new(self)
2574 }
c34b1796
AL
2575}
2576
2577#[stable(feature = "rust1", since = "1.0.0")]
2578impl AsRef<Path> for str {
92a42be0
SL
2579 fn as_ref(&self) -> &Path {
2580 Path::new(self)
2581 }
c34b1796
AL
2582}
2583
2584#[stable(feature = "rust1", since = "1.0.0")]
2585impl AsRef<Path> for String {
92a42be0
SL
2586 fn as_ref(&self) -> &Path {
2587 Path::new(self)
2588 }
c34b1796
AL
2589}
2590
2591#[stable(feature = "rust1", since = "1.0.0")]
2592impl AsRef<Path> for PathBuf {
92a42be0
SL
2593 fn as_ref(&self) -> &Path {
2594 self
2595 }
2596}
2597
2598#[stable(feature = "path_into_iter", since = "1.6.0")]
2599impl<'a> IntoIterator for &'a PathBuf {
2600 type Item = &'a OsStr;
2601 type IntoIter = Iter<'a>;
2602 fn into_iter(self) -> Iter<'a> { self.iter() }
2603}
2604
2605#[stable(feature = "path_into_iter", since = "1.6.0")]
2606impl<'a> IntoIterator for &'a Path {
2607 type Item = &'a OsStr;
2608 type IntoIter = Iter<'a>;
2609 fn into_iter(self) -> Iter<'a> { self.iter() }
2610}
2611
7453a54e 2612macro_rules! impl_cmp {
92a42be0
SL
2613 ($lhs:ty, $rhs: ty) => {
2614 #[stable(feature = "partialeq_path", since = "1.6.0")]
2615 impl<'a, 'b> PartialEq<$rhs> for $lhs {
2616 #[inline]
2617 fn eq(&self, other: &$rhs) -> bool { <Path as PartialEq>::eq(self, other) }
2618 }
2619
2620 #[stable(feature = "partialeq_path", since = "1.6.0")]
2621 impl<'a, 'b> PartialEq<$lhs> for $rhs {
2622 #[inline]
2623 fn eq(&self, other: &$lhs) -> bool { <Path as PartialEq>::eq(self, other) }
2624 }
2625
7453a54e
SL
2626 #[stable(feature = "cmp_path", since = "1.8.0")]
2627 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2628 #[inline]
2629 fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
2630 <Path as PartialOrd>::partial_cmp(self, other)
2631 }
2632 }
2633
2634 #[stable(feature = "cmp_path", since = "1.8.0")]
2635 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2636 #[inline]
2637 fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
2638 <Path as PartialOrd>::partial_cmp(self, other)
2639 }
2640 }
2641 }
2642}
2643
2644impl_cmp!(PathBuf, Path);
2645impl_cmp!(PathBuf, &'a Path);
2646impl_cmp!(Cow<'a, Path>, Path);
2647impl_cmp!(Cow<'a, Path>, &'b Path);
2648impl_cmp!(Cow<'a, Path>, PathBuf);
2649
2650macro_rules! impl_cmp_os_str {
2651 ($lhs:ty, $rhs: ty) => {
2652 #[stable(feature = "cmp_path", since = "1.8.0")]
2653 impl<'a, 'b> PartialEq<$rhs> for $lhs {
2654 #[inline]
2655 fn eq(&self, other: &$rhs) -> bool { <Path as PartialEq>::eq(self, other.as_ref()) }
2656 }
2657
2658 #[stable(feature = "cmp_path", since = "1.8.0")]
2659 impl<'a, 'b> PartialEq<$lhs> for $rhs {
2660 #[inline]
2661 fn eq(&self, other: &$lhs) -> bool { <Path as PartialEq>::eq(self.as_ref(), other) }
2662 }
2663
2664 #[stable(feature = "cmp_path", since = "1.8.0")]
2665 impl<'a, 'b> PartialOrd<$rhs> for $lhs {
2666 #[inline]
2667 fn partial_cmp(&self, other: &$rhs) -> Option<cmp::Ordering> {
2668 <Path as PartialOrd>::partial_cmp(self, other.as_ref())
2669 }
2670 }
2671
2672 #[stable(feature = "cmp_path", since = "1.8.0")]
2673 impl<'a, 'b> PartialOrd<$lhs> for $rhs {
2674 #[inline]
2675 fn partial_cmp(&self, other: &$lhs) -> Option<cmp::Ordering> {
2676 <Path as PartialOrd>::partial_cmp(self.as_ref(), other)
2677 }
2678 }
92a42be0 2679 }
c34b1796
AL
2680}
2681
7453a54e
SL
2682impl_cmp_os_str!(PathBuf, OsStr);
2683impl_cmp_os_str!(PathBuf, &'a OsStr);
2684impl_cmp_os_str!(PathBuf, Cow<'a, OsStr>);
2685impl_cmp_os_str!(PathBuf, OsString);
2686impl_cmp_os_str!(Path, OsStr);
2687impl_cmp_os_str!(Path, &'a OsStr);
2688impl_cmp_os_str!(Path, Cow<'a, OsStr>);
2689impl_cmp_os_str!(Path, OsString);
2690impl_cmp_os_str!(&'a Path, OsStr);
2691impl_cmp_os_str!(&'a Path, Cow<'b, OsStr>);
2692impl_cmp_os_str!(&'a Path, OsString);
2693impl_cmp_os_str!(Cow<'a, Path>, OsStr);
2694impl_cmp_os_str!(Cow<'a, Path>, &'b OsStr);
2695impl_cmp_os_str!(Cow<'a, Path>, OsString);
92a42be0 2696
9cc50fc6
SL
2697#[stable(since = "1.7.0", feature = "strip_prefix")]
2698impl fmt::Display for StripPrefixError {
2699 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2700 self.description().fmt(f)
2701 }
2702}
2703
2704#[stable(since = "1.7.0", feature = "strip_prefix")]
2705impl Error for StripPrefixError {
2706 fn description(&self) -> &str { "prefix not found" }
2707}
2708
85aaf69f
SL
2709#[cfg(test)]
2710mod tests {
2711 use super::*;
85aaf69f 2712
ff7c6d11
XL
2713 use rc::Rc;
2714 use sync::Arc;
2715
85aaf69f
SL
2716 macro_rules! t(
2717 ($path:expr, iter: $iter:expr) => (
2718 {
2719 let path = Path::new($path);
2720
2721 // Forward iteration
2722 let comps = path.iter()
2723 .map(|p| p.to_string_lossy().into_owned())
2724 .collect::<Vec<String>>();
2725 let exp: &[&str] = &$iter;
2726 let exps = exp.iter().map(|s| s.to_string()).collect::<Vec<String>>();
2727 assert!(comps == exps, "iter: Expected {:?}, found {:?}",
2728 exps, comps);
2729
2730 // Reverse iteration
2731 let comps = Path::new($path).iter().rev()
2732 .map(|p| p.to_string_lossy().into_owned())
2733 .collect::<Vec<String>>();
2734 let exps = exps.into_iter().rev().collect::<Vec<String>>();
2735 assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}",
2736 exps, comps);
2737 }
2738 );
2739
2740 ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => (
2741 {
2742 let path = Path::new($path);
2743
2744 let act_root = path.has_root();
2745 assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}",
2746 $has_root, act_root);
2747
2748 let act_abs = path.is_absolute();
2749 assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}",
2750 $is_absolute, act_abs);
2751 }
2752 );
2753
2754 ($path:expr, parent: $parent:expr, file_name: $file:expr) => (
2755 {
2756 let path = Path::new($path);
2757
2758 let parent = path.parent().map(|p| p.to_str().unwrap());
2759 let exp_parent: Option<&str> = $parent;
2760 assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}",
2761 exp_parent, parent);
2762
2763 let file = path.file_name().map(|p| p.to_str().unwrap());
2764 let exp_file: Option<&str> = $file;
2765 assert!(file == exp_file, "file_name: Expected {:?}, found {:?}",
2766 exp_file, file);
2767 }
2768 );
2769
2770 ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => (
2771 {
2772 let path = Path::new($path);
2773
2774 let stem = path.file_stem().map(|p| p.to_str().unwrap());
2775 let exp_stem: Option<&str> = $file_stem;
2776 assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}",
2777 exp_stem, stem);
2778
2779 let ext = path.extension().map(|p| p.to_str().unwrap());
2780 let exp_ext: Option<&str> = $extension;
2781 assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}",
2782 exp_ext, ext);
2783 }
2784 );
2785
2786 ($path:expr, iter: $iter:expr,
2787 has_root: $has_root:expr, is_absolute: $is_absolute:expr,
2788 parent: $parent:expr, file_name: $file:expr,
2789 file_stem: $file_stem:expr, extension: $extension:expr) => (
2790 {
2791 t!($path, iter: $iter);
2792 t!($path, has_root: $has_root, is_absolute: $is_absolute);
2793 t!($path, parent: $parent, file_name: $file);
2794 t!($path, file_stem: $file_stem, extension: $extension);
2795 }
2796 );
2797 );
2798
92a42be0
SL
2799 #[test]
2800 fn into() {
2801 use borrow::Cow;
2802
2803 let static_path = Path::new("/home/foo");
2804 let static_cow_path: Cow<'static, Path> = static_path.into();
2805 let pathbuf = PathBuf::from("/home/foo");
2806
2807 {
2808 let path: &Path = &pathbuf;
2809 let borrowed_cow_path: Cow<Path> = path.into();
2810
2811 assert_eq!(static_cow_path, borrowed_cow_path);
2812 }
2813
2814 let owned_cow_path: Cow<'static, Path> = pathbuf.into();
2815
2816 assert_eq!(static_cow_path, owned_cow_path);
2817 }
2818
85aaf69f
SL
2819 #[test]
2820 #[cfg(unix)]
2821 pub fn test_decompositions_unix() {
2822 t!("",
2823 iter: [],
2824 has_root: false,
2825 is_absolute: false,
2826 parent: None,
2827 file_name: None,
2828 file_stem: None,
2829 extension: None
2830 );
2831
2832 t!("foo",
2833 iter: ["foo"],
2834 has_root: false,
2835 is_absolute: false,
c34b1796 2836 parent: Some(""),
85aaf69f
SL
2837 file_name: Some("foo"),
2838 file_stem: Some("foo"),
2839 extension: None
2840 );
2841
2842 t!("/",
c34b1796 2843 iter: ["/"],
85aaf69f
SL
2844 has_root: true,
2845 is_absolute: true,
2846 parent: None,
2847 file_name: None,
2848 file_stem: None,
2849 extension: None
2850 );
2851
2852 t!("/foo",
2853 iter: ["/", "foo"],
2854 has_root: true,
2855 is_absolute: true,
2856 parent: Some("/"),
2857 file_name: Some("foo"),
2858 file_stem: Some("foo"),
2859 extension: None
2860 );
2861
2862 t!("foo/",
c34b1796 2863 iter: ["foo"],
85aaf69f
SL
2864 has_root: false,
2865 is_absolute: false,
c34b1796
AL
2866 parent: Some(""),
2867 file_name: Some("foo"),
2868 file_stem: Some("foo"),
85aaf69f
SL
2869 extension: None
2870 );
2871
2872 t!("/foo/",
c34b1796 2873 iter: ["/", "foo"],
85aaf69f
SL
2874 has_root: true,
2875 is_absolute: true,
c34b1796
AL
2876 parent: Some("/"),
2877 file_name: Some("foo"),
2878 file_stem: Some("foo"),
85aaf69f
SL
2879 extension: None
2880 );
2881
2882 t!("foo/bar",
2883 iter: ["foo", "bar"],
2884 has_root: false,
2885 is_absolute: false,
2886 parent: Some("foo"),
2887 file_name: Some("bar"),
2888 file_stem: Some("bar"),
2889 extension: None
2890 );
2891
2892 t!("/foo/bar",
2893 iter: ["/", "foo", "bar"],
2894 has_root: true,
2895 is_absolute: true,
2896 parent: Some("/foo"),
2897 file_name: Some("bar"),
2898 file_stem: Some("bar"),
2899 extension: None
2900 );
2901
2902 t!("///foo///",
c34b1796 2903 iter: ["/", "foo"],
85aaf69f
SL
2904 has_root: true,
2905 is_absolute: true,
c34b1796
AL
2906 parent: Some("/"),
2907 file_name: Some("foo"),
2908 file_stem: Some("foo"),
85aaf69f
SL
2909 extension: None
2910 );
2911
2912 t!("///foo///bar",
2913 iter: ["/", "foo", "bar"],
2914 has_root: true,
2915 is_absolute: true,
2916 parent: Some("///foo"),
2917 file_name: Some("bar"),
2918 file_stem: Some("bar"),
2919 extension: None
2920 );
2921
2922 t!("./.",
c34b1796 2923 iter: ["."],
85aaf69f
SL
2924 has_root: false,
2925 is_absolute: false,
c34b1796 2926 parent: Some(""),
85aaf69f
SL
2927 file_name: None,
2928 file_stem: None,
2929 extension: None
2930 );
2931
2932 t!("/..",
2933 iter: ["/", ".."],
2934 has_root: true,
2935 is_absolute: true,
2936 parent: Some("/"),
2937 file_name: None,
2938 file_stem: None,
2939 extension: None
2940 );
2941
2942 t!("../",
c34b1796 2943 iter: [".."],
85aaf69f
SL
2944 has_root: false,
2945 is_absolute: false,
c34b1796 2946 parent: Some(""),
85aaf69f
SL
2947 file_name: None,
2948 file_stem: None,
2949 extension: None
2950 );
2951
2952 t!("foo/.",
c34b1796 2953 iter: ["foo"],
85aaf69f
SL
2954 has_root: false,
2955 is_absolute: false,
c34b1796
AL
2956 parent: Some(""),
2957 file_name: Some("foo"),
2958 file_stem: Some("foo"),
85aaf69f
SL
2959 extension: None
2960 );
2961
2962 t!("foo/..",
2963 iter: ["foo", ".."],
2964 has_root: false,
2965 is_absolute: false,
2966 parent: Some("foo"),
2967 file_name: None,
2968 file_stem: None,
2969 extension: None
2970 );
2971
2972 t!("foo/./",
c34b1796 2973 iter: ["foo"],
85aaf69f
SL
2974 has_root: false,
2975 is_absolute: false,
c34b1796
AL
2976 parent: Some(""),
2977 file_name: Some("foo"),
2978 file_stem: Some("foo"),
85aaf69f
SL
2979 extension: None
2980 );
2981
2982 t!("foo/./bar",
c34b1796 2983 iter: ["foo", "bar"],
85aaf69f
SL
2984 has_root: false,
2985 is_absolute: false,
c34b1796 2986 parent: Some("foo"),
85aaf69f
SL
2987 file_name: Some("bar"),
2988 file_stem: Some("bar"),
2989 extension: None
2990 );
2991
2992 t!("foo/../",
c34b1796 2993 iter: ["foo", ".."],
85aaf69f
SL
2994 has_root: false,
2995 is_absolute: false,
c34b1796 2996 parent: Some("foo"),
85aaf69f
SL
2997 file_name: None,
2998 file_stem: None,
2999 extension: None
3000 );
3001
3002 t!("foo/../bar",
3003 iter: ["foo", "..", "bar"],
3004 has_root: false,
3005 is_absolute: false,
3006 parent: Some("foo/.."),
3007 file_name: Some("bar"),
3008 file_stem: Some("bar"),
3009 extension: None
3010 );
3011
3012 t!("./a",
3013 iter: [".", "a"],
3014 has_root: false,
3015 is_absolute: false,
3016 parent: Some("."),
3017 file_name: Some("a"),
3018 file_stem: Some("a"),
3019 extension: None
3020 );
3021
3022 t!(".",
3023 iter: ["."],
3024 has_root: false,
3025 is_absolute: false,
c34b1796 3026 parent: Some(""),
85aaf69f
SL
3027 file_name: None,
3028 file_stem: None,
3029 extension: None
3030 );
3031
3032 t!("./",
c34b1796 3033 iter: ["."],
85aaf69f
SL
3034 has_root: false,
3035 is_absolute: false,
c34b1796 3036 parent: Some(""),
85aaf69f
SL
3037 file_name: None,
3038 file_stem: None,
3039 extension: None
3040 );
3041
3042 t!("a/b",
3043 iter: ["a", "b"],
3044 has_root: false,
3045 is_absolute: false,
3046 parent: Some("a"),
3047 file_name: Some("b"),
3048 file_stem: Some("b"),
3049 extension: None
3050 );
3051
3052 t!("a//b",
3053 iter: ["a", "b"],
3054 has_root: false,
3055 is_absolute: false,
3056 parent: Some("a"),
3057 file_name: Some("b"),
3058 file_stem: Some("b"),
3059 extension: None
3060 );
3061
3062 t!("a/./b",
c34b1796 3063 iter: ["a", "b"],
85aaf69f
SL
3064 has_root: false,
3065 is_absolute: false,
c34b1796 3066 parent: Some("a"),
85aaf69f
SL
3067 file_name: Some("b"),
3068 file_stem: Some("b"),
3069 extension: None
3070 );
3071
3072 t!("a/b/c",
3073 iter: ["a", "b", "c"],
3074 has_root: false,
3075 is_absolute: false,
3076 parent: Some("a/b"),
3077 file_name: Some("c"),
3078 file_stem: Some("c"),
3079 extension: None
3080 );
c34b1796
AL
3081
3082 t!(".foo",
3083 iter: [".foo"],
3084 has_root: false,
3085 is_absolute: false,
3086 parent: Some(""),
3087 file_name: Some(".foo"),
3088 file_stem: Some(".foo"),
3089 extension: None
3090 );
85aaf69f
SL
3091 }
3092
3093 #[test]
3094 #[cfg(windows)]
3095 pub fn test_decompositions_windows() {
3096 t!("",
3097 iter: [],
3098 has_root: false,
3099 is_absolute: false,
3100 parent: None,
3101 file_name: None,
3102 file_stem: None,
3103 extension: None
3104 );
3105
3106 t!("foo",
3107 iter: ["foo"],
3108 has_root: false,
3109 is_absolute: false,
c34b1796 3110 parent: Some(""),
85aaf69f
SL
3111 file_name: Some("foo"),
3112 file_stem: Some("foo"),
3113 extension: None
3114 );
3115
3116 t!("/",
c34b1796 3117 iter: ["\\"],
85aaf69f
SL
3118 has_root: true,
3119 is_absolute: false,
3120 parent: None,
3121 file_name: None,
3122 file_stem: None,
3123 extension: None
3124 );
3125
3126 t!("\\",
c34b1796 3127 iter: ["\\"],
85aaf69f
SL
3128 has_root: true,
3129 is_absolute: false,
3130 parent: None,
3131 file_name: None,
3132 file_stem: None,
3133 extension: None
3134 );
3135
3136 t!("c:",
c34b1796 3137 iter: ["c:"],
85aaf69f
SL
3138 has_root: false,
3139 is_absolute: false,
3140 parent: None,
3141 file_name: None,
3142 file_stem: None,
3143 extension: None
3144 );
3145
3146 t!("c:\\",
c34b1796 3147 iter: ["c:", "\\"],
85aaf69f
SL
3148 has_root: true,
3149 is_absolute: true,
3150 parent: None,
3151 file_name: None,
3152 file_stem: None,
3153 extension: None
3154 );
3155
3156 t!("c:/",
c34b1796 3157 iter: ["c:", "\\"],
85aaf69f
SL
3158 has_root: true,
3159 is_absolute: true,
3160 parent: None,
3161 file_name: None,
3162 file_stem: None,
3163 extension: None
3164 );
3165
3166 t!("/foo",
3167 iter: ["\\", "foo"],
3168 has_root: true,
3169 is_absolute: false,
3170 parent: Some("/"),
3171 file_name: Some("foo"),
3172 file_stem: Some("foo"),
3173 extension: None
3174 );
3175
3176 t!("foo/",
c34b1796 3177 iter: ["foo"],
85aaf69f
SL
3178 has_root: false,
3179 is_absolute: false,
c34b1796
AL
3180 parent: Some(""),
3181 file_name: Some("foo"),
3182 file_stem: Some("foo"),
85aaf69f
SL
3183 extension: None
3184 );
3185
3186 t!("/foo/",
c34b1796 3187 iter: ["\\", "foo"],
85aaf69f
SL
3188 has_root: true,
3189 is_absolute: false,
c34b1796
AL
3190 parent: Some("/"),
3191 file_name: Some("foo"),
3192 file_stem: Some("foo"),
85aaf69f
SL
3193 extension: None
3194 );
3195
3196 t!("foo/bar",
3197 iter: ["foo", "bar"],
3198 has_root: false,
3199 is_absolute: false,
3200 parent: Some("foo"),
3201 file_name: Some("bar"),
3202 file_stem: Some("bar"),
3203 extension: None
3204 );
3205
3206 t!("/foo/bar",
3207 iter: ["\\", "foo", "bar"],
3208 has_root: true,
3209 is_absolute: false,
3210 parent: Some("/foo"),
3211 file_name: Some("bar"),
3212 file_stem: Some("bar"),
3213 extension: None
3214 );
3215
3216 t!("///foo///",
c34b1796 3217 iter: ["\\", "foo"],
85aaf69f
SL
3218 has_root: true,
3219 is_absolute: false,
c34b1796
AL
3220 parent: Some("/"),
3221 file_name: Some("foo"),
3222 file_stem: Some("foo"),
85aaf69f
SL
3223 extension: None
3224 );
3225
3226 t!("///foo///bar",
3227 iter: ["\\", "foo", "bar"],
3228 has_root: true,
3229 is_absolute: false,
3230 parent: Some("///foo"),
3231 file_name: Some("bar"),
3232 file_stem: Some("bar"),
3233 extension: None
3234 );
3235
3236 t!("./.",
c34b1796 3237 iter: ["."],
85aaf69f
SL
3238 has_root: false,
3239 is_absolute: false,
c34b1796 3240 parent: Some(""),
85aaf69f
SL
3241 file_name: None,
3242 file_stem: None,
3243 extension: None
3244 );
3245
3246 t!("/..",
3247 iter: ["\\", ".."],
3248 has_root: true,
3249 is_absolute: false,
3250 parent: Some("/"),
3251 file_name: None,
3252 file_stem: None,
3253 extension: None
3254 );
3255
3256 t!("../",
c34b1796 3257 iter: [".."],
85aaf69f
SL
3258 has_root: false,
3259 is_absolute: false,
c34b1796 3260 parent: Some(""),
85aaf69f
SL
3261 file_name: None,
3262 file_stem: None,
3263 extension: None
3264 );
3265
3266 t!("foo/.",
c34b1796 3267 iter: ["foo"],
85aaf69f
SL
3268 has_root: false,
3269 is_absolute: false,
c34b1796
AL
3270 parent: Some(""),
3271 file_name: Some("foo"),
3272 file_stem: Some("foo"),
85aaf69f
SL
3273 extension: None
3274 );
3275
3276 t!("foo/..",
3277 iter: ["foo", ".."],
3278 has_root: false,
3279 is_absolute: false,
3280 parent: Some("foo"),
3281 file_name: None,
3282 file_stem: None,
3283 extension: None
3284 );
3285
3286 t!("foo/./",
c34b1796 3287 iter: ["foo"],
85aaf69f
SL
3288 has_root: false,
3289 is_absolute: false,
c34b1796
AL
3290 parent: Some(""),
3291 file_name: Some("foo"),
3292 file_stem: Some("foo"),
85aaf69f
SL
3293 extension: None
3294 );
3295
3296 t!("foo/./bar",
c34b1796 3297 iter: ["foo", "bar"],
85aaf69f
SL
3298 has_root: false,
3299 is_absolute: false,
c34b1796 3300 parent: Some("foo"),
85aaf69f
SL
3301 file_name: Some("bar"),
3302 file_stem: Some("bar"),
3303 extension: None
3304 );
3305
3306 t!("foo/../",
c34b1796 3307 iter: ["foo", ".."],
85aaf69f
SL
3308 has_root: false,
3309 is_absolute: false,
c34b1796 3310 parent: Some("foo"),
85aaf69f
SL
3311 file_name: None,
3312 file_stem: None,
3313 extension: None
3314 );
3315
3316 t!("foo/../bar",
3317 iter: ["foo", "..", "bar"],
3318 has_root: false,
3319 is_absolute: false,
3320 parent: Some("foo/.."),
3321 file_name: Some("bar"),
3322 file_stem: Some("bar"),
3323 extension: None
3324 );
3325
3326 t!("./a",
3327 iter: [".", "a"],
3328 has_root: false,
3329 is_absolute: false,
3330 parent: Some("."),
3331 file_name: Some("a"),
3332 file_stem: Some("a"),
3333 extension: None
3334 );
3335
3336 t!(".",
3337 iter: ["."],
3338 has_root: false,
3339 is_absolute: false,
c34b1796 3340 parent: Some(""),
85aaf69f
SL
3341 file_name: None,
3342 file_stem: None,
3343 extension: None
3344 );
3345
3346 t!("./",
c34b1796 3347 iter: ["."],
85aaf69f
SL
3348 has_root: false,
3349 is_absolute: false,
c34b1796 3350 parent: Some(""),
85aaf69f
SL
3351 file_name: None,
3352 file_stem: None,
3353 extension: None
3354 );
3355
3356 t!("a/b",
3357 iter: ["a", "b"],
3358 has_root: false,
3359 is_absolute: false,
3360 parent: Some("a"),
3361 file_name: Some("b"),
3362 file_stem: Some("b"),
3363 extension: None
3364 );
3365
3366 t!("a//b",
3367 iter: ["a", "b"],
3368 has_root: false,
3369 is_absolute: false,
3370 parent: Some("a"),
3371 file_name: Some("b"),
3372 file_stem: Some("b"),
3373 extension: None
3374 );
3375
3376 t!("a/./b",
c34b1796 3377 iter: ["a", "b"],
85aaf69f
SL
3378 has_root: false,
3379 is_absolute: false,
c34b1796 3380 parent: Some("a"),
85aaf69f
SL
3381 file_name: Some("b"),
3382 file_stem: Some("b"),
3383 extension: None
3384 );
3385
3386 t!("a/b/c",
3387 iter: ["a", "b", "c"],
3388 has_root: false,
3389 is_absolute: false,
3390 parent: Some("a/b"),
3391 file_name: Some("c"),
3392 file_stem: Some("c"),
3393 extension: None);
3394
3395 t!("a\\b\\c",
3396 iter: ["a", "b", "c"],
3397 has_root: false,
3398 is_absolute: false,
3399 parent: Some("a\\b"),
3400 file_name: Some("c"),
3401 file_stem: Some("c"),
3402 extension: None
3403 );
3404
3405 t!("\\a",
3406 iter: ["\\", "a"],
3407 has_root: true,
3408 is_absolute: false,
3409 parent: Some("\\"),
3410 file_name: Some("a"),
3411 file_stem: Some("a"),
3412 extension: None
3413 );
3414
3415 t!("c:\\foo.txt",
3416 iter: ["c:", "\\", "foo.txt"],
3417 has_root: true,
3418 is_absolute: true,
3419 parent: Some("c:\\"),
3420 file_name: Some("foo.txt"),
3421 file_stem: Some("foo"),
3422 extension: Some("txt")
3423 );
3424
3425 t!("\\\\server\\share\\foo.txt",
3426 iter: ["\\\\server\\share", "\\", "foo.txt"],
3427 has_root: true,
3428 is_absolute: true,
3429 parent: Some("\\\\server\\share\\"),
3430 file_name: Some("foo.txt"),
3431 file_stem: Some("foo"),
3432 extension: Some("txt")
3433 );
3434
3435 t!("\\\\server\\share",
c34b1796 3436 iter: ["\\\\server\\share", "\\"],
85aaf69f
SL
3437 has_root: true,
3438 is_absolute: true,
3439 parent: None,
3440 file_name: None,
3441 file_stem: None,
3442 extension: None
3443 );
3444
3445 t!("\\\\server",
3446 iter: ["\\", "server"],
3447 has_root: true,
3448 is_absolute: false,
3449 parent: Some("\\"),
3450 file_name: Some("server"),
3451 file_stem: Some("server"),
3452 extension: None
3453 );
3454
3455 t!("\\\\?\\bar\\foo.txt",
3456 iter: ["\\\\?\\bar", "\\", "foo.txt"],
3457 has_root: true,
3458 is_absolute: true,
3459 parent: Some("\\\\?\\bar\\"),
3460 file_name: Some("foo.txt"),
3461 file_stem: Some("foo"),
3462 extension: Some("txt")
3463 );
3464
3465 t!("\\\\?\\bar",
3466 iter: ["\\\\?\\bar"],
3467 has_root: true,
3468 is_absolute: true,
3469 parent: None,
3470 file_name: None,
3471 file_stem: None,
3472 extension: None
3473 );
3474
3475 t!("\\\\?\\",
3476 iter: ["\\\\?\\"],
3477 has_root: true,
3478 is_absolute: true,
3479 parent: None,
3480 file_name: None,
3481 file_stem: None,
3482 extension: None
3483 );
3484
3485 t!("\\\\?\\UNC\\server\\share\\foo.txt",
3486 iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"],
3487 has_root: true,
3488 is_absolute: true,
3489 parent: Some("\\\\?\\UNC\\server\\share\\"),
3490 file_name: Some("foo.txt"),
3491 file_stem: Some("foo"),
3492 extension: Some("txt")
3493 );
3494
3495 t!("\\\\?\\UNC\\server",
3496 iter: ["\\\\?\\UNC\\server"],
3497 has_root: true,
3498 is_absolute: true,
3499 parent: None,
3500 file_name: None,
3501 file_stem: None,
3502 extension: None
3503 );
3504
3505 t!("\\\\?\\UNC\\",
3506 iter: ["\\\\?\\UNC\\"],
3507 has_root: true,
3508 is_absolute: true,
3509 parent: None,
3510 file_name: None,
3511 file_stem: None,
3512 extension: None
3513 );
3514
3515 t!("\\\\?\\C:\\foo.txt",
3516 iter: ["\\\\?\\C:", "\\", "foo.txt"],
3517 has_root: true,
3518 is_absolute: true,
3519 parent: Some("\\\\?\\C:\\"),
3520 file_name: Some("foo.txt"),
3521 file_stem: Some("foo"),
3522 extension: Some("txt")
3523 );
3524
3525
3526 t!("\\\\?\\C:\\",
c34b1796 3527 iter: ["\\\\?\\C:", "\\"],
85aaf69f
SL
3528 has_root: true,
3529 is_absolute: true,
3530 parent: None,
3531 file_name: None,
3532 file_stem: None,
3533 extension: None
3534 );
3535
3536
3537 t!("\\\\?\\C:",
3538 iter: ["\\\\?\\C:"],
3539 has_root: true,
3540 is_absolute: true,
3541 parent: None,
3542 file_name: None,
3543 file_stem: None,
3544 extension: None
3545 );
3546
3547
3548 t!("\\\\?\\foo/bar",
3549 iter: ["\\\\?\\foo/bar"],
3550 has_root: true,
3551 is_absolute: true,
3552 parent: None,
3553 file_name: None,
3554 file_stem: None,
3555 extension: None
3556 );
3557
3558
3559 t!("\\\\?\\C:/foo",
3560 iter: ["\\\\?\\C:/foo"],
3561 has_root: true,
3562 is_absolute: true,
3563 parent: None,
3564 file_name: None,
3565 file_stem: None,
3566 extension: None
3567 );
3568
3569
3570 t!("\\\\.\\foo\\bar",
3571 iter: ["\\\\.\\foo", "\\", "bar"],
3572 has_root: true,
3573 is_absolute: true,
3574 parent: Some("\\\\.\\foo\\"),
3575 file_name: Some("bar"),
3576 file_stem: Some("bar"),
3577 extension: None
3578 );
3579
3580
3581 t!("\\\\.\\foo",
c34b1796 3582 iter: ["\\\\.\\foo", "\\"],
85aaf69f
SL
3583 has_root: true,
3584 is_absolute: true,
3585 parent: None,
3586 file_name: None,
3587 file_stem: None,
3588 extension: None
3589 );
3590
3591
3592 t!("\\\\.\\foo/bar",
c34b1796 3593 iter: ["\\\\.\\foo/bar", "\\"],
85aaf69f
SL
3594 has_root: true,
3595 is_absolute: true,
3596 parent: None,
3597 file_name: None,
3598 file_stem: None,
3599 extension: None
3600 );
3601
3602
3603 t!("\\\\.\\foo\\bar/baz",
3604 iter: ["\\\\.\\foo", "\\", "bar", "baz"],
3605 has_root: true,
3606 is_absolute: true,
3607 parent: Some("\\\\.\\foo\\bar"),
3608 file_name: Some("baz"),
3609 file_stem: Some("baz"),
3610 extension: None
3611 );
3612
3613
3614 t!("\\\\.\\",
c34b1796 3615 iter: ["\\\\.\\", "\\"],
85aaf69f
SL
3616 has_root: true,
3617 is_absolute: true,
3618 parent: None,
3619 file_name: None,
3620 file_stem: None,
3621 extension: None
3622 );
3623
3624 t!("\\\\?\\a\\b\\",
c34b1796 3625 iter: ["\\\\?\\a", "\\", "b"],
85aaf69f
SL
3626 has_root: true,
3627 is_absolute: true,
c34b1796
AL
3628 parent: Some("\\\\?\\a\\"),
3629 file_name: Some("b"),
3630 file_stem: Some("b"),
85aaf69f
SL
3631 extension: None
3632 );
3633 }
3634
3635 #[test]
3636 pub fn test_stem_ext() {
3637 t!("foo",
3638 file_stem: Some("foo"),
3639 extension: None
3640 );
3641
3642 t!("foo.",
3643 file_stem: Some("foo"),
3644 extension: Some("")
3645 );
3646
3647 t!(".foo",
3648 file_stem: Some(".foo"),
3649 extension: None
3650 );
3651
3652 t!("foo.txt",
3653 file_stem: Some("foo"),
3654 extension: Some("txt")
3655 );
3656
3657 t!("foo.bar.txt",
3658 file_stem: Some("foo.bar"),
3659 extension: Some("txt")
3660 );
3661
3662 t!("foo.bar.",
3663 file_stem: Some("foo.bar"),
3664 extension: Some("")
3665 );
3666
3667 t!(".",
3668 file_stem: None,
3669 extension: None
3670 );
3671
3672 t!("..",
3673 file_stem: None,
3674 extension: None
3675 );
3676
3677 t!("",
3678 file_stem: None,
3679 extension: None
3680 );
3681 }
3682
3683 #[test]
3684 pub fn test_push() {
3685 macro_rules! tp(
3686 ($path:expr, $push:expr, $expected:expr) => ( {
c34b1796 3687 let mut actual = PathBuf::from($path);
85aaf69f
SL
3688 actual.push($push);
3689 assert!(actual.to_str() == Some($expected),
3690 "pushing {:?} onto {:?}: Expected {:?}, got {:?}",
3691 $push, $path, $expected, actual.to_str().unwrap());
3692 });
3693 );
3694
3695 if cfg!(unix) {
3696 tp!("", "foo", "foo");
3697 tp!("foo", "bar", "foo/bar");
3698 tp!("foo/", "bar", "foo/bar");
3699 tp!("foo//", "bar", "foo//bar");
3700 tp!("foo/.", "bar", "foo/./bar");
3701 tp!("foo./.", "bar", "foo././bar");
3702 tp!("foo", "", "foo/");
3703 tp!("foo", ".", "foo/.");
3704 tp!("foo", "..", "foo/..");
3705 tp!("foo", "/", "/");
3706 tp!("/foo/bar", "/", "/");
3707 tp!("/foo/bar", "/baz", "/baz");
3708 tp!("/foo/bar", "./baz", "/foo/bar/./baz");
3709 } else {
3710 tp!("", "foo", "foo");
3711 tp!("foo", "bar", r"foo\bar");
3712 tp!("foo/", "bar", r"foo/bar");
3713 tp!(r"foo\", "bar", r"foo\bar");
3714 tp!("foo//", "bar", r"foo//bar");
3715 tp!(r"foo\\", "bar", r"foo\\bar");
3716 tp!("foo/.", "bar", r"foo/.\bar");
3717 tp!("foo./.", "bar", r"foo./.\bar");
3718 tp!(r"foo\.", "bar", r"foo\.\bar");
3719 tp!(r"foo.\.", "bar", r"foo.\.\bar");
3720 tp!("foo", "", "foo\\");
3721 tp!("foo", ".", r"foo\.");
3722 tp!("foo", "..", r"foo\..");
3723 tp!("foo", "/", "/");
3724 tp!("foo", r"\", r"\");
3725 tp!("/foo/bar", "/", "/");
3726 tp!(r"\foo\bar", r"\", r"\");
3727 tp!("/foo/bar", "/baz", "/baz");
3728 tp!("/foo/bar", r"\baz", r"\baz");
3729 tp!("/foo/bar", "./baz", r"/foo/bar\./baz");
3730 tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz");
3731
3732 tp!("c:\\", "windows", "c:\\windows");
3733 tp!("c:", "windows", "c:windows");
3734
3735 tp!("a\\b\\c", "d", "a\\b\\c\\d");
3736 tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d");
3737 tp!("a\\b", "c\\d", "a\\b\\c\\d");
3738 tp!("a\\b", "\\c\\d", "\\c\\d");
3739 tp!("a\\b", ".", "a\\b\\.");
3740 tp!("a\\b", "..\\c", "a\\b\\..\\c");
3741 tp!("a\\b", "C:a.txt", "C:a.txt");
3742 tp!("a\\b", "C:\\a.txt", "C:\\a.txt");
3743 tp!("C:\\a", "C:\\b.txt", "C:\\b.txt");
3744 tp!("C:\\a\\b\\c", "C:d", "C:d");
3745 tp!("C:a\\b\\c", "C:d", "C:d");
3746 tp!("C:", r"a\b\c", r"C:a\b\c");
3747 tp!("C:", r"..\a", r"C:..\a");
92a42be0
SL
3748 tp!("\\\\server\\share\\foo",
3749 "bar",
3750 "\\\\server\\share\\foo\\bar");
85aaf69f
SL
3751 tp!("\\\\server\\share\\foo", "C:baz", "C:baz");
3752 tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d");
3753 tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d");
3754 tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d");
3755 tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz");
92a42be0
SL
3756 tp!("\\\\?\\UNC\\server\\share\\foo",
3757 "bar",
3758 "\\\\?\\UNC\\server\\share\\foo\\bar");
85aaf69f
SL
3759 tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a");
3760 tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a");
3761
3762 // Note: modified from old path API
3763 tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo");
3764
92a42be0
SL
3765 tp!("C:\\a",
3766 "\\\\?\\UNC\\server\\share",
3767 "\\\\?\\UNC\\server\\share");
85aaf69f
SL
3768 tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz");
3769 tp!("\\\\.\\foo\\bar", "C:a", "C:a");
3770 // again, not sure about the following, but I'm assuming \\.\ should be verbatim
3771 tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar");
3772
3773 tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one
3774 }
3775 }
3776
3777 #[test]
3778 pub fn test_pop() {
3779 macro_rules! tp(
3780 ($path:expr, $expected:expr, $output:expr) => ( {
c34b1796 3781 let mut actual = PathBuf::from($path);
85aaf69f
SL
3782 let output = actual.pop();
3783 assert!(actual.to_str() == Some($expected) && output == $output,
3784 "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
3785 $path, $expected, $output,
3786 actual.to_str().unwrap(), output);
3787 });
3788 );
3789
3790 tp!("", "", false);
3791 tp!("/", "/", false);
c34b1796
AL
3792 tp!("foo", "", true);
3793 tp!(".", "", true);
85aaf69f
SL
3794 tp!("/foo", "/", true);
3795 tp!("/foo/bar", "/foo", true);
3796 tp!("foo/bar", "foo", true);
c34b1796 3797 tp!("foo/.", "", true);
85aaf69f
SL
3798 tp!("foo//bar", "foo", true);
3799
3800 if cfg!(windows) {
3801 tp!("a\\b\\c", "a\\b", true);
3802 tp!("\\a", "\\", true);
3803 tp!("\\", "\\", false);
3804
3805 tp!("C:\\a\\b", "C:\\a", true);
3806 tp!("C:\\a", "C:\\", true);
3807 tp!("C:\\", "C:\\", false);
3808 tp!("C:a\\b", "C:a", true);
3809 tp!("C:a", "C:", true);
3810 tp!("C:", "C:", false);
3811 tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true);
3812 tp!("\\\\server\\share\\a", "\\\\server\\share\\", true);
3813 tp!("\\\\server\\share", "\\\\server\\share", false);
3814 tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true);
3815 tp!("\\\\?\\a\\b", "\\\\?\\a\\", true);
3816 tp!("\\\\?\\a", "\\\\?\\a", false);
3817 tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true);
3818 tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true);
3819 tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false);
92a42be0
SL
3820 tp!("\\\\?\\UNC\\server\\share\\a\\b",
3821 "\\\\?\\UNC\\server\\share\\a",
3822 true);
3823 tp!("\\\\?\\UNC\\server\\share\\a",
3824 "\\\\?\\UNC\\server\\share\\",
3825 true);
3826 tp!("\\\\?\\UNC\\server\\share",
3827 "\\\\?\\UNC\\server\\share",
3828 false);
85aaf69f
SL
3829 tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true);
3830 tp!("\\\\.\\a\\b", "\\\\.\\a\\", true);
3831 tp!("\\\\.\\a", "\\\\.\\a", false);
3832
c34b1796 3833 tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true);
85aaf69f
SL
3834 }
3835 }
3836
3837 #[test]
3838 pub fn test_set_file_name() {
3839 macro_rules! tfn(
3840 ($path:expr, $file:expr, $expected:expr) => ( {
c34b1796 3841 let mut p = PathBuf::from($path);
85aaf69f
SL
3842 p.set_file_name($file);
3843 assert!(p.to_str() == Some($expected),
3844 "setting file name of {:?} to {:?}: Expected {:?}, got {:?}",
3845 $path, $file, $expected,
3846 p.to_str().unwrap());
3847 });
3848 );
3849
3850 tfn!("foo", "foo", "foo");
3851 tfn!("foo", "bar", "bar");
3852 tfn!("foo", "", "");
3853 tfn!("", "foo", "foo");
3854 if cfg!(unix) {
3855 tfn!(".", "foo", "./foo");
c34b1796
AL
3856 tfn!("foo/", "bar", "bar");
3857 tfn!("foo/.", "bar", "bar");
85aaf69f
SL
3858 tfn!("..", "foo", "../foo");
3859 tfn!("foo/..", "bar", "foo/../bar");
3860 tfn!("/", "foo", "/foo");
3861 } else {
3862 tfn!(".", "foo", r".\foo");
c34b1796
AL
3863 tfn!(r"foo\", "bar", r"bar");
3864 tfn!(r"foo\.", "bar", r"bar");
85aaf69f
SL
3865 tfn!("..", "foo", r"..\foo");
3866 tfn!(r"foo\..", "bar", r"foo\..\bar");
3867 tfn!(r"\", "foo", r"\foo");
3868 }
3869 }
3870
3871 #[test]
3872 pub fn test_set_extension() {
3873 macro_rules! tfe(
3874 ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( {
c34b1796 3875 let mut p = PathBuf::from($path);
85aaf69f
SL
3876 let output = p.set_extension($ext);
3877 assert!(p.to_str() == Some($expected) && output == $output,
3878 "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}",
3879 $path, $ext, $expected, $output,
3880 p.to_str().unwrap(), output);
3881 });
3882 );
3883
3884 tfe!("foo", "txt", "foo.txt", true);
3885 tfe!("foo.bar", "txt", "foo.txt", true);
3886 tfe!("foo.bar.baz", "txt", "foo.bar.txt", true);
3887 tfe!(".test", "txt", ".test.txt", true);
3888 tfe!("foo.txt", "", "foo", true);
3889 tfe!("foo", "", "foo", true);
3890 tfe!("", "foo", "", false);
3891 tfe!(".", "foo", ".", false);
c34b1796
AL
3892 tfe!("foo/", "bar", "foo.bar", true);
3893 tfe!("foo/.", "bar", "foo.bar", true);
92a42be0 3894 tfe!("..", "foo", "..", false);
85aaf69f
SL
3895 tfe!("foo/..", "bar", "foo/..", false);
3896 tfe!("/", "foo", "/", false);
3897 }
3898
92a42be0 3899 #[test]
ff7c6d11 3900 fn test_eq_receivers() {
92a42be0
SL
3901 use borrow::Cow;
3902
3903 let borrowed: &Path = Path::new("foo/bar");
3904 let mut owned: PathBuf = PathBuf::new();
3905 owned.push("foo");
3906 owned.push("bar");
3907 let borrowed_cow: Cow<Path> = borrowed.into();
3908 let owned_cow: Cow<Path> = owned.clone().into();
3909
3910 macro_rules! t {
3911 ($($current:expr),+) => {
3912 $(
3913 assert_eq!($current, borrowed);
3914 assert_eq!($current, owned);
3915 assert_eq!($current, borrowed_cow);
3916 assert_eq!($current, owned_cow);
3917 )+
3918 }
3919 }
3920
3921 t!(borrowed, owned, borrowed_cow, owned_cow);
3922 }
3923
85aaf69f
SL
3924 #[test]
3925 pub fn test_compare() {
9e0c209e
SL
3926 use hash::{Hash, Hasher};
3927 use collections::hash_map::DefaultHasher;
92a42be0
SL
3928
3929 fn hash<T: Hash>(t: T) -> u64 {
9e0c209e 3930 let mut s = DefaultHasher::new();
92a42be0
SL
3931 t.hash(&mut s);
3932 s.finish()
3933 }
3934
85aaf69f
SL
3935 macro_rules! tc(
3936 ($path1:expr, $path2:expr, eq: $eq:expr,
3937 starts_with: $starts_with:expr, ends_with: $ends_with:expr,
3938 relative_from: $relative_from:expr) => ({
3939 let path1 = Path::new($path1);
3940 let path2 = Path::new($path2);
3941
3942 let eq = path1 == path2;
3943 assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}",
3944 $path1, $path2, $eq, eq);
92a42be0
SL
3945 assert!($eq == (hash(path1) == hash(path2)),
3946 "{:?} == {:?}, expected {:?}, got {} and {}",
3947 $path1, $path2, $eq, hash(path1), hash(path2));
85aaf69f
SL
3948
3949 let starts_with = path1.starts_with(path2);
3950 assert!(starts_with == $starts_with,
3951 "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2,
3952 $starts_with, starts_with);
3953
3954 let ends_with = path1.ends_with(path2);
3955 assert!(ends_with == $ends_with,
3956 "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2,
3957 $ends_with, ends_with);
3958
7453a54e
SL
3959 let relative_from = path1.strip_prefix(path2)
3960 .map(|p| p.to_str().unwrap())
3961 .ok();
85aaf69f
SL
3962 let exp: Option<&str> = $relative_from;
3963 assert!(relative_from == exp,
7453a54e
SL
3964 "{:?}.strip_prefix({:?}), expected {:?}, got {:?}",
3965 $path1, $path2, exp, relative_from);
85aaf69f
SL
3966 });
3967 );
3968
3969 tc!("", "",
3970 eq: true,
3971 starts_with: true,
3972 ends_with: true,
3973 relative_from: Some("")
3974 );
3975
3976 tc!("foo", "",
3977 eq: false,
3978 starts_with: true,
3979 ends_with: true,
3980 relative_from: Some("foo")
3981 );
3982
3983 tc!("", "foo",
3984 eq: false,
3985 starts_with: false,
3986 ends_with: false,
3987 relative_from: None
3988 );
3989
3990 tc!("foo", "foo",
3991 eq: true,
3992 starts_with: true,
3993 ends_with: true,
3994 relative_from: Some("")
3995 );
3996
3997 tc!("foo/", "foo",
c34b1796 3998 eq: true,
85aaf69f 3999 starts_with: true,
c34b1796
AL
4000 ends_with: true,
4001 relative_from: Some("")
85aaf69f
SL
4002 );
4003
4004 tc!("foo/bar", "foo",
4005 eq: false,
4006 starts_with: true,
4007 ends_with: false,
4008 relative_from: Some("bar")
4009 );
4010
4011 tc!("foo/bar/baz", "foo/bar",
4012 eq: false,
4013 starts_with: true,
4014 ends_with: false,
4015 relative_from: Some("baz")
4016 );
4017
4018 tc!("foo/bar", "foo/bar/baz",
4019 eq: false,
4020 starts_with: false,
4021 ends_with: false,
4022 relative_from: None
4023 );
4024
4025 tc!("./foo/bar/", ".",
4026 eq: false,
4027 starts_with: true,
c34b1796
AL
4028 ends_with: false,
4029 relative_from: Some("foo/bar")
85aaf69f 4030 );
c34b1796
AL
4031
4032 if cfg!(windows) {
4033 tc!(r"C:\src\rust\cargo-test\test\Cargo.toml",
4034 r"c:\src\rust\cargo-test\test",
4035 eq: false,
4036 starts_with: true,
4037 ends_with: false,
4038 relative_from: Some("Cargo.toml")
4039 );
4040
4041 tc!(r"c:\foo", r"C:\foo",
4042 eq: true,
4043 starts_with: true,
4044 ends_with: true,
4045 relative_from: Some("")
4046 );
4047 }
85aaf69f 4048 }
9e0c209e
SL
4049
4050 #[test]
4051 fn test_components_debug() {
4052 let path = Path::new("/tmp");
4053
4054 let mut components = path.components();
4055
4056 let expected = "Components([RootDir, Normal(\"tmp\")])";
4057 let actual = format!("{:?}", components);
4058 assert_eq!(expected, actual);
4059
4060 let _ = components.next().unwrap();
4061 let expected = "Components([Normal(\"tmp\")])";
4062 let actual = format!("{:?}", components);
4063 assert_eq!(expected, actual);
4064
4065 let _ = components.next().unwrap();
4066 let expected = "Components([])";
4067 let actual = format!("{:?}", components);
4068 assert_eq!(expected, actual);
4069 }
4070
4071 #[cfg(unix)]
4072 #[test]
4073 fn test_iter_debug() {
4074 let path = Path::new("/tmp");
4075
4076 let mut iter = path.iter();
4077
4078 let expected = "Iter([\"/\", \"tmp\"])";
4079 let actual = format!("{:?}", iter);
4080 assert_eq!(expected, actual);
4081
4082 let _ = iter.next().unwrap();
4083 let expected = "Iter([\"tmp\"])";
4084 let actual = format!("{:?}", iter);
4085 assert_eq!(expected, actual);
4086
4087 let _ = iter.next().unwrap();
4088 let expected = "Iter([])";
4089 let actual = format!("{:?}", iter);
4090 assert_eq!(expected, actual);
4091 }
8bb4bdeb
XL
4092
4093 #[test]
4094 fn into_boxed() {
4095 let orig: &str = "some/sort/of/path";
4096 let path = Path::new(orig);
cc61c64b
XL
4097 let boxed: Box<Path> = Box::from(path);
4098 let path_buf = path.to_owned().into_boxed_path().into_path_buf();
4099 assert_eq!(path, &*boxed);
4100 assert_eq!(&*boxed, &*path_buf);
4101 assert_eq!(&*path_buf, path);
4102 }
4103
4104 #[test]
4105 fn test_clone_into() {
4106 let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious");
4107 let path = Path::new("short");
4108 path.clone_into(&mut path_buf);
4109 assert_eq!(path, path_buf);
4110 assert!(path_buf.into_os_string().capacity() >= 15);
8bb4bdeb 4111 }
041b39d2
XL
4112
4113 #[test]
4114 fn display_format_flags() {
4115 assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b");
4116 assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b");
4117 }
ff7c6d11
XL
4118
4119 #[test]
4120 fn into_rc() {
4121 let orig = "hello/world";
4122 let path = Path::new(orig);
4123 let rc: Rc<Path> = Rc::from(path);
4124 let arc: Arc<Path> = Arc::from(path);
4125
4126 assert_eq!(&*rc, path);
4127 assert_eq!(&*arc, path);
4128
4129 let rc2: Rc<Path> = Rc::from(path.to_owned());
4130 let arc2: Arc<Path> = Arc::from(path.to_owned());
4131
4132 assert_eq!(&*rc2, path);
4133 assert_eq!(&*arc2, path);
4134 }
85aaf69f 4135}