@@ -1316,7 +1316,7 @@ impl String {
13161316 self . vec . clear ( )
13171317 }
13181318
1319- /// Create a draining iterator that removes the specified range in the string
1319+ /// Creates a draining iterator that removes the specified range in the string
13201320 /// and yields the removed chars.
13211321 ///
13221322 /// Note: The element range is removed even if the iterator is not
@@ -1382,6 +1382,71 @@ impl String {
13821382 }
13831383 }
13841384
1385+ /// Creates a splicing iterator that removes the specified range in the string,
1386+ /// replaces with the given string, and yields the removed chars.
1387+ /// The given string doesn’t need to be the same length as the range.
1388+ ///
1389+ /// Note: The element range is removed when the `Splice` is dropped,
1390+ /// even if the iterator is not consumed until the end.
1391+ ///
1392+ /// # Panics
1393+ ///
1394+ /// Panics if the starting point or end point do not lie on a [`char`]
1395+ /// boundary, or if they're out of bounds.
1396+ ///
1397+ /// [`char`]: ../../std/primitive.char.html
1398+ ///
1399+ /// # Examples
1400+ ///
1401+ /// Basic usage:
1402+ ///
1403+ /// ```
1404+ /// #![feature(splice)]
1405+ /// let mut s = String::from("α is alpha, β is beta");
1406+ /// let beta_offset = s.find('β').unwrap_or(s.len());
1407+ ///
1408+ /// // Replace the range up until the β from the string
1409+ /// let t: String = s.splice(..beta_offset, "Α is capital alpha; ").collect();
1410+ /// assert_eq!(t, "α is alpha, ");
1411+ /// assert_eq!(s, "Α is capital alpha; β is beta");
1412+ /// ```
1413+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
1414+ pub fn splice < ' a , ' b , R > ( & ' a mut self , range : R , replace_with : & ' b str ) -> Splice < ' a , ' b >
1415+ where R : RangeArgument < usize >
1416+ {
1417+ // Memory safety
1418+ //
1419+ // The String version of Splice does not have the memory safety issues
1420+ // of the vector version. The data is just plain bytes.
1421+ // Because the range removal happens in Drop, if the Splice iterator is leaked,
1422+ // the removal will not happen.
1423+ let len = self . len ( ) ;
1424+ let start = match range. start ( ) {
1425+ Included ( & n) => n,
1426+ Excluded ( & n) => n + 1 ,
1427+ Unbounded => 0 ,
1428+ } ;
1429+ let end = match range. end ( ) {
1430+ Included ( & n) => n + 1 ,
1431+ Excluded ( & n) => n,
1432+ Unbounded => len,
1433+ } ;
1434+
1435+ // Take out two simultaneous borrows. The &mut String won't be accessed
1436+ // until iteration is over, in Drop.
1437+ let self_ptr = self as * mut _ ;
1438+ // slicing does the appropriate bounds checks
1439+ let chars_iter = self [ start..end] . chars ( ) ;
1440+
1441+ Splice {
1442+ start : start,
1443+ end : end,
1444+ iter : chars_iter,
1445+ string : self_ptr,
1446+ replace_with : replace_with
1447+ }
1448+ }
1449+
13851450 /// Converts this `String` into a `Box<str>`.
13861451 ///
13871452 /// This will drop any excess capacity.
@@ -2145,3 +2210,61 @@ impl<'a> DoubleEndedIterator for Drain<'a> {
21452210
21462211#[ unstable( feature = "fused" , issue = "35602" ) ]
21472212impl < ' a > FusedIterator for Drain < ' a > { }
2213+
2214+ /// A splicing iterator for `String`.
2215+ ///
2216+ /// This struct is created by the [`splice()`] method on [`String`]. See its
2217+ /// documentation for more.
2218+ ///
2219+ /// [`splice()`]: struct.String.html#method.splice
2220+ /// [`String`]: struct.String.html
2221+ #[ derive( Debug ) ]
2222+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2223+ pub struct Splice < ' a , ' b > {
2224+ /// Will be used as &'a mut String in the destructor
2225+ string : * mut String ,
2226+ /// Start of part to remove
2227+ start : usize ,
2228+ /// End of part to remove
2229+ end : usize ,
2230+ /// Current remaining range to remove
2231+ iter : Chars < ' a > ,
2232+ replace_with : & ' b str ,
2233+ }
2234+
2235+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2236+ unsafe impl < ' a , ' b > Sync for Splice < ' a , ' b > { }
2237+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2238+ unsafe impl < ' a , ' b > Send for Splice < ' a , ' b > { }
2239+
2240+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2241+ impl < ' a , ' b > Drop for Splice < ' a , ' b > {
2242+ fn drop ( & mut self ) {
2243+ unsafe {
2244+ let vec = ( * self . string ) . as_mut_vec ( ) ;
2245+ vec. splice ( self . start ..self . end , self . replace_with . bytes ( ) ) ;
2246+ }
2247+ }
2248+ }
2249+
2250+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2251+ impl < ' a , ' b > Iterator for Splice < ' a , ' b > {
2252+ type Item = char ;
2253+
2254+ #[ inline]
2255+ fn next ( & mut self ) -> Option < char > {
2256+ self . iter . next ( )
2257+ }
2258+
2259+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
2260+ self . iter . size_hint ( )
2261+ }
2262+ }
2263+
2264+ #[ unstable( feature = "splice" , reason = "recently added" , issue = "32310" ) ]
2265+ impl < ' a , ' b > DoubleEndedIterator for Splice < ' a , ' b > {
2266+ #[ inline]
2267+ fn next_back ( & mut self ) -> Option < char > {
2268+ self . iter . next_back ( )
2269+ }
2270+ }
0 commit comments