@@ -22,14 +22,14 @@ use core::fmt;
2222use core:: hash;
2323use core:: iter:: { IntoIterator , FromIterator } ;
2424use core:: mem;
25- use core:: ops:: { self , Deref , Add , Index } ;
25+ use core:: ops:: { self , Deref , Add , Index , Range , RangeTo , RangeFrom , RangeFull } ;
2626use core:: ptr;
2727use core:: raw:: Slice as RawSlice ;
2828use unicode:: str as unicode_str;
2929use unicode:: str:: Utf16Item ;
3030
3131use borrow:: { Cow , IntoCow } ;
32- use str:: { self , CharRange , FromStr , Utf8Error } ;
32+ use str:: { self , CharRange , FromStr , Utf8Error , Chars } ;
3333use vec:: { DerefVec , Vec , as_vec} ;
3434
3535/// A growable string stored as a UTF-8 encoded buffer.
@@ -670,6 +670,122 @@ impl String {
670670 pub fn clear ( & mut self ) {
671671 self . vec . clear ( )
672672 }
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+ }
673789}
674790
675791impl FromUtf8Error {
@@ -1442,4 +1558,12 @@ mod tests {
14421558 r
14431559 } ) ;
14441560 }
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+ }
14451569}
0 commit comments