Skip to main content

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}