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:
commit
581dc93293
3 changed files with 25 additions and 109 deletions
|
@ -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");
|
||||||
```
|
```
|
|
@ -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 doesn’t 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue