@@ -1498,6 +1498,76 @@ impl PathBuf {
14981498 true
14991499 }
15001500
1501+ /// Append [`self.extension`] with `extension`.
1502+ ///
1503+ /// Returns `false` and does nothing if [`self.file_name`] is [`None`],
1504+ /// returns `true` and updates the extension otherwise.
1505+ ///
1506+ /// If [`self.extension`] is [`None`], the extension is added; otherwise
1507+ /// it is appended.
1508+ ///
1509+ /// # Caveats
1510+ ///
1511+ /// The appended `extension` may contain dots and will be used in its entirety,
1512+ /// but only the part after the final dot will be reflected in
1513+ /// [`self.extension`].
1514+ ///
1515+ /// See the examples below.
1516+ ///
1517+ /// [`self.file_name`]: Path::file_name
1518+ /// [`self.extension`]: Path::extension
1519+ ///
1520+ /// # Examples
1521+ ///
1522+ /// ```
1523+ /// use std::path::{Path, PathBuf};
1524+ ///
1525+ /// let mut p = PathBuf::from("/feel/the");
1526+ ///
1527+ /// p.add_extension("formatted");
1528+ /// assert_eq!(Path::new("/feel/the.formatted"), p.as_path());
1529+ ///
1530+ /// p.add_extension("dark.side");
1531+ /// assert_eq!(Path::new("/feel/the.formatted.dark.side"), p.as_path());
1532+ ///
1533+ /// p.set_extension("cookie");
1534+ /// assert_eq!(Path::new("/feel/the.formatted.dark.cookie"), p.as_path());
1535+ ///
1536+ /// p.set_extension("");
1537+ /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1538+ ///
1539+ /// p.add_extension("");
1540+ /// assert_eq!(Path::new("/feel/the.formatted.dark"), p.as_path());
1541+ /// ```
1542+ #[ stable( feature = "rust1" , since = "1.0.0" ) ]
1543+ pub fn add_extension < S : AsRef < OsStr > > ( & mut self , extension : S ) -> bool {
1544+ self . _add_extension ( extension. as_ref ( ) )
1545+ }
1546+
1547+ fn _add_extension ( & mut self , extension : & OsStr ) -> bool {
1548+ let file_name = match self . file_name ( ) {
1549+ None => return false ,
1550+ Some ( f) => f. as_encoded_bytes ( ) ,
1551+ } ;
1552+
1553+ let new = extension. as_encoded_bytes ( ) ;
1554+ if !new. is_empty ( ) {
1555+ // truncate until right after the file name
1556+ // this is necessary for trimming the trailing slash
1557+ let end_file_name = file_name[ file_name. len ( ) ..] . as_ptr ( ) . addr ( ) ;
1558+ let start = self . inner . as_encoded_bytes ( ) . as_ptr ( ) . addr ( ) ;
1559+ let v = self . as_mut_vec ( ) ;
1560+ v. truncate ( end_file_stem. wrapping_sub ( start) ) ;
1561+
1562+ // append the new extension
1563+ v. reserve_exact ( new. len ( ) + 1 ) ;
1564+ v. push ( b'.' ) ;
1565+ v. extend_from_slice ( new) ;
1566+ }
1567+
1568+ true
1569+ }
1570+
15011571 /// Yields a mutable reference to the underlying [`OsString`] instance.
15021572 ///
15031573 /// # Examples
0 commit comments