about summary refs log tree commit diff
path: root/library/std/src/path.rs
diff options
context:
space:
mode:
authorStuart Cook <Zalathar@users.noreply.github.com>2025-05-02 22:17:00 +1000
committerGitHub <noreply@github.com>2025-05-02 22:17:00 +1000
commit5a58c7a6ab060044399f7886cff330f3ee74c21c (patch)
treee1204106d91d881b6aed3e66ddeeb2870824edde /library/std/src/path.rs
parent6fc78d410d506e3c95c6362046f3965810f5ec6d (diff)
parent0f0c0d8b16b265ac57cac9fd50f1dcfe78719a6a (diff)
downloadrust-5a58c7a6ab060044399f7886cff330f3ee74c21c.tar.gz
rust-5a58c7a6ab060044399f7886cff330f3ee74c21c.zip
Rollup merge of #140159 - thaliaarchi:pathbuf-extension, r=workingjubilee
Avoid redundant WTF-8 checks in `PathBuf`

Eliminate checks for WTF-8 boundaries in `PathBuf::set_extension` and `add_extension`, where joining WTF-8 surrogate halves is impossible. Don't convert the `str` to `OsStr`, because `OsString::push` specializes to skip the joining when given strings.

To assist in this, mark the internal methods `OsString::truncate` and `extend_from_slice` as `unsafe` to communicate their safety invariants better than with module privacy.

Similar to #137777.

cc `@joboet` `@ChrisDenton`
Diffstat (limited to 'library/std/src/path.rs')
-rw-r--r--library/std/src/path.rs19
1 files changed, 12 insertions, 7 deletions
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 7cd20c48d89..1a4a7aa7448 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -1529,11 +1529,13 @@ impl PathBuf {
         self.inner.truncate(end_file_stem.wrapping_sub(start));
 
         // add the new extension, if any
-        let new = extension;
+        let new = extension.as_encoded_bytes();
         if !new.is_empty() {
             self.inner.reserve_exact(new.len() + 1);
-            self.inner.push(OsStr::new("."));
-            self.inner.push(new);
+            self.inner.push(".");
+            // SAFETY: Since a UTF-8 string was just pushed, it is not possible
+            // for the buffer to end with a surrogate half.
+            unsafe { self.inner.extend_from_slice_unchecked(new) };
         }
 
         true
@@ -1597,7 +1599,7 @@ impl PathBuf {
             Some(f) => f.as_encoded_bytes(),
         };
 
-        let new = extension;
+        let new = extension.as_encoded_bytes();
         if !new.is_empty() {
             // truncate until right after the file name
             // this is necessary for trimming the trailing slash
@@ -1607,8 +1609,10 @@ impl PathBuf {
 
             // append the new extension
             self.inner.reserve_exact(new.len() + 1);
-            self.inner.push(OsStr::new("."));
-            self.inner.push(new);
+            self.inner.push(".");
+            // SAFETY: Since a UTF-8 string was just pushed, it is not possible
+            // for the buffer to end with a surrogate half.
+            unsafe { self.inner.extend_from_slice_unchecked(new) };
         }
 
         true
@@ -2769,7 +2773,8 @@ impl Path {
         };
 
         let mut new_path = PathBuf::with_capacity(new_capacity);
-        new_path.inner.extend_from_slice(slice_to_copy);
+        // SAFETY: The path is empty, so cannot have surrogate halves.
+        unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) };
         new_path.set_extension(extension);
         new_path
     }