@@ -1403,6 +1403,80 @@ impl PathBuf {
14031403        } 
14041404    } 
14051405
1406+     /// Sets whether the path has a trailing [separator](MAIN_SEPARATOR). 
1407+ /// 
1408+ /// The value returned by [`has_trailing_sep`](Self::has_trailing_sep) will be equivalent to 
1409+ /// the provided value. 
1410+ /// 
1411+ /// # Examples 
1412+ /// 
1413+ /// ``` 
1414+ /// let mut p = PathBuf::from("dir"); 
1415+ /// 
1416+ /// assert!(!p.has_trailing_sep()); 
1417+ /// p.set_trailing_sep(false); 
1418+ /// assert!(!p.has_trailing_sep()); 
1419+ /// p.set_trailing_sep(true); 
1420+ /// assert!(p.has_trailing_sep()); 
1421+ /// assert_eq!(p.file_name(), None); 
1422+ /// p.set_trailing_sep(false); 
1423+ /// assert!(!p.has_trailing_sep()); 
1424+ /// assert_eq!(p.file_name(), Some("dir")); 
1425+ /// assert_eq!(p, Path::new("dir")); 
1426+ /// ``` 
1427+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
1428+     pub  fn  set_trailing_sep ( & mut  self ,  trailing_sep :  bool )  { 
1429+         if  trailing_sep {  self . push_trailing_sep ( )  }  else  {  self . pop_trailing_sep ( )  } 
1430+     } 
1431+ 
1432+     /// Adds a trailing [separator](MAIN_SEPARATOR) to the path. 
1433+ /// 
1434+ /// This acts similarly to [`Path::with_trailing_sep`], but mutates the underlying `PathBuf`. 
1435+ /// 
1436+ /// # Examples 
1437+ /// 
1438+ /// ``` 
1439+ /// use std::path::{Path, PathBuf}; 
1440+ /// 
1441+ /// let mut p = PathBuf::from("dir"); 
1442+ /// 
1443+ /// assert_eq!(p.file_name(), Some(Path::new("dir"))); 
1444+ /// p.push_trailing_sep(); 
1445+ /// assert_eq!(p.file_name(), None); 
1446+ /// p.push_trailing_sep(); 
1447+ /// assert_eq!(p.file_name(), None); 
1448+ /// assert_eq!(p, Path::new("dir/")); 
1449+ /// ``` 
1450+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
1451+     pub  fn  push_trailing_sep ( & mut  self )  { 
1452+         if  !self . has_trailing_sep ( )  { 
1453+             self . push ( "" ) ; 
1454+         } 
1455+     } 
1456+ 
1457+     /// Removes a trailing [separator](MAIN_SEPARATOR) from the path, if possible. 
1458+ /// 
1459+ /// This acts similarly to [`Path::trim_trailing_sep`], but mutates the underlying `PathBuf`. 
1460+ /// 
1461+ /// # Examples 
1462+ /// 
1463+ /// ``` 
1464+ /// use std::path::{Path, PathBuf}; 
1465+ /// 
1466+ /// let mut p = PathBuf::from("dir/"); 
1467+ /// 
1468+ /// assert_eq!(p.file_name(), None); 
1469+ /// p.pop_trailing_sep(); 
1470+ /// assert_eq!(p.file_name(), Some("dir")); 
1471+ /// p.pop_trailing_sep(); 
1472+ /// assert_eq!(p.file_name(), Some("dir")); 
1473+ /// assert_eq!(p, Path::new("/dir")); 
1474+ /// ``` 
1475+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
1476+     pub  fn  pop_trailing_sep ( & mut  self )  { 
1477+         self . inner . truncate ( self . trim_trailing_sep ( ) . as_os_str ( ) . len ( ) ) ; 
1478+     } 
1479+ 
14061480    /// Updates [`self.file_name`] to `file_name`. 
14071481/// 
14081482/// If [`self.file_name`] was [`None`], this is equivalent to pushing 
@@ -2686,6 +2760,85 @@ impl Path {
26862760        self . file_name ( ) . map ( rsplit_file_at_dot) . and_then ( |( before,  after) | before. and ( after) ) 
26872761    } 
26882762
2763+     /// Checks whether the path ends in a trailing [separator](MAIN_SEPARATOR). 
2764+ /// 
2765+ /// This is generally done to ensure that a path is treated as a directory, not a file, 
2766+ /// although it does not actually guarantee that such a path is a directory on the underlying 
2767+ /// file system. 
2768+ /// 
2769+ /// Despite this behavior, two paths are still considered the same in Rust whether they have a 
2770+ /// trailing separator or not. 
2771+ /// 
2772+ /// # Examples 
2773+ /// 
2774+ /// ``` 
2775+ /// use std::path::Path; 
2776+ /// 
2777+ /// assert!(Path::new("dir/").has_trailing_sep()); 
2778+ /// assert!(!Path::new("file.rs").has_trailing_sep()); 
2779+ /// ``` 
2780+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
2781+     #[ must_use]  
2782+     #[ inline]  
2783+     pub  fn  has_trailing_sep ( & self )  -> bool  { 
2784+         self . as_os_str ( ) . as_encoded_bytes ( ) . last ( ) . copied ( ) . is_some_and ( is_sep_byte) 
2785+     } 
2786+ 
2787+     /// Ensures that a path has a trailing [separator](MAIN_SEPARATOR), 
2788+ /// allocating a [`PathBuf`] if necessary. 
2789+ /// 
2790+ /// The resulting path will return true for [`has_trailing_sep`](Self::has_trailing_sep) and 
2791+ /// `None` for [`file_name`](Self::file_name). 
2792+ /// 
2793+ /// # Examples 
2794+ /// 
2795+ /// ``` 
2796+ /// use std::path::Path; 
2797+ /// 
2798+ /// assert_eq!(Path::new("dir//").with_trailing_sep().file_name(), None); 
2799+ /// assert_eq!(Path::new("dir/").with_trailing_sep().file_name(), None); 
2800+ /// assert_eq!(Path::new("dir").with_trailing_sep().file_name(), None); 
2801+ /// assert_eq!(Path::new("dir").file_name(), Some("dir")); 
2802+ /// ``` 
2803+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
2804+     #[ must_use]  
2805+     #[ inline]  
2806+     pub  fn  with_trailing_sep ( & self )  -> Cow < ' _ ,  Path >  { 
2807+         if  self . has_trailing_sep ( )  {  Cow :: Borrowed ( self )  }  else  {  Cow :: Owned ( self . join ( "" ) )  } 
2808+     } 
2809+ 
2810+     /// Trims a trailing [separator](MAIN_SEPARATOR) from a path, if possible. 
2811+ /// 
2812+ /// The resulting path will return false for [`has_trailing_sep`](Self::has_trailing_sep). 
2813+ /// 
2814+ /// # Examples 
2815+ /// 
2816+ /// ``` 
2817+ /// use std::path::Path; 
2818+ /// 
2819+ /// assert_eq!(Path::new("dir//").trim_trailing_sep().file_name(), Some("dir")); 
2820+ /// assert_eq!(Path::new("dir/").trim_trailing_sep().file_name(), Some("dir")); 
2821+ /// assert_eq!(Path::new("dir").trim_trailing_sep().file_name(), Some("dir")); 
2822+ /// ``` 
2823+ #[ unstable( feature = "path_trailing_sep" ,  issue = "142503" ) ]  
2824+     #[ must_use]  
2825+     #[ inline]  
2826+     pub  fn  trim_trailing_sep ( & self )  -> & Path  { 
2827+         if  self . has_trailing_sep ( )  && ( !self . has_root ( )  || self . parent ( ) . is_some ( ) )  { 
2828+             let  mut  bytes = self . inner . as_encoded_bytes ( ) ; 
2829+             while  let  Some ( ( last,  init) )  = bytes. split_last ( ) 
2830+                 && is_sep_byte ( * last) 
2831+             { 
2832+                 bytes = init; 
2833+             } 
2834+ 
2835+             // SAFETY: Trimming trailing ASCII bytes will retain the validity of the string. 
2836+             Path :: new ( unsafe  {  OsStr :: from_encoded_bytes_unchecked ( bytes)  } ) 
2837+         }  else  { 
2838+             self 
2839+         } 
2840+     } 
2841+ 
26892842    /// Creates an owned [`PathBuf`] with `path` adjoined to `self`. 
26902843/// 
26912844/// If `path` is absolute, it replaces the current path. 
0 commit comments