Skip to content

Commit c34bd52

Browse files
authored
Unrolled build for rust-lang#140159
Rollup merge of rust-lang#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 rust-lang#137777. cc `@joboet` `@ChrisDenton`
2 parents f97b3c6 + 0f0c0d8 commit c34bd52

File tree

4 files changed

+65
-31
lines changed

4 files changed

+65
-31
lines changed

library/std/src/ffi/os_str.rs

+16-6
Original file line numberDiff line numberDiff line change
@@ -582,15 +582,25 @@ impl OsString {
582582
#[unstable(feature = "os_string_truncate", issue = "133262")]
583583
pub fn truncate(&mut self, len: usize) {
584584
self.as_os_str().inner.check_public_boundary(len);
585-
self.inner.truncate(len);
585+
// SAFETY: The length was just checked to be at a valid boundary.
586+
unsafe { self.inner.truncate_unchecked(len) };
586587
}
587588

588-
/// Provides plumbing to core `Vec::extend_from_slice`.
589-
/// More well behaving alternative to allowing outer types
590-
/// full mutable access to the core `Vec`.
589+
/// Provides plumbing to `Vec::extend_from_slice` without giving full
590+
/// mutable access to the `Vec`.
591+
///
592+
/// # Safety
593+
///
594+
/// The slice must be valid for the platform encoding (as described in
595+
/// [`OsStr::from_encoded_bytes_unchecked`]).
596+
///
597+
/// This bypasses the encoding-dependent surrogate joining, so `self` must
598+
/// not end with a leading surrogate half and `other` must not start with
599+
/// with a trailing surrogate half.
591600
#[inline]
592-
pub(crate) fn extend_from_slice(&mut self, other: &[u8]) {
593-
self.inner.extend_from_slice(other);
601+
pub(crate) unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
602+
// SAFETY: Guaranteed by caller.
603+
unsafe { self.inner.extend_from_slice_unchecked(other) };
594604
}
595605
}
596606

library/std/src/path.rs

+12-7
Original file line numberDiff line numberDiff line change
@@ -1529,11 +1529,13 @@ impl PathBuf {
15291529
self.inner.truncate(end_file_stem.wrapping_sub(start));
15301530

15311531
// add the new extension, if any
1532-
let new = extension;
1532+
let new = extension.as_encoded_bytes();
15331533
if !new.is_empty() {
15341534
self.inner.reserve_exact(new.len() + 1);
1535-
self.inner.push(OsStr::new("."));
1536-
self.inner.push(new);
1535+
self.inner.push(".");
1536+
// SAFETY: Since a UTF-8 string was just pushed, it is not possible
1537+
// for the buffer to end with a surrogate half.
1538+
unsafe { self.inner.extend_from_slice_unchecked(new) };
15371539
}
15381540

15391541
true
@@ -1597,7 +1599,7 @@ impl PathBuf {
15971599
Some(f) => f.as_encoded_bytes(),
15981600
};
15991601

1600-
let new = extension;
1602+
let new = extension.as_encoded_bytes();
16011603
if !new.is_empty() {
16021604
// truncate until right after the file name
16031605
// this is necessary for trimming the trailing slash
@@ -1607,8 +1609,10 @@ impl PathBuf {
16071609

16081610
// append the new extension
16091611
self.inner.reserve_exact(new.len() + 1);
1610-
self.inner.push(OsStr::new("."));
1611-
self.inner.push(new);
1612+
self.inner.push(".");
1613+
// SAFETY: Since a UTF-8 string was just pushed, it is not possible
1614+
// for the buffer to end with a surrogate half.
1615+
unsafe { self.inner.extend_from_slice_unchecked(new) };
16121616
}
16131617

16141618
true
@@ -2769,7 +2773,8 @@ impl Path {
27692773
};
27702774

27712775
let mut new_path = PathBuf::with_capacity(new_capacity);
2772-
new_path.inner.extend_from_slice(slice_to_copy);
2776+
// SAFETY: The path is empty, so cannot have surrogate halves.
2777+
unsafe { new_path.inner.extend_from_slice_unchecked(slice_to_copy) };
27732778
new_path.set_extension(extension);
27742779
new_path
27752780
}

library/std/src/sys/os_str/bytes.rs

+16-9
Original file line numberDiff line numberDiff line change
@@ -216,19 +216,26 @@ impl Buf {
216216
self.as_slice().into_rc()
217217
}
218218

219-
/// Provides plumbing to core `Vec::truncate`.
220-
/// More well behaving alternative to allowing outer types
221-
/// full mutable access to the core `Vec`.
222-
#[inline]
223-
pub(crate) fn truncate(&mut self, len: usize) {
219+
/// Provides plumbing to `Vec::truncate` without giving full mutable access
220+
/// to the `Vec`.
221+
///
222+
/// # Safety
223+
///
224+
/// The length must be at an `OsStr` boundary, according to
225+
/// `Slice::check_public_boundary`.
226+
#[inline]
227+
pub unsafe fn truncate_unchecked(&mut self, len: usize) {
224228
self.inner.truncate(len);
225229
}
226230

227-
/// Provides plumbing to core `Vec::extend_from_slice`.
228-
/// More well behaving alternative to allowing outer types
229-
/// full mutable access to the core `Vec`.
231+
/// Provides plumbing to `Vec::extend_from_slice` without giving full
232+
/// mutable access to the `Vec`.
233+
///
234+
/// # Safety
235+
///
236+
/// This encoding has no safety requirements.
230237
#[inline]
231-
pub(crate) fn extend_from_slice(&mut self, other: &[u8]) {
238+
pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
232239
self.inner.extend_from_slice(other);
233240
}
234241
}

library/std/src/sys/os_str/wtf8.rs

+21-9
Original file line numberDiff line numberDiff line change
@@ -195,19 +195,31 @@ impl Buf {
195195
self.as_slice().into_rc()
196196
}
197197

198-
/// Provides plumbing to core `Vec::truncate`.
199-
/// More well behaving alternative to allowing outer types
200-
/// full mutable access to the core `Vec`.
201-
#[inline]
202-
pub(crate) fn truncate(&mut self, len: usize) {
198+
/// Provides plumbing to `Vec::truncate` without giving full mutable access
199+
/// to the `Vec`.
200+
///
201+
/// # Safety
202+
///
203+
/// The length must be at an `OsStr` boundary, according to
204+
/// `Slice::check_public_boundary`.
205+
#[inline]
206+
pub unsafe fn truncate_unchecked(&mut self, len: usize) {
203207
self.inner.truncate(len);
204208
}
205209

206-
/// Provides plumbing to core `Vec::extend_from_slice`.
207-
/// More well behaving alternative to allowing outer types
208-
/// full mutable access to the core `Vec`.
210+
/// Provides plumbing to `Vec::extend_from_slice` without giving full
211+
/// mutable access to the `Vec`.
212+
///
213+
/// # Safety
214+
///
215+
/// The slice must be valid for the platform encoding (as described in
216+
/// [`Slice::from_encoded_bytes_unchecked`]).
217+
///
218+
/// This bypasses the WTF-8 surrogate joining, so `self` must not end with a
219+
/// leading surrogate half and `other` must not start with with a trailing
220+
/// surrogate half.
209221
#[inline]
210-
pub(crate) fn extend_from_slice(&mut self, other: &[u8]) {
222+
pub unsafe fn extend_from_slice_unchecked(&mut self, other: &[u8]) {
211223
self.inner.extend_from_slice(other);
212224
}
213225
}

0 commit comments

Comments
 (0)