Implement IndexMut for String and str.

... matching the existing Index impls.
There is no reason not to if String implement DerefMut.

The code removed in `src/librustc/middle/effect.rs` was added in #9750
to prevent things like `s[0] = 0x80` where `s: String`,
but I belive became unnecessary when the Index(Mut) traits were introduced.
This commit is contained in:
Simon Sapin 2015-06-15 18:33:21 +02:00
parent 90d61d828f
commit f9005512a9
4 changed files with 108 additions and 0 deletions

View File

@ -546,6 +546,14 @@ impl str {
core_str::StrExt::slice_unchecked(self, begin, end)
}
/// Takes a bytewise mutable slice from a string.
///
/// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`.
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
core_str::StrExt::slice_mut_unchecked(self, begin, end)
}
/// Returns a slice of the string from the character range [`begin`..`end`).
///
/// That is, start at the `begin`-th code point of the string and continue

View File

@ -979,6 +979,38 @@ impl ops::Index<ops::RangeFull> for String {
}
}
#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::Range<usize>> for String {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
&mut self[..][index]
}
}
#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeTo<usize>> for String {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
&mut self[..][index]
}
}
#[cfg(not(stage0))]
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeFrom<usize>> for String {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
&mut self[..][index]
}
}
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeFull> for String {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
unsafe { mem::transmute(&mut *self.vec) }
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Deref for String {
type Target = str;

View File

@ -1116,6 +1116,23 @@ mod traits {
}
}
/// Returns a mutable slice of the given string from the byte range
/// [`begin`..`end`).
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::Range<usize>> for str {
#[inline]
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
// is_char_boundary checks that the index is in [0, .len()]
if index.start <= index.end &&
self.is_char_boundary(index.start) &&
self.is_char_boundary(index.end) {
unsafe { self.slice_mut_unchecked(index.start, index.end) }
} else {
super::slice_error_fail(self, index.start, index.end)
}
}
}
/// Returns a slice of the string from the beginning to byte
/// `end`.
///
@ -1138,6 +1155,21 @@ mod traits {
}
}
/// Returns a mutable slice of the string from the beginning to byte
/// `end`.
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeTo<usize>> for str {
#[inline]
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(index.end) {
unsafe { self.slice_mut_unchecked(0, index.end) }
} else {
super::slice_error_fail(self, 0, index.end)
}
}
}
/// Returns a slice of the string from `begin` to its end.
///
/// Equivalent to `self[begin .. self.len()]`.
@ -1159,6 +1191,21 @@ mod traits {
}
}
/// Returns a slice of the string from `begin` to its end.
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeFrom<usize>> for str {
#[inline]
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
// is_char_boundary checks that the index is in [0, .len()]
if self.is_char_boundary(index.start) {
let len = self.len();
unsafe { self.slice_mut_unchecked(index.start, len) }
} else {
super::slice_error_fail(self, index.start, self.len())
}
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ops::Index<ops::RangeFull> for str {
type Output = str;
@ -1168,6 +1215,14 @@ mod traits {
self
}
}
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
impl ops::IndexMut<ops::RangeFull> for str {
#[inline]
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
self
}
}
}
/// Methods for string slices
@ -1204,6 +1259,7 @@ pub trait StrExt {
fn char_len(&self) -> usize;
fn slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str;
unsafe fn slice_unchecked<'a>(&'a self, begin: usize, end: usize) -> &'a str;
unsafe fn slice_mut_unchecked<'a>(&'a mut self, begin: usize, end: usize) -> &'a mut str;
fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
where P::Searcher: ReverseSearcher<'a>;
@ -1379,6 +1435,14 @@ impl StrExt for str {
})
}
#[inline]
unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
mem::transmute(Slice {
data: self.as_ptr().offset(begin as isize),
len: end - begin,
})
}
#[inline]
fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
pat.is_prefix_of(self)

View File

@ -583,6 +583,10 @@ mod tests {
test!('!', '!');
test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9");
test!("hıß".to_string(), "Hıß");
let mut x = "Hello".to_string();
x[..3].make_ascii_uppercase(); // Test IndexMut on String.
assert_eq!(x, "HELlo")
}
#[test]