1
Fork 0

Rollup merge of #44044 - mattico:string-splice-return, r=dtolnay

Remove Splice struct return value from String::splice

The implementation is now almost identical to the one in the RFC.

Fixes #44038
cc #32310
This commit is contained in:
Alex Crichton 2017-08-30 11:11:09 -05:00 committed by GitHub
commit 581dc93293
3 changed files with 25 additions and 109 deletions

View file

@ -18,7 +18,6 @@ let mut s = String::from("α is alpha, β is beta");
let beta_offset = s.find('β').unwrap_or(s.len()); let beta_offset = s.find('β').unwrap_or(s.len());
// Replace the range up until the β from the string // Replace the range up until the β from the string
let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); s.splice(..beta_offset, "Α is capital alpha; ");
assert_eq!(t, "α is alpha, ");
assert_eq!(s, "Α is capital alpha; β is beta"); assert_eq!(s, "Α is capital alpha; β is beta");
``` ```

View file

@ -1392,11 +1392,11 @@ impl String {
} }
/// Creates a splicing iterator that removes the specified range in the string, /// Creates a splicing iterator that removes the specified range in the string,
/// replaces with the given string, and yields the removed chars. /// and replaces it with the given string.
/// The given string doesnt need to be the same length as the range. /// The given string doesn't need to be the same length as the range.
/// ///
/// Note: The element range is removed when the [`Splice`] is dropped, /// Note: Unlike [`Vec::splice`], the replacement happens eagerly, and this
/// even if the iterator is not consumed until the end. /// method does not return the removed chars.
/// ///
/// # Panics /// # Panics
/// ///
@ -1404,7 +1404,7 @@ impl String {
/// boundary, or if they're out of bounds. /// boundary, or if they're out of bounds.
/// ///
/// [`char`]: ../../std/primitive.char.html /// [`char`]: ../../std/primitive.char.html
/// [`Splice`]: ../../std/string/struct.Splice.html /// [`Vec::splice`]: ../../std/vec/struct.Vec.html#method.splice
/// ///
/// # Examples /// # Examples
/// ///
@ -1416,45 +1416,32 @@ impl String {
/// let beta_offset = s.find('β').unwrap_or(s.len()); /// let beta_offset = s.find('β').unwrap_or(s.len());
/// ///
/// // Replace the range up until the β from the string /// // Replace the range up until the β from the string
/// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect(); /// s.splice(..beta_offset, "Α is capital alpha; ");
/// assert_eq!(t, "α is alpha, ");
/// assert_eq!(s, "Α is capital alpha; β is beta"); /// assert_eq!(s, "Α is capital alpha; β is beta");
/// ``` /// ```
#[unstable(feature = "splice", reason = "recently added", issue = "32310")] #[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub fn splice<'a, 'b, R>(&'a mut self, range: R, replace_with: &'b str) -> Splice<'a, 'b> pub fn splice<R>(&mut self, range: R, replace_with: &str)
where R: RangeArgument<usize> where R: RangeArgument<usize>
{ {
// Memory safety // Memory safety
// //
// The String version of Splice does not have the memory safety issues // The String version of Splice does not have the memory safety issues
// of the vector version. The data is just plain bytes. // of the vector version. The data is just plain bytes.
// Because the range removal happens in Drop, if the Splice iterator is leaked,
// the removal will not happen. match range.start() {
let len = self.len(); Included(&n) => assert!(self.is_char_boundary(n)),
let start = match range.start() { Excluded(&n) => assert!(self.is_char_boundary(n + 1)),
Included(&n) => n, Unbounded => {},
Excluded(&n) => n + 1,
Unbounded => 0,
}; };
let end = match range.end() { match range.end() {
Included(&n) => n + 1, Included(&n) => assert!(self.is_char_boundary(n + 1)),
Excluded(&n) => n, Excluded(&n) => assert!(self.is_char_boundary(n)),
Unbounded => len, Unbounded => {},
}; };
// Take out two simultaneous borrows. The &mut String won't be accessed unsafe {
// until iteration is over, in Drop. self.as_mut_vec()
let self_ptr = self as *mut _; }.splice(range, replace_with.bytes());
// slicing does the appropriate bounds checks
let chars_iter = self[start..end].chars();
Splice {
start,
end,
iter: chars_iter,
string: self_ptr,
replace_with,
}
} }
/// Converts this `String` into a [`Box`]`<`[`str`]`>`. /// Converts this `String` into a [`Box`]`<`[`str`]`>`.
@ -2241,61 +2228,3 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
#[unstable(feature = "fused", issue = "35602")] #[unstable(feature = "fused", issue = "35602")]
impl<'a> FusedIterator for Drain<'a> {} impl<'a> FusedIterator for Drain<'a> {}
/// A splicing iterator for `String`.
///
/// This struct is created by the [`splice()`] method on [`String`]. See its
/// documentation for more.
///
/// [`splice()`]: struct.String.html#method.splice
/// [`String`]: struct.String.html
#[derive(Debug)]
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
pub struct Splice<'a, 'b> {
/// Will be used as &'a mut String in the destructor
string: *mut String,
/// Start of part to remove
start: usize,
/// End of part to remove
end: usize,
/// Current remaining range to remove
iter: Chars<'a>,
replace_with: &'b str,
}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Sync for Splice<'a, 'b> {}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
unsafe impl<'a, 'b> Send for Splice<'a, 'b> {}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Drop for Splice<'a, 'b> {
fn drop(&mut self) {
unsafe {
let vec = (*self.string).as_mut_vec();
vec.splice(self.start..self.end, self.replace_with.bytes());
}
}
}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> Iterator for Splice<'a, 'b> {
type Item = char;
#[inline]
fn next(&mut self) -> Option<char> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
#[unstable(feature = "splice", reason = "recently added", issue = "32310")]
impl<'a, 'b> DoubleEndedIterator for Splice<'a, 'b> {
#[inline]
fn next_back(&mut self) -> Option<char> {
self.iter.next_back()
}
}

View file

@ -442,9 +442,8 @@ fn test_drain() {
#[test] #[test]
fn test_splice() { fn test_splice() {
let mut s = "Hello, world!".to_owned(); let mut s = "Hello, world!".to_owned();
let t: String = s.splice(7..12, "世界").collect(); s.splice(7..12, "世界");
assert_eq!(s, "Hello, 世界!"); assert_eq!(s, "Hello, 世界!");
assert_eq!(t, "world");
} }
#[test] #[test]
@ -457,12 +456,10 @@ fn test_splice_char_boundary() {
#[test] #[test]
fn test_splice_inclusive_range() { fn test_splice_inclusive_range() {
let mut v = String::from("12345"); let mut v = String::from("12345");
let t: String = v.splice(2...3, "789").collect(); v.splice(2...3, "789");
assert_eq!(v, "127895"); assert_eq!(v, "127895");
assert_eq!(t, "34"); v.splice(1...2, "A");
let t2: String = v.splice(1...2, "A").collect();
assert_eq!(v, "1A895"); assert_eq!(v, "1A895");
assert_eq!(t2, "27");
} }
#[test] #[test]
@ -482,24 +479,15 @@ fn test_splice_inclusive_out_of_bounds() {
#[test] #[test]
fn test_splice_empty() { fn test_splice_empty() {
let mut s = String::from("12345"); let mut s = String::from("12345");
let t: String = s.splice(1..2, "").collect(); s.splice(1..2, "");
assert_eq!(s, "1345"); assert_eq!(s, "1345");
assert_eq!(t, "2");
} }
#[test] #[test]
fn test_splice_unbounded() { fn test_splice_unbounded() {
let mut s = String::from("12345"); let mut s = String::from("12345");
let t: String = s.splice(.., "").collect(); s.splice(.., "");
assert_eq!(s, ""); assert_eq!(s, "");
assert_eq!(t, "12345");
}
#[test]
fn test_splice_forget() {
let mut s = String::from("12345");
::std::mem::forget(s.splice(2..4, "789"));
assert_eq!(s, "12345");
} }
#[test] #[test]