@@ -26,7 +26,8 @@ use rustc_unicode::str as unicode_str;
26
26
use rustc_unicode:: str:: Utf16Item ;
27
27
28
28
use borrow:: { Cow , IntoCow } ;
29
- use str:: { self , FromStr , Utf8Error } ;
29
+ use range:: RangeArgument ;
30
+ use str:: { self , FromStr , Utf8Error , Chars } ;
30
31
use vec:: { DerefVec , Vec , as_vec} ;
31
32
32
33
/// A growable string stored as a UTF-8 encoded buffer.
@@ -695,6 +696,59 @@ impl String {
695
696
pub fn clear ( & mut self ) {
696
697
self . vec . clear ( )
697
698
}
699
+
700
+ /// Create a draining iterator that removes the specified range in the string
701
+ /// and yields the removed chars from start to end. The element range is
702
+ /// removed even if the iterator is not consumed until the end.
703
+ ///
704
+ /// # Panics
705
+ ///
706
+ /// Panics if the starting point or end point are not on character boundaries,
707
+ /// or if they are out of bounds.
708
+ ///
709
+ /// # Examples
710
+ ///
711
+ /// ```
712
+ /// # #![feature(collections_drain)]
713
+ ///
714
+ /// let mut s = String::from("α is alpha, β is beta");
715
+ /// let beta_offset = s.find('β').unwrap_or(s.len());
716
+ ///
717
+ /// // Remove the range up until the β from the string
718
+ /// let t: String = s.drain(..beta_offset).collect();
719
+ /// assert_eq!(t, "α is alpha, ");
720
+ /// assert_eq!(s, "β is beta");
721
+ ///
722
+ /// // A full range clears the string
723
+ /// s.drain(..);
724
+ /// assert_eq!(s, "");
725
+ /// ```
726
+ #[ unstable( feature = "collections_drain" ,
727
+ reason = "recently added, matches RFC" ) ]
728
+ pub fn drain < R > ( & mut self , range : R ) -> Drain where R : RangeArgument < usize > {
729
+ // Memory safety
730
+ //
731
+ // The String version of Drain does not have the memory safety issues
732
+ // of the vector version. The data is just plain bytes.
733
+ // Because the range removal happens in Drop, if the Drain iterator is leaked,
734
+ // the removal will not happen.
735
+ let len = self . len ( ) ;
736
+ let start = * range. start ( ) . unwrap_or ( & 0 ) ;
737
+ let end = * range. end ( ) . unwrap_or ( & len) ;
738
+
739
+ // Take out two simultaneous borrows. The &mut String won't be accessed
740
+ // until iteration is over, in Drop.
741
+ let self_ptr = self as * mut _ ;
742
+ // slicing does the appropriate bounds checks
743
+ let chars_iter = self [ start..end] . chars ( ) ;
744
+
745
+ Drain {
746
+ start : start,
747
+ end : end,
748
+ iter : chars_iter,
749
+ string : self_ptr,
750
+ }
751
+ }
698
752
}
699
753
700
754
impl FromUtf8Error {
@@ -1075,3 +1129,55 @@ impl fmt::Write for String {
1075
1129
Ok ( ( ) )
1076
1130
}
1077
1131
}
1132
+
1133
+ /// A draining iterator for `String`.
1134
+ #[ unstable( feature = "collections_drain" , reason = "recently added" ) ]
1135
+ pub struct Drain < ' a > {
1136
+ /// Will be used as &'a mut String in the destructor
1137
+ string : * mut String ,
1138
+ /// Start of part to remove
1139
+ start : usize ,
1140
+ /// End of part to remove
1141
+ end : usize ,
1142
+ /// Current remaining range to remove
1143
+ iter : Chars < ' a > ,
1144
+ }
1145
+
1146
+ unsafe impl < ' a > Sync for Drain < ' a > { }
1147
+ unsafe impl < ' a > Send for Drain < ' a > { }
1148
+
1149
+ #[ unstable( feature = "collections_drain" , reason = "recently added" ) ]
1150
+ impl < ' a > Drop for Drain < ' a > {
1151
+ fn drop ( & mut self ) {
1152
+ unsafe {
1153
+ // Use Vec::drain. "Reaffirm" the bounds checks to avoid
1154
+ // panic code being inserted again.
1155
+ let self_vec = ( * self . string ) . as_mut_vec ( ) ;
1156
+ if self . start <= self . end && self . end <= self_vec. len ( ) {
1157
+ self_vec. drain ( self . start ..self . end ) ;
1158
+ }
1159
+ }
1160
+ }
1161
+ }
1162
+
1163
+ #[ unstable( feature = "collections_drain" , reason = "recently added" ) ]
1164
+ impl < ' a > Iterator for Drain < ' a > {
1165
+ type Item = char ;
1166
+
1167
+ #[ inline]
1168
+ fn next ( & mut self ) -> Option < char > {
1169
+ self . iter . next ( )
1170
+ }
1171
+
1172
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
1173
+ self . iter . size_hint ( )
1174
+ }
1175
+ }
1176
+
1177
+ #[ unstable( feature = "collections_drain" , reason = "recently added" ) ]
1178
+ impl < ' a > DoubleEndedIterator for Drain < ' a > {
1179
+ #[ inline]
1180
+ fn next_back ( & mut self ) -> Option < char > {
1181
+ self . iter . next_back ( )
1182
+ }
1183
+ }
0 commit comments