> FromIterator for PathBuf {
+ /// Creates a new `PathBuf` from the [`Path`] elements of an iterator.
+ ///
+ /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+ /// [components](Components).
+ ///
+ /// # Examples
+ /// ```
+ /// # use std::path::PathBuf;
+ /// let path = PathBuf::from_iter(["/tmp", "foo", "bar"]);
+ /// assert_eq!(path, PathBuf::from("/tmp/foo/bar"));
+ /// ```
+ ///
+ /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
+ fn from_iter>(iter: I) -> PathBuf {
+ let mut buf = PathBuf::new();
+ buf.extend(iter);
+ buf
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl> Extend for PathBuf {
+ /// Extends `self` with [`Path`] elements from `iter`.
+ ///
+ /// This uses [`push`](Self::push) to add each element, so can be used to adjoin multiple path
+ /// [components](Components).
+ ///
+ /// # Examples
+ /// ```
+ /// # use std::path::PathBuf;
+ /// let mut path = PathBuf::from("/tmp");
+ /// path.extend(["foo", "bar", "file.txt"]);
+ /// assert_eq!(path, PathBuf::from("/tmp/foo/bar/file.txt"));
+ /// ```
+ ///
+ /// See documentation for [`push`](Self::push) for more details on how the path is constructed.
+ fn extend>(&mut self, iter: I) {
+ iter.into_iter().for_each(move |p| self.push(p.as_ref()));
+ }
+
+ #[inline]
+ fn extend_one(&mut self, p: P) {
+ self.push(p.as_ref());
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for PathBuf {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&**self, formatter)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ops::Deref for PathBuf {
+ type Target = Path;
+ #[inline]
+ fn deref(&self) -> &Path {
+ Path::new(&self.inner)
+ }
+}
+
+#[stable(feature = "path_buf_deref_mut", since = "1.68.0")]
+impl ops::DerefMut for PathBuf {
+ #[inline]
+ fn deref_mut(&mut self) -> &mut Path {
+ Path::from_inner_mut(&mut self.inner)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Borrow for PathBuf {
+ #[inline]
+ fn borrow(&self) -> &Path {
+ self.deref()
+ }
+}
+
+#[stable(feature = "default_for_pathbuf", since = "1.17.0")]
+impl Default for PathBuf {
+ #[inline]
+ fn default() -> Self {
+ PathBuf::new()
+ }
+}
+
+#[stable(feature = "cow_from_path", since = "1.6.0")]
+impl<'a> From<&'a Path> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`Path`].
+ ///
+ /// This conversion does not clone or allocate.
+ #[inline]
+ fn from(s: &'a Path) -> Cow<'a, Path> {
+ Cow::Borrowed(s)
+ }
+}
+
+#[stable(feature = "cow_from_path", since = "1.6.0")]
+impl<'a> From for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from an owned
+ /// instance of [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
+ #[inline]
+ fn from(s: PathBuf) -> Cow<'a, Path> {
+ Cow::Owned(s)
+ }
+}
+
+#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
+impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
+ /// Creates a clone-on-write pointer from a reference to
+ /// [`PathBuf`].
+ ///
+ /// This conversion does not clone or allocate.
+ #[inline]
+ fn from(p: &'a PathBuf) -> Cow<'a, Path> {
+ Cow::Borrowed(p.as_path())
+ }
+}
+
+#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
+impl<'a> From> for PathBuf {
+ /// Converts a clone-on-write pointer to an owned path.
+ ///
+ /// Converting from a `Cow::Owned` does not clone or allocate.
+ #[inline]
+ fn from(p: Cow<'a, Path>) -> Self {
+ p.into_owned()
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From for Arc {
+ /// Converts a [`PathBuf`] into an [Arc]<[Path]> by moving the [`PathBuf`] data
+ /// into a new [`Arc`] buffer.
+ #[inline]
+ fn from(s: PathBuf) -> Arc {
+ let arc: Arc = Arc::from(s.into_os_string());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&Path> for Arc {
+ /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer.
+ #[inline]
+ fn from(s: &Path) -> Arc {
+ let arc: Arc = Arc::from(s.as_os_str());
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_mut_slice", since = "1.84.0")]
+impl From<&mut Path> for Arc {
+ /// Converts a [`Path`] into an [`Arc`] by copying the [`Path`] data into a new [`Arc`] buffer.
+ #[inline]
+ fn from(s: &mut Path) -> Arc {
+ Arc::from(&*s)
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From for Rc {
+ /// Converts a [`PathBuf`] into an [Rc]<[Path]> by moving the [`PathBuf`] data into
+ /// a new [`Rc`] buffer.
+ #[inline]
+ fn from(s: PathBuf) -> Rc {
+ let rc: Rc = Rc::from(s.into_os_string());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_slice2", since = "1.24.0")]
+impl From<&Path> for Rc {
+ /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer.
+ #[inline]
+ fn from(s: &Path) -> Rc {
+ let rc: Rc = Rc::from(s.as_os_str());
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Path) }
+ }
+}
+
+#[stable(feature = "shared_from_mut_slice", since = "1.84.0")]
+impl From<&mut Path> for Rc {
+ /// Converts a [`Path`] into an [`Rc`] by copying the [`Path`] data into a new [`Rc`] buffer.
+ #[inline]
+ fn from(s: &mut Path) -> Rc {
+ Rc::from(&*s)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ToOwned for Path {
+ type Owned = PathBuf;
+ #[inline]
+ fn to_owned(&self) -> PathBuf {
+ self.to_path_buf()
+ }
+ #[inline]
+ fn clone_into(&self, target: &mut PathBuf) {
+ self.inner.clone_into(&mut target.inner);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for PathBuf {
+ #[inline]
+ fn eq(&self, other: &PathBuf) -> bool {
+ self.components() == other.components()
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for PathBuf {
+ #[inline]
+ fn eq(&self, other: &str) -> bool {
+ self.as_path() == other
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for str {
+ #[inline]
+ fn eq(&self, other: &PathBuf) -> bool {
+ self == other.as_path()
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for PathBuf {
+ #[inline]
+ fn eq(&self, other: &String) -> bool {
+ self.as_path() == other.as_str()
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for String {
+ #[inline]
+ fn eq(&self, other: &PathBuf) -> bool {
+ self.as_str() == other.as_path()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for PathBuf {
+ fn hash(&self, h: &mut H) {
+ self.as_path().hash(h)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for PathBuf {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for PathBuf {
+ #[inline]
+ fn partial_cmp(&self, other: &PathBuf) -> Option {
+ Some(compare_components(self.components(), other.components()))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for PathBuf {
+ #[inline]
+ fn cmp(&self, other: &PathBuf) -> cmp::Ordering {
+ compare_components(self.components(), other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef for PathBuf {
+ #[inline]
+ fn as_ref(&self) -> &OsStr {
+ &self.inner[..]
+ }
+}
+
+/// A slice of a path (akin to [`str`]).
+///
+/// This type supports a number of operations for inspecting a path, including
+/// breaking the path into its components (separated by `/` on Unix and by either
+/// `/` or `\` on Windows), extracting the file name, determining whether the path
+/// is absolute, and so on.
+///
+/// This is an *unsized* type, meaning that it must always be used behind a
+/// pointer like `&` or [`Box`]. For an owned version of this type,
+/// see [`PathBuf`].
+///
+/// More details about the overall approach can be found in
+/// the [module documentation](self).
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+/// use std::ffi::OsStr;
+///
+/// // Note: this example does work on Windows
+/// let path = Path::new("./foo/bar.txt");
+///
+/// let parent = path.parent();
+/// assert_eq!(parent, Some(Path::new("./foo")));
+///
+/// let file_stem = path.file_stem();
+/// assert_eq!(file_stem, Some(OsStr::new("bar")));
+///
+/// let extension = path.extension();
+/// assert_eq!(extension, Some(OsStr::new("txt")));
+/// ```
+#[cfg_attr(not(test), rustc_diagnostic_item = "Path")]
+#[stable(feature = "rust1", since = "1.0.0")]
+// `Path::new` and `impl CloneToUninit for Path` current implementation relies
+// on `Path` being layout-compatible with `OsStr`.
+// However, `Path` layout is considered an implementation detail and must not be relied upon.
+#[repr(transparent)]
+pub struct Path {
+ inner: OsStr,
+}
+
+/// An error returned from [`Path::strip_prefix`] if the prefix was not found.
+///
+/// This `struct` is created by the [`strip_prefix`] method on [`Path`].
+/// See its documentation for more.
+///
+/// [`strip_prefix`]: Path::strip_prefix
+#[derive(Debug, Clone, PartialEq, Eq)]
+#[stable(since = "1.7.0", feature = "strip_prefix")]
+pub struct StripPrefixError(());
+
+/// An error returned from [`Path::normalize_lexically`] if a `..` parent reference
+/// would escape the path.
+#[unstable(feature = "normalize_lexically", issue = "134694")]
+#[derive(Debug, PartialEq)]
+#[non_exhaustive]
+pub struct NormalizeError;
+
+impl Path {
+ // The following (private!) function allows construction of a path from a u8
+ // slice, which is only safe when it is known to follow the OsStr encoding.
+ unsafe fn from_u8_slice(s: &[u8]) -> &Path {
+ unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) }
+ }
+ // The following (private!) function reveals the byte encoding used for OsStr.
+ pub(crate) fn as_u8_slice(&self) -> &[u8] {
+ self.inner.as_encoded_bytes()
+ }
+
+ /// Directly wraps a string slice as a `Path` slice.
+ ///
+ /// This is a cost-free conversion.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// Path::new("foo.txt");
+ /// ```
+ ///
+ /// You can create `Path`s from `String`s, or even other `Path`s:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let string = String::from("foo.txt");
+ /// let from_string = Path::new(&string);
+ /// let from_path = Path::new(&from_string);
+ /// assert_eq!(from_string, from_path);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+ pub const fn new + ?Sized>(s: &S) -> &Path {
+ unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
+ }
+
+ #[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+ const fn from_inner_mut(inner: &mut OsStr) -> &mut Path {
+ // SAFETY: Path is just a wrapper around OsStr,
+ // therefore converting &mut OsStr to &mut Path is safe.
+ unsafe { &mut *(inner as *mut OsStr as *mut Path) }
+ }
+
+ /// Yields the underlying [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let os_str = Path::new("foo.txt").as_os_str();
+ /// assert_eq!(os_str, std::ffi::OsStr::new("foo.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ #[inline]
+ pub fn as_os_str(&self) -> &OsStr {
+ &self.inner
+ }
+
+ /// Yields a mutable reference to the underlying [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let mut path = PathBuf::from("Foo.TXT");
+ ///
+ /// assert_ne!(path, Path::new("foo.txt"));
+ ///
+ /// path.as_mut_os_str().make_ascii_lowercase();
+ /// assert_eq!(path, Path::new("foo.txt"));
+ /// ```
+ #[stable(feature = "path_as_mut_os_str", since = "1.70.0")]
+ #[must_use]
+ #[inline]
+ pub fn as_mut_os_str(&mut self) -> &mut OsStr {
+ &mut self.inner
+ }
+
+ /// Yields a [`&str`] slice if the `Path` is valid unicode.
+ ///
+ /// This conversion may entail doing a check for UTF-8 validity.
+ /// Note that validation is performed because non-UTF-8 strings are
+ /// perfectly valid for some OS.
+ ///
+ /// [`&str`]: str
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_str(), Some("foo.txt"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub fn to_str(&self) -> Option<&str> {
+ self.inner.to_str()
+ }
+
+ /// Converts a `Path` to a [`Cow`].
+ ///
+ /// Any non-UTF-8 sequences are replaced with
+ /// [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD].
+ ///
+ /// [U+FFFD]: super::char::REPLACEMENT_CHARACTER
+ ///
+ /// # Examples
+ ///
+ /// Calling `to_string_lossy` on a `Path` with valid unicode:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.txt");
+ /// assert_eq!(path.to_string_lossy(), "foo.txt");
+ /// ```
+ ///
+ /// Had `path` contained invalid unicode, the `to_string_lossy` call might
+ /// have returned `"fo�.txt"`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[inline]
+ pub fn to_string_lossy(&self) -> Cow<'_, str> {
+ self.inner.to_string_lossy()
+ }
+
+ /// Converts a `Path` to an owned [`PathBuf`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path_buf = Path::new("foo.txt").to_path_buf();
+ /// assert_eq!(path_buf, PathBuf::from("foo.txt"));
+ /// ```
+ #[rustc_conversion_suggestion]
+ #[must_use = "this returns the result of the operation, \
+ without modifying the original"]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[cfg_attr(not(test), rustc_diagnostic_item = "path_to_pathbuf")]
+ pub fn to_path_buf(&self) -> PathBuf {
+ PathBuf::from(self.inner.to_os_string())
+ }
+
+ /// Returns `true` if the `Path` is absolute, i.e., if it is independent of
+ /// the current directory.
+ ///
+ /// * On Unix, a path is absolute if it starts with the root, so
+ /// `is_absolute` and [`has_root`] are equivalent.
+ ///
+ /// * On Windows, a path is absolute if it has a prefix and starts with the
+ /// root: `c:\windows` is absolute, while `c:temp` and `\temp` are not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(!Path::new("foo.txt").is_absolute());
+ /// ```
+ ///
+ /// [`has_root`]: Path::has_root
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ #[allow(deprecated)]
+ pub fn is_absolute(&self) -> bool {
+ sys::path::is_absolute(self)
+ }
+
+ /// Returns `true` if the `Path` is relative, i.e., not absolute.
+ ///
+ /// See [`is_absolute`]'s documentation for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("foo.txt").is_relative());
+ /// ```
+ ///
+ /// [`is_absolute`]: Path::is_absolute
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ #[inline]
+ pub fn is_relative(&self) -> bool {
+ !self.is_absolute()
+ }
+
+ pub(crate) fn prefix(&self) -> Option> {
+ self.components().prefix
+ }
+
+ /// Returns `true` if the `Path` has a root.
+ ///
+ /// * On Unix, a path has a root if it begins with `/`.
+ ///
+ /// * On Windows, a path has a root if it:
+ /// * has no prefix and begins with a separator, e.g., `\windows`
+ /// * has a prefix followed by a separator, e.g., `c:\windows` but not `c:windows`
+ /// * has any non-disk prefix, e.g., `\\server\share`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("/etc/passwd").has_root());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ #[inline]
+ pub fn has_root(&self) -> bool {
+ self.components().has_root()
+ }
+
+ /// Returns the `Path` without its final component, if there is one.
+ ///
+ /// This means it returns `Some("")` for relative paths with one component.
+ ///
+ /// Returns [`None`] if the path terminates in a root or prefix, or if it's
+ /// the empty string.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/foo/bar");
+ /// let parent = path.parent().unwrap();
+ /// assert_eq!(parent, Path::new("/foo"));
+ ///
+ /// let grand_parent = parent.parent().unwrap();
+ /// assert_eq!(grand_parent, Path::new("/"));
+ /// assert_eq!(grand_parent.parent(), None);
+ ///
+ /// let relative_path = Path::new("foo/bar");
+ /// let parent = relative_path.parent();
+ /// assert_eq!(parent, Some(Path::new("foo")));
+ /// let grand_parent = parent.and_then(Path::parent);
+ /// assert_eq!(grand_parent, Some(Path::new("")));
+ /// let great_grand_parent = grand_parent.and_then(Path::parent);
+ /// assert_eq!(great_grand_parent, None);
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[doc(alias = "dirname")]
+ #[must_use]
+ pub fn parent(&self) -> Option<&Path> {
+ let mut comps = self.components();
+ let comp = comps.next_back();
+ comp.and_then(|p| match p {
+ Component::Normal(_) | Component::CurDir | Component::ParentDir => {
+ Some(comps.as_path())
+ }
+ _ => None,
+ })
+ }
+
+ /// Produces an iterator over `Path` and its ancestors.
+ ///
+ /// The iterator will yield the `Path` that is returned if the [`parent`] method is used zero
+ /// or more times. If the [`parent`] method returns [`None`], the iterator will do likewise.
+ /// The iterator will always yield at least one value, namely `Some(&self)`. Next it will yield
+ /// `&self.parent()`, `&self.parent().and_then(Path::parent)` and so on.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let mut ancestors = Path::new("/foo/bar").ancestors();
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo/bar")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/foo")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("/")));
+ /// assert_eq!(ancestors.next(), None);
+ ///
+ /// let mut ancestors = Path::new("../foo/bar").ancestors();
+ /// assert_eq!(ancestors.next(), Some(Path::new("../foo/bar")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("../foo")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("..")));
+ /// assert_eq!(ancestors.next(), Some(Path::new("")));
+ /// assert_eq!(ancestors.next(), None);
+ /// ```
+ ///
+ /// [`parent`]: Path::parent
+ #[stable(feature = "path_ancestors", since = "1.28.0")]
+ #[inline]
+ pub fn ancestors(&self) -> Ancestors<'_> {
+ Ancestors { next: Some(&self) }
+ }
+
+ /// Returns the final component of the `Path`, if there is one.
+ ///
+ /// If the path is a normal file, this is the file name. If it's the path of a directory, this
+ /// is the directory name.
+ ///
+ /// Returns [`None`] if the path terminates in `..`.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ /// use std::ffi::OsStr;
+ ///
+ /// assert_eq!(Some(OsStr::new("bin")), Path::new("/usr/bin/").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("tmp/foo.txt").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.").file_name());
+ /// assert_eq!(Some(OsStr::new("foo.txt")), Path::new("foo.txt/.//").file_name());
+ /// assert_eq!(None, Path::new("foo.txt/..").file_name());
+ /// assert_eq!(None, Path::new("/").file_name());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[doc(alias = "basename")]
+ #[must_use]
+ pub fn file_name(&self) -> Option<&OsStr> {
+ self.components().next_back().and_then(|p| match p {
+ Component::Normal(p) => Some(p),
+ _ => None,
+ })
+ }
+
+ /// Returns a path that, when joined onto `base`, yields `self`.
+ ///
+ /// # Errors
+ ///
+ /// If `base` is not a prefix of `self` (i.e., [`starts_with`]
+ /// returns `false`), returns [`Err`].
+ ///
+ /// [`starts_with`]: Path::starts_with
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/test/haha/foo.txt");
+ ///
+ /// assert_eq!(path.strip_prefix("/"), Ok(Path::new("test/haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/"), Ok(Path::new("haha/foo.txt")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt"), Ok(Path::new("")));
+ /// assert_eq!(path.strip_prefix("/test/haha/foo.txt/"), Ok(Path::new("")));
+ ///
+ /// assert!(path.strip_prefix("test").is_err());
+ /// assert!(path.strip_prefix("/te").is_err());
+ /// assert!(path.strip_prefix("/haha").is_err());
+ ///
+ /// let prefix = PathBuf::from("/test/");
+ /// assert_eq!(path.strip_prefix(prefix), Ok(Path::new("haha/foo.txt")));
+ /// ```
+ #[stable(since = "1.7.0", feature = "path_strip_prefix")]
+ pub fn strip_prefix(&self, base: P) -> Result<&Path, StripPrefixError>
+ where
+ P: AsRef,
+ {
+ self._strip_prefix(base.as_ref())
+ }
+
+ fn _strip_prefix(&self, base: &Path) -> Result<&Path, StripPrefixError> {
+ iter_after(self.components(), base.components())
+ .map(|c| c.as_path())
+ .ok_or(StripPrefixError(()))
+ }
+
+ /// Determines whether `base` is a prefix of `self`.
+ ///
+ /// Only considers whole path components to match.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/passwd");
+ ///
+ /// assert!(path.starts_with("/etc"));
+ /// assert!(path.starts_with("/etc/"));
+ /// assert!(path.starts_with("/etc/passwd"));
+ /// assert!(path.starts_with("/etc/passwd/")); // extra slash is okay
+ /// assert!(path.starts_with("/etc/passwd///")); // multiple extra slashes are okay
+ ///
+ /// assert!(!path.starts_with("/e"));
+ /// assert!(!path.starts_with("/etc/passwd.txt"));
+ ///
+ /// assert!(!Path::new("/etc/foo.rs").starts_with("/etc/foo"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn starts_with>(&self, base: P) -> bool {
+ self._starts_with(base.as_ref())
+ }
+
+ fn _starts_with(&self, base: &Path) -> bool {
+ iter_after(self.components(), base.components()).is_some()
+ }
+
+ /// Determines whether `child` is a suffix of `self`.
+ ///
+ /// Only considers whole path components to match.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/etc/resolv.conf");
+ ///
+ /// assert!(path.ends_with("resolv.conf"));
+ /// assert!(path.ends_with("etc/resolv.conf"));
+ /// assert!(path.ends_with("/etc/resolv.conf"));
+ ///
+ /// assert!(!path.ends_with("/resolv.conf"));
+ /// assert!(!path.ends_with("conf")); // use .extension() instead
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn ends_with>(&self, child: P) -> bool {
+ self._ends_with(child.as_ref())
+ }
+
+ fn _ends_with(&self, child: &Path) -> bool {
+ iter_after(self.components().rev(), child.components().rev()).is_some()
+ }
+
+ /// Checks whether the `Path` is empty.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_is_empty)]
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("");
+ /// assert!(path.is_empty());
+ ///
+ /// let path = Path::new("foo");
+ /// assert!(!path.is_empty());
+ ///
+ /// let path = Path::new(".");
+ /// assert!(!path.is_empty());
+ /// ```
+ #[unstable(feature = "path_is_empty", issue = "148494")]
+ pub fn is_empty(&self) -> bool {
+ self.as_os_str().is_empty()
+ }
+
+ /// Extracts the stem (non-extension) portion of [`self.file_name`].
+ ///
+ /// [`self.file_name`]: Path::file_name
+ ///
+ /// The stem is:
+ ///
+ /// * [`None`], if there is no file name;
+ /// * The entire file name if there is no embedded `.`;
+ /// * The entire file name if the file name begins with `.` and has no other `.`s within;
+ /// * Otherwise, the portion of the file name before the final `.`
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert_eq!("foo", Path::new("foo.rs").file_stem().unwrap());
+ /// assert_eq!("foo.tar", Path::new("foo.tar.gz").file_stem().unwrap());
+ /// ```
+ ///
+ /// # See Also
+ /// This method is similar to [`Path::file_prefix`], which extracts the portion of the file name
+ /// before the *first* `.`
+ ///
+ /// [`Path::file_prefix`]: Path::file_prefix
+ ///
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn file_stem(&self) -> Option<&OsStr> {
+ self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.or(after))
+ }
+
+ /// Extracts the prefix of [`self.file_name`].
+ ///
+ /// The prefix is:
+ ///
+ /// * [`None`], if there is no file name;
+ /// * The entire file name if there is no embedded `.`;
+ /// * The portion of the file name before the first non-beginning `.`;
+ /// * The entire file name if the file name begins with `.` and has no other `.`s within;
+ /// * The portion of the file name before the second `.` if the file name begins with `.`
+ ///
+ /// [`self.file_name`]: Path::file_name
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert_eq!("foo", Path::new("foo.rs").file_prefix().unwrap());
+ /// assert_eq!("foo", Path::new("foo.tar.gz").file_prefix().unwrap());
+ /// assert_eq!(".config", Path::new(".config").file_prefix().unwrap());
+ /// assert_eq!(".config", Path::new(".config.toml").file_prefix().unwrap());
+ /// ```
+ ///
+ /// # See Also
+ /// This method is similar to [`Path::file_stem`], which extracts the portion of the file name
+ /// before the *last* `.`
+ ///
+ /// [`Path::file_stem`]: Path::file_stem
+ ///
+ #[stable(feature = "path_file_prefix", since = "1.91.0")]
+ #[must_use]
+ pub fn file_prefix(&self) -> Option<&OsStr> {
+ self.file_name().map(split_file_at_dot).and_then(|(before, _after)| Some(before))
+ }
+
+ /// Extracts the extension (without the leading dot) of [`self.file_name`], if possible.
+ ///
+ /// The extension is:
+ ///
+ /// * [`None`], if there is no file name;
+ /// * [`None`], if there is no embedded `.`;
+ /// * [`None`], if the file name begins with `.` and has no other `.`s within;
+ /// * Otherwise, the portion of the file name after the final `.`
+ ///
+ /// [`self.file_name`]: Path::file_name
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// assert_eq!("rs", Path::new("foo.rs").extension().unwrap());
+ /// assert_eq!("gz", Path::new("foo.tar.gz").extension().unwrap());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn extension(&self) -> Option<&OsStr> {
+ self.file_name().map(rsplit_file_at_dot).and_then(|(before, after)| before.and(after))
+ }
+
+ /// Checks whether the path ends in a trailing [separator](MAIN_SEPARATOR).
+ ///
+ /// This is generally done to ensure that a path is treated as a directory, not a file,
+ /// although it does not actually guarantee that such a path is a directory on the underlying
+ /// file system.
+ ///
+ /// Despite this behavior, two paths are still considered the same in Rust whether they have a
+ /// trailing separator or not.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_trailing_sep)]
+ /// use std::path::Path;
+ ///
+ /// assert!(Path::new("dir/").has_trailing_sep());
+ /// assert!(!Path::new("file.rs").has_trailing_sep());
+ /// ```
+ #[unstable(feature = "path_trailing_sep", issue = "142503")]
+ #[must_use]
+ #[inline]
+ pub fn has_trailing_sep(&self) -> bool {
+ self.as_os_str().as_encoded_bytes().last().copied().is_some_and(is_sep_byte)
+ }
+
+ /// Ensures that a path has a trailing [separator](MAIN_SEPARATOR),
+ /// allocating a [`PathBuf`] if necessary.
+ ///
+ /// The resulting path will return true for [`has_trailing_sep`](Self::has_trailing_sep).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_trailing_sep)]
+ /// use std::ffi::OsStr;
+ /// use std::path::Path;
+ ///
+ /// assert_eq!(Path::new("dir//").with_trailing_sep().as_os_str(), OsStr::new("dir//"));
+ /// assert_eq!(Path::new("dir/").with_trailing_sep().as_os_str(), OsStr::new("dir/"));
+ /// assert!(!Path::new("dir").has_trailing_sep());
+ /// assert!(Path::new("dir").with_trailing_sep().has_trailing_sep());
+ /// ```
+ #[unstable(feature = "path_trailing_sep", issue = "142503")]
+ #[must_use]
+ #[inline]
+ pub fn with_trailing_sep(&self) -> Cow<'_, Path> {
+ if self.has_trailing_sep() { Cow::Borrowed(self) } else { Cow::Owned(self.join("")) }
+ }
+
+ /// Trims a trailing [separator](MAIN_SEPARATOR) from a path, if possible.
+ ///
+ /// The resulting path will return false for [`has_trailing_sep`](Self::has_trailing_sep) for
+ /// most paths.
+ ///
+ /// Some paths, like `/`, cannot be trimmed in this way.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_trailing_sep)]
+ /// use std::ffi::OsStr;
+ /// use std::path::Path;
+ ///
+ /// assert_eq!(Path::new("dir//").trim_trailing_sep().as_os_str(), OsStr::new("dir"));
+ /// assert_eq!(Path::new("dir/").trim_trailing_sep().as_os_str(), OsStr::new("dir"));
+ /// assert_eq!(Path::new("dir").trim_trailing_sep().as_os_str(), OsStr::new("dir"));
+ /// assert_eq!(Path::new("/").trim_trailing_sep().as_os_str(), OsStr::new("/"));
+ /// assert_eq!(Path::new("//").trim_trailing_sep().as_os_str(), OsStr::new("//"));
+ /// ```
+ #[unstable(feature = "path_trailing_sep", issue = "142503")]
+ #[must_use]
+ #[inline]
+ pub fn trim_trailing_sep(&self) -> &Path {
+ if self.has_trailing_sep() && (!self.has_root() || self.parent().is_some()) {
+ let mut bytes = self.inner.as_encoded_bytes();
+ while let Some((last, init)) = bytes.split_last()
+ && is_sep_byte(*last)
+ {
+ bytes = init;
+ }
+
+ // SAFETY: Trimming trailing ASCII bytes will retain the validity of the string.
+ Path::new(unsafe { OsStr::from_encoded_bytes_unchecked(bytes) })
+ } else {
+ self
+ }
+ }
+
+ /// Creates an owned [`PathBuf`] with `path` adjoined to `self`.
+ ///
+ /// If `path` is absolute, it replaces the current path.
+ ///
+ /// On Windows:
+ ///
+ /// * if `path` has a root but no prefix (e.g., `\windows`), it
+ /// replaces and returns everything except for the prefix (if any) of `self`.
+ /// * if `path` has a prefix but no root, `self` is ignored and `path` is returned.
+ /// * if `self` has a verbatim prefix (e.g. `\\?\C:\windows`)
+ /// and `path` is not empty, the new path is normalized: all references
+ /// to `.` and `..` are removed.
+ ///
+ /// See [`PathBuf::push`] for more details on what it means to adjoin a path.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// assert_eq!(Path::new("/etc").join("passwd"), PathBuf::from("/etc/passwd"));
+ /// assert_eq!(Path::new("/etc").join("/bin/sh"), PathBuf::from("/bin/sh"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn join>(&self, path: P) -> PathBuf {
+ self._join(path.as_ref())
+ }
+
+ fn _join(&self, path: &Path) -> PathBuf {
+ let mut buf = self.to_path_buf();
+ buf.push(path);
+ buf
+ }
+
+ /// Creates an owned [`PathBuf`] like `self` but with the given file name.
+ ///
+ /// See [`PathBuf::set_file_name`] for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("/tmp/foo.png");
+ /// assert_eq!(path.with_file_name("bar"), PathBuf::from("/tmp/bar"));
+ /// assert_eq!(path.with_file_name("bar.txt"), PathBuf::from("/tmp/bar.txt"));
+ ///
+ /// let path = Path::new("/tmp");
+ /// assert_eq!(path.with_file_name("var"), PathBuf::from("/var"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use]
+ pub fn with_file_name>(&self, file_name: S) -> PathBuf {
+ self._with_file_name(file_name.as_ref())
+ }
+
+ fn _with_file_name(&self, file_name: &OsStr) -> PathBuf {
+ let mut buf = self.to_path_buf();
+ buf.set_file_name(file_name);
+ buf
+ }
+
+ /// Creates an owned [`PathBuf`] like `self` but with the given extension.
+ ///
+ /// See [`PathBuf::set_extension`] for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.rs");
+ /// assert_eq!(path.with_extension("txt"), Path::new("foo.txt"));
+ /// assert_eq!(path.with_extension(""), Path::new("foo"));
+ /// ```
+ ///
+ /// Handling multiple extensions:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo.tar.gz");
+ /// assert_eq!(path.with_extension("xz"), Path::new("foo.tar.xz"));
+ /// assert_eq!(path.with_extension("").with_extension("txt"), Path::new("foo.txt"));
+ /// ```
+ ///
+ /// Adding an extension where one did not exist:
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("foo");
+ /// assert_eq!(path.with_extension("rs"), Path::new("foo.rs"));
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn with_extension>(&self, extension: S) -> PathBuf {
+ self._with_extension(extension.as_ref())
+ }
+
+ fn _with_extension(&self, extension: &OsStr) -> PathBuf {
+ let self_len = self.as_os_str().len();
+ let self_bytes = self.as_os_str().as_encoded_bytes();
+
+ let (new_capacity, slice_to_copy) = match self.extension() {
+ None => {
+ // Enough capacity for the extension and the dot
+ let capacity = self_len + extension.len() + 1;
+ let whole_path = self_bytes;
+ (capacity, whole_path)
+ }
+ Some(previous_extension) => {
+ let capacity = self_len + extension.len() - previous_extension.len();
+ let path_till_dot = &self_bytes[..self_len - previous_extension.len()];
+ (capacity, path_till_dot)
+ }
+ };
+
+ let mut new_path = PathBuf::with_capacity(new_capacity);
+ // SAFETY: The path is empty, so cannot have surrogate halves.
+ unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) };
+ new_path.set_extension(extension);
+ new_path
+ }
+
+ /// Creates an owned [`PathBuf`] like `self` but with the extension added.
+ ///
+ /// See [`PathBuf::add_extension`] for more details.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let path = Path::new("foo.rs");
+ /// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
+ ///
+ /// let path = Path::new("foo.tar.gz");
+ /// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
+ /// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
+ /// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
+ /// ```
+ #[stable(feature = "path_add_extension", since = "1.91.0")]
+ pub fn with_added_extension>(&self, extension: S) -> PathBuf {
+ let mut new_path = self.to_path_buf();
+ new_path.add_extension(extension);
+ new_path
+ }
+
+ /// Produces an iterator over the [`Component`]s of the path.
+ ///
+ /// When parsing the path, there is a small amount of normalization:
+ ///
+ /// * Repeated separators are ignored, so `a/b` and `a//b` both have
+ /// `a` and `b` as components.
+ ///
+ /// * Occurrences of `.` are normalized away, except if they are at the
+ /// beginning of the path. For example, `a/./b`, `a/b/`, `a/b/.` and
+ /// `a/b` all have `a` and `b` as components, but `./a/b` starts with
+ /// an additional [`CurDir`] component.
+ ///
+ /// * Trailing separators are normalized away, so `/a/b` and `/a/b/` are equivalent.
+ ///
+ /// Note that no other normalization takes place; in particular, `a/c`
+ /// and `a/b/../c` are distinct, to account for the possibility that `b`
+ /// is a symbolic link (so its parent isn't `a`).
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{Path, Component};
+ /// use std::ffi::OsStr;
+ ///
+ /// let mut components = Path::new("/tmp/foo.txt").components();
+ ///
+ /// assert_eq!(components.next(), Some(Component::RootDir));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("tmp"))));
+ /// assert_eq!(components.next(), Some(Component::Normal(OsStr::new("foo.txt"))));
+ /// assert_eq!(components.next(), None)
+ /// ```
+ ///
+ /// [`CurDir`]: Component::CurDir
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn components(&self) -> Components<'_> {
+ let prefix = parse_prefix(self.as_os_str());
+ Components {
+ path: self.as_u8_slice(),
+ prefix,
+ has_physical_root: has_physical_root(self.as_u8_slice(), prefix),
+ // use a platform-specific initial state to avoid one turn of
+ // the state-machine when the platform doesn't have a Prefix.
+ front: const { if HAS_PREFIXES { State::Prefix } else { State::StartDir } },
+ back: State::Body,
+ }
+ }
+
+ /// Produces an iterator over the path's components viewed as [`OsStr`]
+ /// slices.
+ ///
+ /// For more information about the particulars of how the path is separated
+ /// into components, see [`components`].
+ ///
+ /// [`components`]: Path::components
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::{self, Path};
+ /// use std::ffi::OsStr;
+ ///
+ /// let mut it = Path::new("/tmp/foo.txt").iter();
+ /// assert_eq!(it.next(), Some(OsStr::new(&path::MAIN_SEPARATOR.to_string())));
+ /// assert_eq!(it.next(), Some(OsStr::new("tmp")));
+ /// assert_eq!(it.next(), Some(OsStr::new("foo.txt")));
+ /// assert_eq!(it.next(), None)
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[inline]
+ pub fn iter(&self) -> Iter<'_> {
+ Iter { inner: self.components() }
+ }
+
+ /// Returns an object that implements [`Display`] for safely printing paths
+ /// that may contain non-Unicode data. This may perform lossy conversion,
+ /// depending on the platform. If you would like an implementation which
+ /// escapes the path please use [`Debug`] instead.
+ ///
+ /// [`Display`]: fmt::Display
+ /// [`Debug`]: fmt::Debug
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::path::Path;
+ ///
+ /// let path = Path::new("/tmp/foo.rs");
+ ///
+ /// println!("{}", path.display());
+ /// ```
+ #[stable(feature = "rust1", since = "1.0.0")]
+ #[must_use = "this does not display the path, \
+ it returns an object that can be displayed"]
+ #[inline]
+ pub fn display(&self) -> Display<'_> {
+ Display { inner: self.inner.display() }
+ }
+
+ /// Returns the same path as `&Path`.
+ ///
+ /// This method is redundant when used directly on `&Path`, but
+ /// it helps dereferencing other `PathBuf`-like types to `Path`s,
+ /// for example references to `Box` or `Arc`.
+ #[inline]
+ #[unstable(feature = "str_as_str", issue = "130366")]
+ pub const fn as_path(&self) -> &Path {
+ self
+ }
+
+ // /// Queries the file system to get information about a file, directory, etc.
+ // ///
+ // /// This function will traverse symbolic links to query information about the
+ // /// destination file.
+ // ///
+ // /// This is an alias to [`fs::metadata`].
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // ///
+ // /// let path = Path::new("/Minas/tirith");
+ // /// let metadata = path.metadata().expect("metadata call failed");
+ // /// println!("{:?}", metadata.file_type());
+ // /// ```
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[inline]
+ // pub fn metadata(&self) -> io::Result {
+ // fs::metadata(self)
+ // }
+
+ // /// Queries the metadata about a file without following symlinks.
+ // ///
+ // /// This is an alias to [`fs::symlink_metadata`].
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // ///
+ // /// let path = Path::new("/Minas/tirith");
+ // /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed");
+ // /// println!("{:?}", metadata.file_type());
+ // /// ```
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[inline]
+ // pub fn symlink_metadata(&self) -> io::Result {
+ // fs::symlink_metadata(self)
+ // }
+
+ // /// Returns the canonical, absolute form of the path with all intermediate
+ // /// components normalized and symbolic links resolved.
+ // ///
+ // /// This is an alias to [`fs::canonicalize`].
+ // ///
+ // /// # Errors
+ // ///
+ // /// This method will return an error in the following situations, but is not
+ // /// limited to just these cases:
+ // ///
+ // /// * `path` does not exist.
+ // /// * A non-final component in path is not a directory.
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::{Path, PathBuf};
+ // ///
+ // /// let path = Path::new("/foo/test/../test/bar.rs");
+ // /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs"));
+ // /// ```
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[inline]
+ // pub fn canonicalize(&self) -> io::Result {
+ // fs::canonicalize(self)
+ // }
+
+ /// Normalize a path, including `..` without traversing the filesystem.
+ ///
+ /// Returns an error if normalization would leave leading `..` components.
+ ///
+ ///
+ ///
+ /// This function always resolves `..` to the "lexical" parent.
+ /// That is "a/b/../c" will always resolve to `a/c` which can change the meaning of the path.
+ /// In particular, `a/c` and `a/b/../c` are distinct on many systems because `b` may be a symbolic link, so its parent isn't `a`.
+ ///
+ ///
+ ///
+ /// [`path::absolute`](absolute) is an alternative that preserves `..`.
+ /// Or [`Path::canonicalize`] can be used to resolve any `..` by querying the filesystem.
+ #[unstable(feature = "normalize_lexically", issue = "134694")]
+ pub fn normalize_lexically(&self) -> Result {
+ let mut lexical = PathBuf::new();
+ let mut iter = self.components().peekable();
+
+ // Find the root, if any, and add it to the lexical path.
+ // Here we treat the Windows path "C:\" as a single "root" even though
+ // `components` splits it into two: (Prefix, RootDir).
+ let root = match iter.peek() {
+ Some(Component::ParentDir) => return Err(NormalizeError),
+ Some(p @ Component::RootDir) | Some(p @ Component::CurDir) => {
+ lexical.push(p);
+ iter.next();
+ lexical.as_os_str().len()
+ }
+ Some(Component::Prefix(prefix)) => {
+ lexical.push(prefix.as_os_str());
+ iter.next();
+ if let Some(p @ Component::RootDir) = iter.peek() {
+ lexical.push(p);
+ iter.next();
+ }
+ lexical.as_os_str().len()
+ }
+ None => return Ok(PathBuf::new()),
+ Some(Component::Normal(_)) => 0,
+ };
+
+ for component in iter {
+ match component {
+ Component::RootDir => unreachable!(),
+ Component::Prefix(_) => return Err(NormalizeError),
+ Component::CurDir => continue,
+ Component::ParentDir => {
+ // It's an error if ParentDir causes us to go above the "root".
+ if lexical.as_os_str().len() == root {
+ return Err(NormalizeError);
+ } else {
+ lexical.pop();
+ }
+ }
+ Component::Normal(path) => lexical.push(path),
+ }
+ }
+ Ok(lexical)
+ }
+
+ // /// Reads a symbolic link, returning the file that the link points to.
+ // ///
+ // /// This is an alias to [`fs::read_link`].
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // ///
+ // /// let path = Path::new("/laputa/sky_castle.rs");
+ // /// let path_link = path.read_link().expect("read_link call failed");
+ // /// ```
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[inline]
+ // pub fn read_link(&self) -> io::Result {
+ // fs::read_link(self)
+ // }
+
+ // /// Returns an iterator over the entries within a directory.
+ // ///
+ // /// The iterator will yield instances of [io::Result]<[fs::DirEntry]>. New
+ // /// errors may be encountered after an iterator is initially constructed.
+ // ///
+ // /// This is an alias to [`fs::read_dir`].
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // ///
+ // /// let path = Path::new("/laputa");
+ // /// for entry in path.read_dir().expect("read_dir call failed") {
+ // /// if let Ok(entry) = entry {
+ // /// println!("{:?}", entry.path());
+ // /// }
+ // /// }
+ // /// ```
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[inline]
+ // pub fn read_dir(&self) -> io::Result {
+ // fs::read_dir(self)
+ // }
+
+ // /// Returns `true` if the path points at an existing entity.
+ // ///
+ // /// Warning: this method may be error-prone, consider using [`try_exists()`] instead!
+ // /// It also has a risk of introducing time-of-check to time-of-use ([TOCTOU]) bugs.
+ // ///
+ // /// This function will traverse symbolic links to query information about the
+ // /// destination file.
+ // ///
+ // /// If you cannot access the metadata of the file, e.g. because of a
+ // /// permission error or broken symbolic links, this will return `false`.
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // /// assert!(!Path::new("does_not_exist.txt").exists());
+ // /// ```
+ // ///
+ // /// # See Also
+ // ///
+ // /// This is a convenience function that coerces errors to false. If you want to
+ // /// check errors, call [`Path::try_exists`].
+ // ///
+ // /// [`try_exists()`]: Self::try_exists
+ // /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[must_use]
+ // #[inline]
+ // pub fn exists(&self) -> bool {
+ // fs::metadata(self).is_ok()
+ // }
+
+ // /// Returns `Ok(true)` if the path points at an existing entity.
+ // ///
+ // /// This function will traverse symbolic links to query information about the
+ // /// destination file. In case of broken symbolic links this will return `Ok(false)`.
+ // ///
+ // /// [`Path::exists()`] only checks whether or not a path was both found and readable. By
+ // /// contrast, `try_exists` will return `Ok(true)` or `Ok(false)`, respectively, if the path
+ // /// was _verified_ to exist or not exist. If its existence can neither be confirmed nor
+ // /// denied, it will propagate an `Err(_)` instead. This can be the case if e.g. listing
+ // /// permission is denied on one of the parent directories.
+ // ///
+ // /// Note that while this avoids some pitfalls of the `exists()` method, it still can not
+ // /// prevent time-of-check to time-of-use ([TOCTOU]) bugs. You should only use it in scenarios
+ // /// where those bugs are not an issue.
+ // ///
+ // /// This is an alias for [`std::fs::exists`](crate::fs::exists).
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // /// assert!(!Path::new("does_not_exist.txt").try_exists().expect("Can't check existence of file does_not_exist.txt"));
+ // /// assert!(Path::new("/root/secret_file.txt").try_exists().is_err());
+ // /// ```
+ // ///
+ // /// [TOCTOU]: fs#time-of-check-to-time-of-use-toctou
+ // /// [`exists()`]: Self::exists
+ // #[stable(feature = "path_try_exists", since = "1.63.0")]
+ // #[inline]
+ // pub fn try_exists(&self) -> io::Result {
+ // fs::exists(self)
+ // }
+
+ // /// Returns `true` if the path exists on disk and is pointing at a regular file.
+ // ///
+ // /// This function will traverse symbolic links to query information about the
+ // /// destination file.
+ // ///
+ // /// If you cannot access the metadata of the file, e.g. because of a
+ // /// permission error or broken symbolic links, this will return `false`.
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // /// assert_eq!(Path::new("./is_a_directory/").is_file(), false);
+ // /// assert_eq!(Path::new("a_file.txt").is_file(), true);
+ // /// ```
+ // ///
+ // /// # See Also
+ // ///
+ // /// This is a convenience function that coerces errors to false. If you want to
+ // /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+ // /// [`fs::Metadata::is_file`] if it was [`Ok`].
+ // ///
+ // /// When the goal is simply to read from (or write to) the source, the most
+ // /// reliable way to test the source can be read (or written to) is to open
+ // /// it. Only using `is_file` can break workflows like `diff <( prog_a )` on
+ // /// a Unix-like system for example. See [`fs::File::open`] or
+ // /// [`fs::OpenOptions::open`] for more information.
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[must_use]
+ // pub fn is_file(&self) -> bool {
+ // fs::metadata(self).map(|m| m.is_file()).unwrap_or(false)
+ // }
+
+ // /// Returns `true` if the path exists on disk and is pointing at a directory.
+ // ///
+ // /// This function will traverse symbolic links to query information about the
+ // /// destination file.
+ // ///
+ // /// If you cannot access the metadata of the file, e.g. because of a
+ // /// permission error or broken symbolic links, this will return `false`.
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```no_run
+ // /// use std::path::Path;
+ // /// assert_eq!(Path::new("./is_a_directory/").is_dir(), true);
+ // /// assert_eq!(Path::new("a_file.txt").is_dir(), false);
+ // /// ```
+ // ///
+ // /// # See Also
+ // ///
+ // /// This is a convenience function that coerces errors to false. If you want to
+ // /// check errors, call [`fs::metadata`] and handle its [`Result`]. Then call
+ // /// [`fs::Metadata::is_dir`] if it was [`Ok`].
+ // #[stable(feature = "path_ext", since = "1.5.0")]
+ // #[must_use]
+ // pub fn is_dir(&self) -> bool {
+ // fs::metadata(self).map(|m| m.is_dir()).unwrap_or(false)
+ // }
+
+ // /// Returns `true` if the path exists on disk and is pointing at a symbolic link.
+ // ///
+ // /// This function will not traverse symbolic links.
+ // /// In case of a broken symbolic link this will also return true.
+ // ///
+ // /// If you cannot access the directory containing the file, e.g., because of a
+ // /// permission error, this will return false.
+ // ///
+ // /// # Examples
+ // ///
+ // /// ```rust,no_run
+ // /// # #[cfg(unix)] {
+ // /// use std::path::Path;
+ // /// use std::os::unix::fs::symlink;
+ // ///
+ // /// let link_path = Path::new("link");
+ // /// symlink("/origin_does_not_exist/", link_path).unwrap();
+ // /// assert_eq!(link_path.is_symlink(), true);
+ // /// assert_eq!(link_path.exists(), false);
+ // /// # }
+ // /// ```
+ // ///
+ // /// # See Also
+ // ///
+ // /// This is a convenience function that coerces errors to false. If you want to
+ // /// check errors, call [`fs::symlink_metadata`] and handle its [`Result`]. Then call
+ // /// [`fs::Metadata::is_symlink`] if it was [`Ok`].
+ // #[must_use]
+ // #[stable(feature = "is_symlink", since = "1.58.0")]
+ // pub fn is_symlink(&self) -> bool {
+ // fs::symlink_metadata(self).map(|m| m.is_symlink()).unwrap_or(false)
+ // }
+
+ /// Converts a [`Box`](Box) into a [`PathBuf`] without copying or
+ /// allocating.
+ #[stable(feature = "into_boxed_path", since = "1.20.0")]
+ #[must_use = "`self` will be dropped if the result is not used"]
+ pub fn into_path_buf(self: Box) -> PathBuf {
+ let rw = Box::into_raw(self) as *mut OsStr;
+ let inner = unsafe { Box::from_raw(rw) };
+ PathBuf { inner: OsString::from(inner) }
+ }
+}
+
+#[unstable(feature = "clone_to_uninit", issue = "126799")]
+unsafe impl CloneToUninit for Path {
+ #[inline]
+ #[cfg_attr(debug_assertions, track_caller)]
+ unsafe fn clone_to_uninit(&self, dst: *mut u8) {
+ // SAFETY: Path is just a transparent wrapper around OsStr
+ unsafe { self.inner.clone_to_uninit(dst) }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl const AsRef for Path {
+ #[inline]
+ fn as_ref(&self) -> &OsStr {
+ &self.inner
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Path {
+ fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, formatter)
+ }
+}
+
+/// Helper struct for safely printing paths with [`format!`] and `{}`.
+///
+/// A [`Path`] might contain non-Unicode data. This `struct` implements the
+/// [`Display`] trait in a way that mitigates that. It is created by the
+/// [`display`](Path::display) method on [`Path`]. This may perform lossy
+/// conversion, depending on the platform. If you would like an implementation
+/// which escapes the path please use [`Debug`] instead.
+///
+/// # Examples
+///
+/// ```
+/// use std::path::Path;
+///
+/// let path = Path::new("/tmp/foo.rs");
+///
+/// println!("{}", path.display());
+/// ```
+///
+/// [`Display`]: fmt::Display
+/// [`format!`]: crate::format
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct Display<'a> {
+ inner: os_str::Display<'a>,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Debug for Display<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.inner, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl fmt::Display for Display<'_> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Display::fmt(&self.inner, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialEq for Path {
+ #[inline]
+ fn eq(&self, other: &Path) -> bool {
+ self.components() == other.components()
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for Path {
+ #[inline]
+ fn eq(&self, other: &str) -> bool {
+ let other: &OsStr = other.as_ref();
+ self == other
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for str {
+ #[inline]
+ fn eq(&self, other: &Path) -> bool {
+ other == self
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for Path {
+ #[inline]
+ fn eq(&self, other: &String) -> bool {
+ self == other.as_str()
+ }
+}
+
+#[stable(feature = "eq_str_for_path", since = "1.91.0")]
+impl cmp::PartialEq for String {
+ #[inline]
+ fn eq(&self, other: &Path) -> bool {
+ self.as_str() == other
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Hash for Path {
+ fn hash(&self, h: &mut H) {
+ let bytes = self.as_u8_slice();
+ let (prefix_len, verbatim) = match parse_prefix(&self.inner) {
+ Some(prefix) => {
+ prefix.hash(h);
+ (prefix.len(), prefix.is_verbatim())
+ }
+ None => (0, false),
+ };
+ let bytes = &bytes[prefix_len..];
+
+ let mut component_start = 0;
+ // track some extra state to avoid prefix collisions.
+ // ["foo", "bar"] and ["foobar"], will have the same payload bytes
+ // but result in different chunk_bits
+ let mut chunk_bits: usize = 0;
+
+ for i in 0..bytes.len() {
+ let is_sep = if verbatim { is_verbatim_sep(bytes[i]) } else { is_sep_byte(bytes[i]) };
+ if is_sep {
+ if i > component_start {
+ let to_hash = &bytes[component_start..i];
+ chunk_bits = chunk_bits.wrapping_add(to_hash.len());
+ chunk_bits = chunk_bits.rotate_right(2);
+ h.write(to_hash);
+ }
+
+ // skip over separator and optionally a following CurDir item
+ // since components() would normalize these away.
+ component_start = i + 1;
+
+ let tail = &bytes[component_start..];
+
+ if !verbatim {
+ component_start += match tail {
+ [b'.'] => 1,
+ [b'.', sep, ..] if is_sep_byte(*sep) => 1,
+ _ => 0,
+ };
+ }
+ }
+ }
+
+ if component_start < bytes.len() {
+ let to_hash = &bytes[component_start..];
+ chunk_bits = chunk_bits.wrapping_add(to_hash.len());
+ chunk_bits = chunk_bits.rotate_right(2);
+ h.write(to_hash);
+ }
+
+ h.write_usize(chunk_bits);
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Eq for Path {}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl PartialOrd for Path {
+ #[inline]
+ fn partial_cmp(&self, other: &Path) -> Option {
+ Some(compare_components(self.components(), other.components()))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Ord for Path {
+ #[inline]
+ fn cmp(&self, other: &Path) -> cmp::Ordering {
+ compare_components(self.components(), other.components())
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl const AsRef for Path {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ self
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[rustc_const_unstable(feature = "const_convert", issue = "143773")]
+impl const AsRef for OsStr {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "cow_os_str_as_ref_path", since = "1.8.0")]
+impl AsRef for Cow<'_, OsStr> {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef for OsString {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef for str {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef for String {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ Path::new(self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRef for PathBuf {
+ #[inline]
+ fn as_ref(&self) -> &Path {
+ self
+ }
+}
+
+#[stable(feature = "path_into_iter", since = "1.6.0")]
+impl<'a> IntoIterator for &'a PathBuf {
+ type Item = &'a OsStr;
+ type IntoIter = Iter<'a>;
+ #[inline]
+ fn into_iter(self) -> Iter<'a> {
+ self.iter()
+ }
+}
+
+#[stable(feature = "path_into_iter", since = "1.6.0")]
+impl<'a> IntoIterator for &'a Path {
+ type Item = &'a OsStr;
+ type IntoIter = Iter<'a>;
+ #[inline]
+ fn into_iter(self) -> Iter<'a> {
+ self.iter()
+ }
+}
+
+macro_rules! impl_cmp {
+ ($lhs:ty, $rhs: ty) => {
+ #[stable(feature = "partialeq_path", since = "1.6.0")]
+ impl PartialEq<$rhs> for $lhs {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool {
+ ::eq(self, other)
+ }
+ }
+
+ #[stable(feature = "partialeq_path", since = "1.6.0")]
+ impl PartialEq<$lhs> for $rhs {
+ #[inline]
+ fn eq(&self, other: &$lhs) -> bool {
+ ::eq(self, other)
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl PartialOrd<$rhs> for $lhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$rhs) -> Option {
+ ::partial_cmp(self, other)
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl PartialOrd<$lhs> for $rhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$lhs) -> Option {
+ ::partial_cmp(self, other)
+ }
+ }
+ };
+}
+
+impl_cmp!(PathBuf, Path);
+impl_cmp!(PathBuf, &Path);
+impl_cmp!(Cow<'_, Path>, Path);
+impl_cmp!(Cow<'_, Path>, &Path);
+impl_cmp!(Cow<'_, Path>, PathBuf);
+
+macro_rules! impl_cmp_os_str {
+ ($lhs:ty, $rhs: ty) => {
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl PartialEq<$rhs> for $lhs {
+ #[inline]
+ fn eq(&self, other: &$rhs) -> bool {
+ ::eq(self, other.as_ref())
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl PartialEq<$lhs> for $rhs {
+ #[inline]
+ fn eq(&self, other: &$lhs) -> bool {
+ ::eq(self.as_ref(), other)
+ }
+ }
+
+ #[stable(feature = "cmp_path", since = "1.8.0")]
+ impl PartialOrd<$rhs> for $lhs {
+ #[inline]
+ fn partial_cmp(&self, other: &$rhs) -> Option {
+