Skip to content

Commit acbefbb

Browse files
committed
impl PathBuf::add_extension and Path::with_added_extension
Signed-off-by: tison <wander4096@gmail.com>
1 parent 5b0d82f commit acbefbb

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed

std/src/path.rs

+97
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,77 @@ impl PathBuf {
15191519
true
15201520
}
15211521

1522+
/// Append [`self.extension`] with `extension`.
1523+
///
1524+
/// Returns `false` and does nothing if [`self.file_name`] is [`None`],
1525+
/// returns `true` and updates the extension otherwise.
1526+
///
1527+
/// If [`self.extension`] is [`None`], the extension is added; otherwise
1528+
/// it is appended.
1529+
///
1530+
/// # Caveats
1531+
///
1532+
/// The appended `extension` may contain dots and will be used in its entirety,
1533+
/// but only the part after the final dot will be reflected in
1534+
/// [`self.extension`].
1535+
///
1536+
/// See the examples below.
1537+
///
1538+
/// [`self.file_name`]: Path::file_name
1539+
/// [`self.extension`]: Path::extension
1540+
///
1541+
/// # Examples
1542+
///
1543+
/// ```
1544+
/// #![feature(path_add_extension)]
1545+
///
1546+
/// use std::path::{Path, PathBuf};
1547+
///
1548+
/// let mut p = PathBuf::from("/feel/the");
1549+
///
1550+
/// p.add_extension("formatted");
1551+
/// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
1552+
///
1553+
/// p.add_extension("dark.side");
1554+
/// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
1555+
///
1556+
/// p.set_extension("cookie");
1557+
/// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
1558+
///
1559+
/// p.set_extension("");
1560+
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1561+
///
1562+
/// p.add_extension("");
1563+
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1564+
/// ```
1565+
#[unstable(feature = "path_add_extension", issue = "127292")]
1566+
pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
1567+
self._add_extension(extension.as_ref())
1568+
}
1569+
1570+
fn _add_extension(&mut self, extension: &OsStr) -> bool {
1571+
let file_name = match self.file_name() {
1572+
None => return false,
1573+
Some(f) => f.as_encoded_bytes(),
1574+
};
1575+
1576+
let new = extension;
1577+
if !new.is_empty() {
1578+
// truncate until right after the file name
1579+
// this is necessary for trimming the trailing slash
1580+
let end_file_name = file_name[file_name.len()..].as_ptr().addr();
1581+
let start = self.inner.as_encoded_bytes().as_ptr().addr();
1582+
self.inner.truncate(end_file_name.wrapping_sub(start));
1583+
1584+
// append the new extension
1585+
self.inner.reserve_exact(new.len() + 1);
1586+
self.inner.push(OsStr::new("."));
1587+
self.inner.push(new);
1588+
}
1589+
1590+
true
1591+
}
1592+
15221593
/// Yields a mutable reference to the underlying [`OsString`] instance.
15231594
///
15241595
/// # Examples
@@ -2656,6 +2727,32 @@ impl Path {
26562727
new_path
26572728
}
26582729

2730+
/// Creates an owned [`PathBuf`] like `self` but with an extra extension.
2731+
///
2732+
/// See [`PathBuf::add_extension`] for more details.
2733+
///
2734+
/// # Examples
2735+
///
2736+
/// ```
2737+
/// #![feature(path_add_extension)]
2738+
///
2739+
/// use std::path::{Path, PathBuf};
2740+
///
2741+
/// let path = Path::new("foo.rs");
2742+
/// assert_eq!(path.with_added_extension("txt"), PathBuf::from("foo.rs.txt"));
2743+
///
2744+
/// let path = Path::new("foo.tar.gz");
2745+
/// assert_eq!(path.with_added_extension(""), PathBuf::from("foo.tar.gz"));
2746+
/// assert_eq!(path.with_added_extension("xz"), PathBuf::from("foo.tar.gz.xz"));
2747+
/// assert_eq!(path.with_added_extension("").with_added_extension("txt"), PathBuf::from("foo.tar.gz.txt"));
2748+
/// ```
2749+
#[unstable(feature = "path_add_extension", issue = "127292")]
2750+
pub fn with_added_extension<S: AsRef<OsStr>>(&self, extension: S) -> PathBuf {
2751+
let mut new_path = self.to_path_buf();
2752+
new_path.add_extension(extension);
2753+
new_path
2754+
}
2755+
26592756
/// Produces an iterator over the [`Component`]s of the path.
26602757
///
26612758
/// When parsing the path, there is a small amount of normalization:

0 commit comments

Comments
 (0)