Skip to content

Commit c58c928

Browse files
committed
Auto merge of rust-lang#41096 - clarcharr:as_bytes_mut, r=alexcrichton
Reduce str transmutes, add mut versions of methods. When I was working on the various parts involved in rust-lang#40380 one of the comments I got was the excess of transmutes necessary to make the changes work. This is part of a set of multiple changes I'd like to offer to fix this problem. I think that having these methods is reasonable because they're already possible via transmutes, and it makes the code that uses them safer. I can also add `pub(crate)` to these methods for now if the libs team would rather not expose them to the public without an RFC.
2 parents 6edc596 + a2b28be commit c58c928

File tree

9 files changed

+57
-14
lines changed

9 files changed

+57
-14
lines changed

src/doc/unstable-book/src/SUMMARY.md

+1
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@
188188
- [str_checked_slicing](str-checked-slicing.md)
189189
- [str_escape](str-escape.md)
190190
- [str_internals](str-internals.md)
191+
- [str_mut_extras](str-mut-extras.md)
191192
- [struct_field_attributes](struct-field-attributes.md)
192193
- [structural_match](structural-match.md)
193194
- [target_feature](target-feature.md)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# `str_mut_extras`
2+
3+
The tracking issue for this feature is: [#str_mut_extras]
4+
5+
[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119
6+
7+
------------------------
8+

src/libcollections/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
#![feature(specialization)]
5858
#![feature(staged_api)]
5959
#![feature(str_internals)]
60+
#![feature(str_mut_extras)]
6061
#![feature(trusted_len)]
6162
#![feature(unicode)]
6263
#![feature(unique)]

src/libcollections/str.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ pub use core::str::{MatchIndices, RMatchIndices};
7272
#[stable(feature = "rust1", since = "1.0.0")]
7373
pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
7474
#[stable(feature = "rust1", since = "1.0.0")]
75-
pub use core::str::{from_utf8_unchecked, ParseBoolError};
75+
pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
7676
#[stable(feature = "rust1", since = "1.0.0")]
7777
pub use std_unicode::str::SplitWhitespace;
7878
#[stable(feature = "rust1", since = "1.0.0")]
@@ -294,6 +294,13 @@ impl str {
294294
core_str::StrExt::as_bytes(self)
295295
}
296296

297+
/// Converts a mutable string slice to a mutable byte slice.
298+
#[unstable(feature = "str_mut_extras", issue = "41119")]
299+
#[inline(always)]
300+
pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
301+
core_str::StrExt::as_bytes_mut(self)
302+
}
303+
297304
/// Converts a string slice to a raw pointer.
298305
///
299306
/// As string slices are a slice of bytes, the raw pointer points to a

src/libcollections/string.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1790,7 +1790,7 @@ impl ops::IndexMut<ops::RangeFrom<usize>> for String {
17901790
impl ops::IndexMut<ops::RangeFull> for String {
17911791
#[inline]
17921792
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
1793-
unsafe { mem::transmute(&mut *self.vec) }
1793+
unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
17941794
}
17951795
}
17961796
#[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
@@ -1822,7 +1822,7 @@ impl ops::Deref for String {
18221822
impl ops::DerefMut for String {
18231823
#[inline]
18241824
fn deref_mut(&mut self) -> &mut str {
1825-
unsafe { mem::transmute(&mut *self.vec) }
1825+
unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
18261826
}
18271827
}
18281828

src/libcore/char.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ use char_private::is_printable;
1919
use convert::TryFrom;
2020
use fmt::{self, Write};
2121
use slice;
22+
use str::from_utf8_unchecked_mut;
2223
use iter::FusedIterator;
2324
use mem::transmute;
2425

@@ -448,7 +449,7 @@ impl CharExt for char {
448449
code,
449450
dst.len())
450451
};
451-
transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
452+
from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
452453
}
453454
}
454455

src/libcore/str/mod.rs

+32-7
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ use char;
2121
use convert::TryFrom;
2222
use fmt;
2323
use iter::{Map, Cloned, FusedIterator};
24-
use mem;
2524
use slice::{self, SliceIndex};
25+
use mem;
2626

2727
pub mod pattern;
2828

@@ -300,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
300300
Ok(unsafe { from_utf8_unchecked(v) })
301301
}
302302

