about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/doc/unstable-book/src/SUMMARY.md1
-rw-r--r--src/doc/unstable-book/src/str-mut-extras.md8
-rw-r--r--src/libcollections/lib.rs1
-rw-r--r--src/libcollections/str.rs9
-rw-r--r--src/libcollections/string.rs4
-rw-r--r--src/libcore/char.rs3
-rw-r--r--src/libcore/str/mod.rs39
-rw-r--r--src/libstd/ascii.rs5
-rw-r--r--src/libstd/lib.rs1
9 files changed, 57 insertions, 14 deletions
diff --git a/src/doc/unstable-book/src/SUMMARY.md b/src/doc/unstable-book/src/SUMMARY.md
index d86766bac02..c077568d96e 100644
--- a/src/doc/unstable-book/src/SUMMARY.md
+++ b/src/doc/unstable-book/src/SUMMARY.md
@@ -187,6 +187,7 @@
 - [str_checked_slicing](str-checked-slicing.md)
 - [str_escape](str-escape.md)
 - [str_internals](str-internals.md)
+- [str_mut_extras](str-mut-extras.md)
 - [struct_field_attributes](struct-field-attributes.md)
 - [structural_match](structural-match.md)
 - [target_feature](target-feature.md)
diff --git a/src/doc/unstable-book/src/str-mut-extras.md b/src/doc/unstable-book/src/str-mut-extras.md
new file mode 100644
index 00000000000..df4f35832cd
--- /dev/null
+++ b/src/doc/unstable-book/src/str-mut-extras.md
@@ -0,0 +1,8 @@
+# `str_mut_extras`
+
+The tracking issue for this feature is: [#str_mut_extras]
+
+[#str_mut_extras]: https://github.com/rust-lang/rust/issues/41119
+
+------------------------
+
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 248c15e96f8..b485f900094 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -57,6 +57,7 @@
 #![feature(specialization)]
 #![feature(staged_api)]
 #![feature(str_internals)]
+#![feature(str_mut_extras)]
 #![feature(trusted_len)]
 #![feature(unicode)]
 #![feature(unique)]
diff --git a/src/libcollections/str.rs b/src/libcollections/str.rs
index c37a4fa6b55..d04f414250a 100644
--- a/src/libcollections/str.rs
+++ b/src/libcollections/str.rs
@@ -72,7 +72,7 @@ pub use core::str::{MatchIndices, RMatchIndices};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use core::str::{from_utf8, Chars, CharIndices, Bytes};
 #[stable(feature = "rust1", since = "1.0.0")]
-pub use core::str::{from_utf8_unchecked, ParseBoolError};
+pub use core::str::{from_utf8_unchecked, from_utf8_unchecked_mut, ParseBoolError};
 #[stable(feature = "rust1", since = "1.0.0")]
 pub use std_unicode::str::SplitWhitespace;
 #[stable(feature = "rust1", since = "1.0.0")]
@@ -294,6 +294,13 @@ impl str {
         core_str::StrExt::as_bytes(self)
     }
 
+    /// Converts a mutable string slice to a mutable byte slice.
+    #[unstable(feature = "str_mut_extras", issue = "41119")]
+    #[inline(always)]
+    pub unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+        core_str::StrExt::as_bytes_mut(self)
+    }
+
     /// Converts a string slice to a raw pointer.
     ///
     /// As string slices are a slice of bytes, the raw pointer points to a
diff --git a/src/libcollections/string.rs b/src/libcollections/string.rs
index 0ee4c8b8e95..7d9d7276201 100644
--- a/src/libcollections/string.rs
+++ b/src/libcollections/string.rs
@@ -1790,7 +1790,7 @@ impl ops::IndexMut<ops::RangeFrom<usize>> for String {
 impl ops::IndexMut<ops::RangeFull> for String {
     #[inline]
     fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
-        unsafe { mem::transmute(&mut *self.vec) }
+        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
     }
 }
 #[unstable(feature = "inclusive_range", reason = "recently added, follows RFC", issue = "28237")]
@@ -1822,7 +1822,7 @@ impl ops::Deref for String {
 impl ops::DerefMut for String {
     #[inline]
     fn deref_mut(&mut self) -> &mut str {
-        unsafe { mem::transmute(&mut *self.vec) }
+        unsafe { str::from_utf8_unchecked_mut(&mut *self.vec) }
     }
 }
 
diff --git a/src/libcore/char.rs b/src/libcore/char.rs
index b27c801cf89..98268e3813f 100644
--- a/src/libcore/char.rs
+++ b/src/libcore/char.rs
@@ -19,6 +19,7 @@ use char_private::is_printable;
 use convert::TryFrom;
 use fmt::{self, Write};
 use slice;
+use str::from_utf8_unchecked_mut;
 use iter::FusedIterator;
 use mem::transmute;
 
@@ -448,7 +449,7 @@ impl CharExt for char {
                     code,
                     dst.len())
             };
-            transmute(slice::from_raw_parts_mut(dst.as_mut_ptr(), len))
+            from_utf8_unchecked_mut(dst.get_unchecked_mut(..len))
         }
     }
 
