drain_while/lib.rs
1/*!
2This library provides a draining `Iterator` which stops when a predicate becomes false.
3
4```
5use drain_while::*;
6
7let mut original = vec![1,2,3,4,5];
8let mut matching = vec![];
9
10for x in original.drain_while(|x| *x < 3) {
11 matching.push(x);
12}
13
14assert_eq!(matching, vec![1,2]);
15assert_eq!(original, vec![3,4,5]);
16```
17
18See the documentation for [`drain_while()`](trait.DrainWhileable.html#tymethod.drain_while) for
19more.
20*/
21
22use std::vec::Drain;
23
24pub trait DrainWhileable<T> {
25 /// Take the elements of a vector, left-to-right, stopping at the first non-matching element.
26 ///
27 /// The returned `DrainWhile` iterates over the longest prefex in which all elements satisfy
28 /// `pred`; when the iterator is dropped, the prefix is removed from `vec`.
29 ///
30 /// ```
31 /// # use drain_while::*;
32 /// let mut orig: Vec<usize> = vec![0,1,2,3,4,5];
33 /// let none: Vec<usize> = orig.drain_while(|_| false).collect();
34 /// let some: Vec<usize> = orig.drain_while(|x| *x < 3).collect();
35 /// let rest: Vec<usize> = orig.drain_while(|_| true).collect();
36 ///
37 /// assert_eq!(none, vec![]);
38 /// assert_eq!(some, vec![0,1,2]);
39 /// assert_eq!(rest, vec![3,4,5]);
40 /// assert_eq!(orig, vec![]);
41 /// ```
42 ///
43 /// The behaviour of `drain_while()` differs from `drain().take_while()` in the final state of
44 /// the original vector, as illustrated here:
45 ///
46 /// ```
47 /// # use drain_while::*;
48 /// let mut v1 = vec![1,2,3,4,5];
49 /// let mut v2 = vec![1,2,3,4,5];
50 /// v1.drain(..).take_while(|x| *x < 3);
51 /// v2.drain_while(|x| *x < 3);
52 /// assert_eq!(v1, vec![]);
53 /// assert_eq!(v2, vec![3,4,5]);
54 /// ```
55 ///
56 /// The same caveats which apply to `drain` also apply to `drain_while`:
57 ///
58 /// 1. The element range is removed even if the iterator is only partially consumed or not
59 /// consumed at all.
60 /// 2. It is unspecified how many elements are removed from the vector, if the `DrainWhile`
61 /// value is leaked.
62 ///
63 /// The current implementation is fairly naive, but I believe there's scope for speeding it up
64 /// substantially.
65 fn drain_while<P>(&mut self, pred: P) -> DrainWhile<T> where P: Fn(&T) -> bool;
66}
67
68/// A draining iterator for `Vec<T>`.
69///
70/// See [`Vec::drain_while`](trait.DrainWhileable.html#tymethod.drain_while) for more.
71//
72// Just a newtype to allow changing the implementation later.
73pub struct DrainWhile<'a, T: 'a>(Drain<'a, T>);
74impl<'a, T> Iterator for DrainWhile<'a, T> {
75 type Item = T;
76 fn next(&mut self) -> Option<T> { self.0.next() }
77}
78
79impl<T> DrainWhileable<T> for Vec<T> {
80 // TODO: Surely this can be implemented more efficiently, but it may not be worth the effort...
81 fn drain_while<P>(&mut self, mut pred: P) -> DrainWhile<T> where P: FnMut(&T) -> bool {
82 // This is purely a performance optimisation for the 0-matching case.
83 let some_match = match self.first() {
84 Some(x) => pred(x),
85 _ => false
86 };
87 if some_match {
88 match self.iter().position(|x| !pred(x)) {
89 None => /* they all matched pred */ DrainWhile(self.drain(..)),
90 Some(i) => /* they matched until i */ DrainWhile(self.drain(..i)),
91 }
92 } else {
93 /* none of them matched */ DrainWhile(self.drain(0..0))
94 }
95 }
96}