Skip to content

Commit 35d2e1b

Browse files
committed
impl add_extension for PathBuf
Signed-off-by: tison <[email protected]>
1 parent 1cfd47f commit 35d2e1b

File tree

1 file changed

+70
-0
lines changed

1 file changed

+70
-0
lines changed

library/std/src/path.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1519,6 +1519,76 @@ 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+
/// use std::path::{Path, PathBuf};
1545+
///
1546+
/// let mut p = PathBuf::from("/feel/the");
1547+
///
1548+
/// p.add_extension("formatted");
1549+
/// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
1550+
///
1551+
/// p.add_extension("dark.side");
1552+
/// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
1553+
///
1554+
/// p.set_extension("cookie");
1555+
/// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
1556+
///
1557+
/// p.set_extension("");
1558+
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1559+
///
1560+
/// p.add_extension("");
1561+
/// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1562+
/// ```
1563+
#[stable(feature = "rust1", since = "1.0.0")]
1564+
pub fn add_extension<S: AsRef<OsStr>>(&mut self, extension: S) -> bool {
1565+
self._add_extension(extension.as_ref())
1566+
}
1567+
1568+
fn _add_extension(&mut self, extension: &OsStr) -> bool {
1569+
let file_name = match self.file_name() {
1570+
None => return false,
1571+
Some(f) => f.as_encoded_bytes(),
1572+
};
1573+
1574+
let new = extension.as_encoded_bytes();
1575+
if !new.is_empty() {
1576+
// truncate until right after the file name
1577+
// this is necessary for trimming the trailing slash
1578+
let end_file_name = file_name[file_name.len()..].as_ptr().addr();
1579+
let start = self.inner.as_encoded_bytes().as_ptr().addr();
1580+
let v = self.as_mut_vec();
1581+
v.truncate(end_file_name.wrapping_sub(start));
1582+
1583+
// append the new extension
1584+
v.reserve_exact(new.len() + 1);
1585+
v.push(b'.');
1586+
v.extend_from_slice(new);
1587+
}
1588+
1589+
true
1590+
}
1591+
15221592
/// Yields a mutable reference to the underlying [`OsString`] instance.
15231593
///
15241594
/// # Examples

0 commit comments

Comments
 (0)