Skip to content

Commit f900551

Browse files
committed
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.
1 parent 90d61d8 commit f900551

File tree

4 files changed

+108
-0
lines changed

4 files changed

+108
-0
lines changed

src/libcollections/str.rs

+8
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,14 @@ impl str {
546546
core_str::StrExt::slice_unchecked(self, begin, end)
547547
}
548548

549+
/// Takes a bytewise mutable slice from a string.
550+
///
551+
/// Same as `slice_unchecked`, but works with `&mut str` instead of `&str`.
552+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
553+
pub unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
554+
core_str::StrExt::slice_mut_unchecked(self, begin, end)
555+
}
556+
549557
/// Returns a slice of the string from the character range [`begin`..`end`).
550558
///
551559
/// That is, start at the `begin`-th code point of the string and continue

src/libcollections/string.rs

+32
Original file line numberDiff line numberDiff line change
@@ -979,6 +979,38 @@ impl ops::Index<ops::RangeFull> for String {
979979
}
980980
}
981981

982+
#[cfg(not(stage0))]
983+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
984+
impl ops::IndexMut<ops::Range<usize>> for String {
985+
#[inline]
986+
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
987+
&mut self[..][index]
988+
}
989+
}
990+
#[cfg(not(stage0))]
991+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
992+
impl ops::IndexMut<ops::RangeTo<usize>> for String {
993+
#[inline]
994+
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
995+
&mut self[..][index]
996+
}
997+
}
998+
#[cfg(not(stage0))]
999+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1000+
impl ops::IndexMut<ops::RangeFrom<usize>> for String {
1001+
#[inline]
1002+
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
1003+
&mut self[..][index]
1004+
}
1005+
}
1006+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1007+
impl ops::IndexMut<ops::RangeFull> for String {
1008+
#[inline]
1009+
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
1010+
unsafe { mem::transmute(&mut *self.vec) }
1011+
}
1012+
}
1013+
9821014
#[stable(feature = "rust1", since = "1.0.0")]
9831015
impl ops::Deref for String {
9841016
type Target = str;

src/libcore/str/mod.rs

+64
Original file line numberDiff line numberDiff line change
@@ -1116,6 +1116,23 @@ mod traits {
11161116
}
11171117
}
11181118

1119+
/// Returns a mutable slice of the given string from the byte range
1120+
/// [`begin`..`end`).
1121+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1122+
impl ops::IndexMut<ops::Range<usize>> for str {
1123+
#[inline]
1124+
fn index_mut(&mut self, index: ops::Range<usize>) -> &mut str {
1125+
// is_char_boundary checks that the index is in [0, .len()]
1126+
if index.start <= index.end &&
1127+
self.is_char_boundary(index.start) &&
1128+
self.is_char_boundary(index.end) {
1129+
unsafe { self.slice_mut_unchecked(index.start, index.end) }
1130+
} else {
1131+
super::slice_error_fail(self, index.start, index.end)
1132+
}
1133+
}
1134+
}
1135+
11191136
/// Returns a slice of the string from the beginning to byte
11201137
/// `end`.
11211138
///
@@ -1138,6 +1155,21 @@ mod traits {
11381155
}
11391156
}
11401157

1158+
/// Returns a mutable slice of the string from the beginning to byte
1159+
/// `end`.
1160+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1161+
impl ops::IndexMut<ops::RangeTo<usize>> for str {
1162+
#[inline]
1163+
fn index_mut(&mut self, index: ops::RangeTo<usize>) -> &mut str {
1164+
// is_char_boundary checks that the index is in [0, .len()]
1165+
if self.is_char_boundary(index.end) {
1166+
unsafe { self.slice_mut_unchecked(0, index.end) }
1167+
} else {
1168+
super::slice_error_fail(self, 0, index.end)
1169+
}
1170+
}
1171+
}
1172+
11411173
/// Returns a slice of the string from `begin` to its end.
11421174
///
11431175
/// Equivalent to `self[begin .. self.len()]`.
@@ -1159,6 +1191,21 @@ mod traits {
11591191
}
11601192
}
11611193

1194+
/// Returns a slice of the string from `begin` to its end.
1195+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1196+
impl ops::IndexMut<ops::RangeFrom<usize>> for str {
1197+
#[inline]
1198+
fn index_mut(&mut self, index: ops::RangeFrom<usize>) -> &mut str {
1199+
// is_char_boundary checks that the index is in [0, .len()]
1200+
if self.is_char_boundary(index.start) {
1201+
let len = self.len();
1202+
unsafe { self.slice_mut_unchecked(index.start, len) }
1203+
} else {
1204+
super::slice_error_fail(self, index.start, self.len())
1205+
}
1206+
}
1207+
}
1208+
11621209
#[stable(feature = "rust1", since = "1.0.0")]
11631210
impl ops::Index<ops::RangeFull> for str {
11641211
type Output = str;
@@ -1168,6 +1215,14 @@ mod traits {
11681215
self
11691216
}
11701217
}
1218+
1219+
#[stable(feature = "derefmut_for_string", since = "1.2.0")]
1220+
impl ops::IndexMut<ops::RangeFull> for str {
1221+
#[inline]
1222+
fn index_mut(&mut self, _index: ops::RangeFull) -> &mut str {
1223+
self
1224+
}
1225+
}
11711226
}
11721227

11731228
/// Methods for string slices
@@ -1204,6 +1259,7 @@ pub trait StrExt {
12041259
fn char_len(&self) -> usize;
12051260
fn slice_chars<'a>(&'a self, begin: usize, end: usize) -> &'a str;
12061261
unsafe fn slice_unchecked<'a>(&'a self, begin: usize, end: usize) -> &'a str;
1262+
unsafe fn slice_mut_unchecked<'a>(&'a mut self, begin: usize, end: usize) -> &'a mut str;
12071263
fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool;
12081264
fn ends_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool
12091265
where P::Searcher: ReverseSearcher<'a>;
@@ -1379,6 +1435,14 @@ impl StrExt for str {
13791435
})
13801436
}
13811437

1438+
#[inline]
1439+
unsafe fn slice_mut_unchecked(&mut self, begin: usize, end: usize) -> &mut str {
1440+
mem::transmute(Slice {
1441+
data: self.as_ptr().offset(begin as isize),
1442+
len: end - begin,
1443+
})
1444+
}
1445+
13821446
#[inline]
13831447
fn starts_with<'a, P: Pattern<'a>>(&'a self, pat: P) -> bool {
13841448
pat.is_prefix_of(self)

src/libstd/ascii.rs

+4
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@ mod tests {
583583
test!('!', '!');
584584
test!(b"h\xc3\xa9".to_vec(), b"H\xc3\xa9");
585585
test!("hıKß".to_string(), "HıKß");
586+
587+
let mut x = "Hello".to_string();
588+
x[..3].make_ascii_uppercase(); // Test IndexMut on String.
589+
assert_eq!(x, "HELlo")
586590
}
587591

588592
#[test]

0 commit comments

Comments
 (0)