// This casts are safe as OsStr is internally a wrapper around [u8] on all
// platforms.
//
- // Note that currently this relies on the special knowledge that libstd has;
+ // Note that currently this relies on the special knowledge that std has;
// these types are single-element structs but are not marked
// repr(transparent) or repr(C) which would make these casts not allowable
// outside std.
/// and `path` is not empty, the new path is normalized: all references
/// to `.` and `..` are removed.
///
+ /// Consider using [`Path::join`] if you need a new `PathBuf` instead of
+ /// using this function on a cloned `PathBuf`.
+ ///
/// # Examples
///
/// Pushing a relative path extends the existing path:
self.push(file_name);
}
- /// Updates [`self.extension`] to `extension`.
+ /// Updates [`self.extension`] to `Some(extension)` or to `None` if
+ /// `extension` is empty.
///
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
/// returns `true` and updates the extension otherwise.
/// If [`self.extension`] is [`None`], the extension is added; otherwise
/// it is replaced.
///
+ /// If `extension` is the empty string, [`self.extension`] will be [`None`]
+ /// afterwards, not `Some("")`.
+ ///
+ /// # Caveats
+ ///
+ /// The new `extension` may contain dots and will be used in its entirety,
+ /// but only the part after the final dot will be reflected in
+ /// [`self.extension`].
+ ///
+ /// If the file stem contains internal dots and `extension` is empty, part
+ /// of the old file stem will be considered the new [`self.extension`].
+ ///
+ /// See the examples below.
+ ///
/// [`self.file_name`]: Path::file_name
/// [`self.extension`]: Path::extension
///
/// p.set_extension("force");
/// assert_eq!(Path::new("/feel/the.force"), p.as_path());
///
- /// p.set_extension("dark_side");
- /// assert_eq!(Path::new("/feel/the.dark_side"), p.as_path());
+ /// p.set_extension("dark.side");
+ /// assert_eq!(Path::new("/feel/the.dark.side"), p.as_path());
+ ///
+ /// p.set_extension("cookie");
+ /// assert_eq!(Path::new("/feel/the.dark.cookie"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the.dark"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
+ ///
+ /// p.set_extension("");
+ /// assert_eq!(Path::new("/feel/the"), p.as_path());
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub fn set_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
true
}
+ /// Yields a mutable reference to the underlying [`OsString`] instance.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_as_mut_os_str)]
+ /// use std::path::{Path, PathBuf};
+ ///
+ /// let mut path = PathBuf::from("/foo");
+ ///
+ /// path.push("bar");
+ /// assert_eq!(path, Path::new("/foo/bar"));
+ ///
+ /// // OsString's `push` does not add a separator.
+ /// path.as_mut_os_string().push("baz");
+ /// assert_eq!(path, Path::new("/foo/barbaz"));
+ /// ```
+ #[unstable(feature = "path_as_mut_os_str", issue = "105021")]
+ #[must_use]
+ #[inline]
+ pub fn as_mut_os_string(&mut self) -> &mut OsString {
+ &mut self.inner
+ }
+
/// Consumes the `PathBuf`, yielding its internal [`OsString`] storage.
///
/// # Examples
}
}
+#[stable(feature = "path_buf_deref_mut", since = "CURRENT_RUSTC_VERSION")]
+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<Path> for PathBuf {
#[inline]
unsafe { &*(s.as_ref() as *const OsStr as *const Path) }
}
+ 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
&self.inner
}
+ /// Yields a mutable reference to the underlying [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// #![feature(path_as_mut_os_str)]
+ /// 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"));
+ /// ```
+ #[unstable(feature = "path_as_mut_os_str", issue = "105021")]
+ #[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.
/// Returns the `Path` without its final component, if there is one.
///
- /// Returns [`None`] if the path terminates in a root or prefix.
+ /// 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
///
/// 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")]