Skip to content

Commit c0369c4

Browse files
authored
Rollup merge of #70048 - TyPR124:mutable_osstr, r=dtolnay
Allow obtaining &mut OsStr ```rust impl DerefMut for OsString {...} // type Target = OsStr impl IndexMut<RangeFull> for OsString {...} // type Output = OsStr ``` --- This change is pulled out of #69937 per @dtolnay This implements `DerefMut for OsString` to allow obtaining a `&mut OsStr`. This also implements `IndexMut for OsString`, which is used by `DerefMut`. This pattern is the same as is used by `Deref`. This is necessary to for methods like `make_ascii_lowercase` which need to mutate the underlying value.
2 parents f635c37 + 45416cd commit c0369c4

File tree

3 files changed

+50
-0
lines changed

3 files changed

+50
-0
lines changed

src/libstd/ffi/os_str.rs

+27
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,14 @@ impl ops::Index<ops::RangeFull> for OsString {
379379
}
380380
}
381381

382+
#[stable(feature = "mut_osstr", since = "1.44.0")]
383+
impl ops::IndexMut<ops::RangeFull> for OsString {
384+
#[inline]
385+
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr {
386+
OsStr::from_inner_mut(self.inner.as_mut_slice())
387+
}
388+
}
389+
382390
#[stable(feature = "rust1", since = "1.0.0")]
383391
impl ops::Deref for OsString {
384392
type Target = OsStr;
@@ -389,6 +397,14 @@ impl ops::Deref for OsString {
389397
}
390398
}
391399

400+
#[stable(feature = "mut_osstr", since = "1.44.0")]
401+
impl ops::DerefMut for OsString {
402+
#[inline]
403+
fn deref_mut(&mut self) -> &mut OsStr {
404+
&mut self[..]
405+
}
406+
}
407+
392408
#[stable(feature = "osstring_default", since = "1.9.0")]
393409
impl Default for OsString {
394410
/// Constructs an empty `OsString`.
@@ -509,9 +525,20 @@ impl OsStr {
509525

510526
#[inline]
511527
fn from_inner(inner: &Slice) -> &OsStr {
528+
// Safety: OsStr is just a wrapper of Slice,
529+
// therefore converting &Slice to &OsStr is safe.
512530
unsafe { &*(inner as *const Slice as *const OsStr) }
513531
}
514532

533+
#[inline]
534+
fn from_inner_mut(inner: &mut Slice) -> &mut OsStr {
535+
// Safety: OsStr is just a wrapper of Slice,
536+
// therefore converting &mut Slice to &mut OsStr is safe.
537+
// Any method that mutates OsStr must be careful not to
538+
// break platform-specific encoding, in particular Wtf8 on Windows.
539+
unsafe { &mut *(inner as *mut Slice as *mut OsStr) }
540+
}
541+
515542
/// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
516543
///
517544
/// This conversion may entail doing a check for UTF-8 validity.

src/libstd/sys/windows/os_str.rs

+12
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,21 @@ impl Buf {
7777
}
7878

7979
pub fn as_slice(&self) -> &Slice {
80+
// Safety: Slice is just a wrapper for Wtf8,
81+
// and self.inner.as_slice() returns &Wtf8.
82+
// Therefore, transmuting &Wtf8 to &Slice is safe.
8083
unsafe { mem::transmute(self.inner.as_slice()) }
8184
}
8285

86+
pub fn as_mut_slice(&mut self) -> &mut Slice {
87+
// Safety: Slice is just a wrapper for Wtf8,
88+
// and self.inner.as_mut_slice() returns &mut Wtf8.
89+
// Therefore, transmuting &mut Wtf8 to &mut Slice is safe.
90+
// Additionally, care should be taken to ensure the slice
91+
// is always valid Wtf8.
92+
unsafe { mem::transmute(self.inner.as_mut_slice()) }
93+
}
94+
8395
pub fn into_string(self) -> Result<String, Buf> {
8496
self.inner.into_string().map_err(|buf| Buf { inner: buf })
8597
}

src/libstd/sys_common/os_str_bytes.rs

+11
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,20 @@ impl Buf {
106106

107107
#[inline]
108108
pub fn as_slice(&self) -> &Slice {
109+
// Safety: Slice just wraps [u8],
110+
// and &*self.inner is &[u8], therefore
111+
// transmuting &[u8] to &Slice is safe.
109112
unsafe { mem::transmute(&*self.inner) }
110113
}
111114

115+
#[inline]
116+
pub fn as_mut_slice(&mut self) -> &mut Slice {
117+
// Safety: Slice just wraps [u8],
118+
// and &mut *self.inner is &mut [u8], therefore
119+
// transmuting &mut [u8] to &mut Slice is safe.
120+
unsafe { mem::transmute(&mut *self.inner) }
121+
}
122+
112123
pub fn into_string(self) -> Result<String, Buf> {
113124
String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() })
114125
}

0 commit comments

Comments
 (0)