Skip to content

Commit 2c6536a

Browse files
author
Julian Orth
committed
Implement drain RFC
Closes #23055 [breaking-change]
1 parent 68740b4 commit 2c6536a

File tree

5 files changed

+270
-57
lines changed

5 files changed

+270
-57
lines changed

src/libcollections/binary_heap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,8 @@ impl<T: Ord> BinaryHeap<T> {
553553
#[inline]
554554
#[unstable(feature = "collections",
555555
reason = "matches collection reform specification, waiting for dust to settle")]
556-
pub fn drain(&mut self) -> Drain<T> {
557-
Drain { iter: self.data.drain() }
556+
pub fn drain<'a>(&'a mut self) -> Drain<'a, T> {
557+
Drain { iter: self.data.drain(..) }
558558
}
559559

560560
/// Drops all items from the binary heap.

src/libcollections/string.rs

Lines changed: 126 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,14 @@ use core::fmt;
2222
use core::hash;
2323
use core::iter::{IntoIterator, FromIterator};
2424
use core::mem;
25-
use core::ops::{self, Deref, Add, Index};
25+
use core::ops::{self, Deref, Add, Index, Range, RangeTo, RangeFrom, RangeFull};
2626
use core::ptr;
2727
use core::raw::Slice as RawSlice;
2828
use unicode::str as unicode_str;
2929
use unicode::str::Utf16Item;
3030

3131
use borrow::{Cow, IntoCow};
32-
use str::{self, CharRange, FromStr, Utf8Error};
32+
use str::{self, CharRange, FromStr, Utf8Error, Chars};
3333
use 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

675791
impl 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

Comments
 (0)