@@ -22,14 +22,14 @@ use core::fmt;
22
22
use core:: hash;
23
23
use core:: iter:: { IntoIterator , FromIterator } ;
24
24
use core:: mem;
25
- use core:: ops:: { self , Deref , Add , Index } ;
25
+ use core:: ops:: { self , Deref , Add , Index , Range , RangeTo , RangeFrom , RangeFull } ;
26
26
use core:: ptr;
27
27
use core:: raw:: Slice as RawSlice ;
28
28
use unicode:: str as unicode_str;
29
29
use unicode:: str:: Utf16Item ;
30
30
31
31
use borrow:: { Cow , IntoCow } ;
32
- use str:: { self , CharRange , FromStr , Utf8Error } ;
32
+ use str:: { self , CharRange , FromStr , Utf8Error , Chars } ;
33
33
use vec:: { DerefVec , Vec , as_vec} ;
34
34
35
35
/// A growable string stored as a UTF-8 encoded buffer.
@@ -670,6 +670,122 @@ impl String {
670
670
pub fn clear ( & mut self ) {
671
671
self . vec . clear ( )
672
672
}
673
+
674
+ /// Creates a draining iterator that clears the specified range in the String
675
+ /// and iterates over the characters contained in the range.
676
+ ///
677
+ /// # Example
678
+ ///
679
+ /// ```
680
+ /// let mut s = "Hello World!".to_string();
681
+ /// let s2: String = s.drain(6..11).collect();
682
+ /// assert_eq!(s, "Hello !");
683
+ /// assert_eq!(s2, "World");
684
+ /// ```
685
+ ///
686
+ /// # Panics
687
+ ///
688
+ /// Panics if the range is decreasing, if the upper bound is larger than the
689
+ /// length of the String, or if the start and the end of the range don't lie on
690
+ /// character boundaries.
691
+ pub fn drain < ' a , T : DrainRange > ( & ' a mut self , range : T ) -> CharDrain < ' a > {
692
+ range. drain ( self )
693
+ }
694
+ }
695
+
696
+ /// A trait for draining a string.
697
+ ///
698
+ /// See the documentation of `String::drain`.
699
+ pub trait DrainRange {
700
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > ;
701
+ }
702
+
703
+ impl DrainRange for Range < usize > {
704
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > {
705
+ assert ! ( self . start <= self . end, "Range not increasing" ) ;
706
+ assert ! ( self . end <= s. len( ) , "Range out of bounds" ) ;
707
+ unsafe {
708
+ let slice = mem:: transmute :: < & str , & ' static str > ( & s[ self . start ..self . end ] ) ;
709
+ let tail = s. len ( ) - self . end ;
710
+ s. as_mut_vec ( ) . set_len ( tail + self . start ) ;
711
+ let ptr = s. as_mut_vec ( ) . as_mut_ptr ( ) ;
712
+ CharDrain {
713
+ tail : tail,
714
+ start : ptr. offset ( self . start as isize ) ,
715
+ end : ptr. offset ( self . end as isize ) ,
716
+ chars : slice. chars ( ) ,
717
+ }
718
+ }
719
+ }
720
+ }
721
+
722
+ impl DrainRange for RangeFrom < usize > {
723
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > {
724
+ assert ! ( self . start <= s. len( ) , "Range out of bounds" ) ;
725
+ ( self . start ..s. len ( ) ) . drain ( s)
726
+ }
727
+ }
728
+
729
+ impl DrainRange for RangeTo < usize > {
730
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > {
731
+ ( 0 ..self . end ) . drain ( s)
732
+ }
733
+ }
734
+
735
+ impl DrainRange for RangeFull {
736
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > {
737
+ ( 0 ..s. len ( ) ) . drain ( s)
738
+ }
739
+ }
740
+
741
+ impl DrainRange for usize {
742
+ fn drain < ' a > ( & self , s : & ' a mut String ) -> CharDrain < ' a > {
743
+ ( * self ..* self +1 ) . drain ( s)
744
+ }
745
+ }
746
+
747
+ /// An iterator that drains part of string.
748
+ #[ unsafe_no_drop_flag]
749
+ pub struct CharDrain < ' a > {
750
+ tail : usize ,
751
+ start : * mut u8 ,
752
+ end : * mut u8 ,
753
+ chars : Chars < ' a > ,
754
+ }
755
+
756
+ unsafe impl < ' a > Sync for CharDrain < ' a > { }
757
+ unsafe impl < ' a > Send for CharDrain < ' a > { }
758
+
759
+ impl < ' a > Iterator for CharDrain < ' a > {
760
+ type Item = char ;
761
+
762
+ #[ inline]
763
+ fn next ( & mut self ) -> Option < char > {
764
+ self . chars . next ( )
765
+ }
766
+
767
+ #[ inline]
768
+ fn size_hint ( & self ) -> ( usize , Option < usize > ) {
769
+ self . chars . size_hint ( )
770
+ }
771
+ }
772
+
773
+ impl < ' a > DoubleEndedIterator for CharDrain < ' a > {
774
+ #[ inline]
775
+ fn next_back ( & mut self ) -> Option < char > {
776
+ self . chars . next_back ( )
777
+ }
778
+ }
779
+
780
+ #[ unsafe_destructor]
781
+ impl < ' a > Drop for CharDrain < ' a > {
782
+ fn drop ( & mut self ) {
783
+ // self.start == null if drop has already been called, so we can use
784
+ // #[unsafe_no_drop_flag].
785
+ if !self . start . is_null ( ) {
786
+ unsafe { ptr:: copy ( self . start , self . end , self . tail ) ; }
787
+ }
788
+ }
673
789
}
674
790
675
791
impl FromUtf8Error {
@@ -1442,4 +1558,12 @@ mod tests {
1442
1558
r
1443
1559
} ) ;
1444
1560
}
1561
+
1562
+ #[ test]
1563
+ fn test_drain ( ) {
1564
+ let mut s = "Hello World!" . to_string ( ) ;
1565
+ let s2: String = s. drain ( 6 ..11 ) . collect ( ) ;
1566
+ assert_eq ! ( s, "Hello !" ) ;
1567
+ assert_eq ! ( s2, "World" ) ;
1568
+ }
1445
1569
}
0 commit comments