303+
/// Converts a mutable slice of bytes to a mutable string slice.
304+
#[unstable(feature = "str_mut_extras", issue = "41119")]
305+
pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
306+
run_utf8_validation(v)?;
307+
Ok(unsafe { from_utf8_unchecked_mut(v) })
308+
}
309+
303310
/// Forms a str from a pointer and a length.
304311
///
305312
/// The `len` argument is the number of bytes in the string.
@@ -325,7 +332,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
325332
/// str is returned.
326333
///
327334
unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str {
328-
mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len))
335+
from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len))
329336
}
330337

331338
/// Converts a slice of bytes to a string slice without checking
@@ -365,6 +372,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
365372
mem::transmute(v)
366373
}
367374

375+
/// Converts a slice of bytes to a string slice without checking
376+
/// that the string contains valid UTF-8; mutable version.
377+
///
378+
/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
379+
///
380+
/// [fromutf8]: fn.from_utf8_unchecked.html
381+
#[inline(always)]
382+
#[unstable(feature = "str_mut_extras", issue = "41119")]
383+
pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
384+
mem::transmute(v)
385+
}
386+
368387
#[stable(feature = "rust1", since = "1.0.0")]
369388
impl fmt::Display for Utf8Error {
370389
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1474,7 +1493,6 @@ Section: Trait implementations
14741493
mod traits {
14751494
use cmp::Ordering;
14761495
use ops;
1477-
use mem;
14781496
use slice::{self, SliceIndex};
14791497
use str::eq_slice;
14801498

@@ -1811,7 +1829,7 @@ mod traits {
18111829
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
18121830
let ptr = slice.as_ptr().offset(self.start as isize);
18131831
let len = self.end - self.start;
1814-
mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
1832+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
18151833
}
18161834
#[inline]
18171835
fn index(self, slice: &str) -> &Self::Output {
@@ -1859,7 +1877,7 @@ mod traits {
18591877
#[inline]
18601878
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
18611879
let ptr = slice.as_ptr();
1862-
mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
1880+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
18631881
}
18641882
#[inline]
18651883
fn index(self, slice: &str) -> &Self::Output {
@@ -1905,7 +1923,7 @@ mod traits {
19051923
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
19061924
let ptr = slice.as_ptr().offset(self.start as isize);
19071925
let len = slice.len() - self.start;
1908-
mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
1926+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
19091927
}
19101928
#[inline]
19111929
fn index(self, slice: &str) -> &Self::Output {
@@ -1998,7 +2016,7 @@ mod traits {
19982016
#[inline]
19992017
unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
20002018
let ptr = slice.as_ptr();
2001-
mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
2019+
super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
20022020
}
20032021
#[inline]
20042022
fn index(self, slice: &str) -> &Self::Output {
@@ -2096,6 +2114,8 @@ pub trait StrExt {
20962114
fn is_char_boundary(&self, index: usize) -> bool;
20972115
#[stable(feature = "core", since = "1.6.0")]
20982116
fn as_bytes(&self) -> &[u8];
2117+
#[unstable(feature = "str_mut_extras", issue = "0")]
2118+
unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
20992119
#[stable(feature = "core", since = "1.6.0")]
21002120
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
21012121
#[stable(feature = "core", since = "1.6.0")]
@@ -2373,6 +2393,11 @@ impl StrExt for str {
23732393
unsafe { mem::transmute(self) }
23742394
}
23752395

2396+
#[inline]
2397+
unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
2398+
mem::transmute(self)
2399+
}
2400+
23762401
fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
23772402
pat.into_searcher(self).next_match().map(|(i, _)| i)
23782403
}

src/libstd/ascii.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#![stable(feature = "rust1", since = "1.0.0")]
2828

2929
use fmt;
30-
use mem;
3130
use ops::Range;
3231
use iter::FusedIterator;
3332

@@ -599,12 +598,12 @@ impl AsciiExt for str {
599598
}
600599

601600
fn make_ascii_uppercase(&mut self) {
602-
let me: &mut [u8] = unsafe { mem::transmute(self) };
601+
let me = unsafe { self.as_bytes_mut() };
603602
me.make_ascii_uppercase()
604603
}
605604

606605
fn make_ascii_lowercase(&mut self) {
607-
let me: &mut [u8] = unsafe { mem::transmute(self) };
606+
let me = unsafe { self.as_bytes_mut() };
608607
me.make_ascii_lowercase()
609608
}
610609

src/libstd/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@
296296
#![feature(stmt_expr_attributes)]
297297
#![feature(str_char)]
298298
#![feature(str_internals)]
299+
#![feature(str_mut_extras)]
299300
#![feature(str_utf16)]
300301
#![feature(test, rustc_private)]
301302
#![feature(thread_local)]

0 commit comments

Comments
 (0)