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