Skip to content

Commit

Permalink
Rollup merge of rust-lang#70048 - TyPR124:mutable_osstr, r=dtolnay
Browse files Browse the repository at this point in the history
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 rust-lang#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.
  • Loading branch information
Dylan-DPC committed Mar 27, 2020
2 parents f635c37 + 45416cd commit c0369c4
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 0 deletions.
27 changes: 27 additions & 0 deletions src/libstd/ffi/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,14 @@ impl ops::Index<ops::RangeFull> for OsString {
}
}

#[stable(feature = "mut_osstr", since = "1.44.0")]
impl ops::IndexMut<ops::RangeFull> for OsString {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut OsStr {
OsStr::from_inner_mut(self.inner.as_mut_slice())
}
}

#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Deref for OsString {
type Target = OsStr;
Expand All @@ -389,6 +397,14 @@ impl ops::Deref for OsString {
}
}

#[stable(feature = "mut_osstr", since = "1.44.0")]
impl ops::DerefMut for OsString {
#[inline]
fn deref_mut(&mut self) -> &mut OsStr {
&mut self[..]
}
}

#[stable(feature = "osstring_default", since = "1.9.0")]
impl Default for OsString {
/// Constructs an empty `OsString`.
Expand Down Expand Up @@ -509,9 +525,20 @@ impl OsStr {

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

#[inline]
fn from_inner_mut(inner: &mut Slice) -> &mut OsStr {
// Safety: OsStr is just a wrapper of Slice,
// therefore converting &mut Slice to &mut OsStr is safe.
// Any method that mutates OsStr must be careful not to
// break platform-specific encoding, in particular Wtf8 on Windows.
unsafe { &mut *(inner as *mut Slice as *mut OsStr) }
}

/// Yields a [`&str`] slice if the `OsStr` is valid Unicode.
///
/// This conversion may entail doing a check for UTF-8 validity.
Expand Down
12 changes: 12 additions & 0 deletions src/libstd/sys/windows/os_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,9 +77,21 @@ impl Buf {
}

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

pub fn as_mut_slice(&mut self) -> &mut Slice {
// Safety: Slice is just a wrapper for Wtf8,
// and self.inner.as_mut_slice() returns &mut Wtf8.
// Therefore, transmuting &mut Wtf8 to &mut Slice is safe.
// Additionally, care should be taken to ensure the slice
// is always valid Wtf8.
unsafe { mem::transmute(self.inner.as_mut_slice()) }
}

pub fn into_string(self) -> Result<String, Buf> {
self.inner.into_string().map_err(|buf| Buf { inner: buf })
}
Expand Down
11 changes: 11 additions & 0 deletions src/libstd/sys_common/os_str_bytes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,20 @@ impl Buf {

#[inline]
pub fn as_slice(&self) -> &Slice {
// Safety: Slice just wraps [u8],
// and &*self.inner is &[u8], therefore
// transmuting &[u8] to &Slice is safe.
unsafe { mem::transmute(&*self.inner) }
}

#[inline]
pub fn as_mut_slice(&mut self) -> &mut Slice {
// Safety: Slice just wraps [u8],
// and &mut *self.inner is &mut [u8], therefore
// transmuting &mut [u8] to &mut Slice is safe.
unsafe { mem::transmute(&mut *self.inner) }
}

pub fn into_string(self) -> Result<String, Buf> {
String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() })
}
Expand Down

0 comments on commit c0369c4

Please sign in to comment.