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