diff --git a/src/libcore/str/mod.rs b/src/libcore/str/mod.rs
index 352cc926994..2ceef54ffed 100644
--- a/src/libcore/str/mod.rs
+++ b/src/libcore/str/mod.rs
@@ -21,8 +21,8 @@ use char;
 use convert::TryFrom;
 use fmt;
 use iter::{Map, Cloned, FusedIterator};
-use mem;
 use slice::{self, SliceIndex};
+use mem;
 
 pub mod pattern;
 
@@ -300,6 +300,13 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
     Ok(unsafe { from_utf8_unchecked(v) })
 }
 
+/// Converts a mutable slice of bytes to a mutable string slice.
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> {
+    run_utf8_validation(v)?;
+    Ok(unsafe { from_utf8_unchecked_mut(v) })
+}
+
 /// Forms a str from a pointer and a length.
 ///
 /// The `len` argument is the number of bytes in the string.
@@ -325,7 +332,7 @@ pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> {
 /// str is returned.
 ///
 unsafe fn from_raw_parts_mut<'a>(p: *mut u8, len: usize) -> &'a mut str {
-    mem::transmute::<&mut [u8], &mut str>(slice::from_raw_parts_mut(p, len))
+    from_utf8_unchecked_mut(slice::from_raw_parts_mut(p, len))
 }
 
 /// Converts a slice of bytes to a string slice without checking
@@ -365,6 +372,18 @@ pub unsafe fn from_utf8_unchecked(v: &[u8]) -> &str {
     mem::transmute(v)
 }
 
+/// Converts a slice of bytes to a string slice without checking
+/// that the string contains valid UTF-8; mutable version.
+///
+/// See the immutable version, [`from_utf8_unchecked()`][fromutf8], for more information.
+///
+/// [fromutf8]: fn.from_utf8_unchecked.html
+#[inline(always)]
+#[unstable(feature = "str_mut_extras", issue = "41119")]
+pub unsafe fn from_utf8_unchecked_mut(v: &mut [u8]) -> &mut str {
+    mem::transmute(v)
+}
+
 #[stable(feature = "rust1", since = "1.0.0")]
 impl fmt::Display for Utf8Error {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@@ -1474,7 +1493,6 @@ Section: Trait implementations
 mod traits {
     use cmp::Ordering;
     use ops;
-    use mem;
     use slice::{self, SliceIndex};
     use str::eq_slice;
 
@@ -1811,7 +1829,7 @@ mod traits {
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr().offset(self.start as isize);
             let len = self.end - self.start;
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1859,7 +1877,7 @@ mod traits {
         #[inline]
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr();
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1905,7 +1923,7 @@ mod traits {
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr().offset(self.start as isize);
             let len = slice.len() - self.start;
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, len))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, len))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -1998,7 +2016,7 @@ mod traits {
         #[inline]
         unsafe fn get_unchecked_mut(self, slice: &mut str) -> &mut Self::Output {
             let ptr = slice.as_ptr();
-            mem::transmute(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
+            super::from_utf8_unchecked_mut(slice::from_raw_parts_mut(ptr as *mut u8, self.end + 1))
         }
         #[inline]
         fn index(self, slice: &str) -> &Self::Output {
@@ -2096,6 +2114,8 @@ pub trait StrExt {
     fn is_char_boundary(&self, index: usize) -> bool;
     #[stable(feature = "core", since = "1.6.0")]
     fn as_bytes(&self) -> &[u8];
+    #[unstable(feature = "str_mut_extras", issue = "0")]
+    unsafe fn as_bytes_mut(&mut self) -> &mut [u8];
     #[stable(feature = "core", since = "1.6.0")]
     fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize>;
     #[stable(feature = "core", since = "1.6.0")]
@@ -2373,6 +2393,11 @@ impl StrExt for str {
         unsafe { mem::transmute(self) }
     }
 
+    #[inline]
+    unsafe fn as_bytes_mut(&mut self) -> &mut [u8] {
+        mem::transmute(self)
+    }
+
     fn find<'a, P: Pattern<'a>>(&'a self, pat: P) -> Option<usize> {
         pat.into_searcher(self).next_match().map(|(i, _)| i)
     }
diff --git a/src/libstd/ascii.rs b/src/libstd/ascii.rs
index b3625386209..4e3781ecafa 100644
--- a/src/libstd/ascii.rs
+++ b/src/libstd/ascii.rs
@@ -27,7 +27,6 @@
 #![stable(feature = "rust1", since = "1.0.0")]
 
 use fmt;
-use mem;
 use ops::Range;
 use iter::FusedIterator;
 
@@ -599,12 +598,12 @@ impl AsciiExt for str {
     }
 
     fn make_ascii_uppercase(&mut self) {
-        let me: &mut [u8] = unsafe { mem::transmute(self) };
+        let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_uppercase()
     }
 
     fn make_ascii_lowercase(&mut self) {
-        let me: &mut [u8] = unsafe { mem::transmute(self) };
+        let me = unsafe { self.as_bytes_mut() };
         me.make_ascii_lowercase()
     }
 
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 064144dcd68..6299a9070ae 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -296,6 +296,7 @@
 #![feature(stmt_expr_attributes)]
 #![feature(str_char)]
 #![feature(str_internals)]
+#![feature(str_mut_extras)]
 #![feature(str_utf16)]
 #![feature(test, rustc_private)]
 #![feature(thread_local)]