exotic_iter/
lib.rs

1mod alternate;
2
3pub use alternate::*;
4
5/// Provides additional convenience methods to the `Iterator` trait and its implementors.
6pub trait ExoticIteratorExt: Iterator + Sized {
7    /// Consumes the iterator, counting the number of items that pass the predicate and returns true iff there were at least `n` passing items.
8    /// 
9    /// # Example
10    /// ```rust
11    /// use exotic_iter::*;
12    /// let very_few_twos = vec![1, 2, 3, 4, 5, 6];
13    /// let lots_of_twos = vec![2, 3, 2, 4, 2, 5];
14    /// assert_eq!(false, very_few_twos.into_iter().at_least(3_usize, |n| *n == 2));
15    /// assert_eq!(true, lots_of_twos.into_iter().at_least(3_usize, |n| *n == 2));
16    /// ```
17    fn at_least<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool;
18
19    /// Consumes the iterator, counting the number of items that pass the predicate and returns true iff there were no more than `n` passing items.
20    ///
21    /// # Example
22    /// ```rust
23    /// use exotic_iter::*;
24    /// let just_enough_twos = vec![1, 1, 2, 2, 3, 3];
25    /// let too_many_twos = vec![2, 2, 2, 2, 2, 2];
26    /// assert_eq!(true, just_enough_twos.into_iter().at_most(2_usize, |n| *n == 2));
27    /// assert_eq!(false, too_many_twos.into_iter().at_most(2_usize, |n| *n == 2));
28    /// ```
29    fn at_most<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool;
30
31    /// Consumes the iterator, counting the number of items that pass the predicate and returns true iff there were exactly `n` passing items.
32    ///
33    /// # Example
34    /// ```rust
35    /// use exotic_iter::*;
36    /// let no_digits = "deadbeef";
37    /// let two_digits = "deadb33f";
38    /// let three_digits = "d3adb33f";
39    /// assert_eq!(false, no_digits.chars().exactly_n(2_usize, |c| c.is_ascii_digit()));
40    /// assert_eq!(true, two_digits.chars().exactly_n(2_usize, |c| c.is_ascii_digit()));
41    /// assert_eq!(false, three_digits.chars().exactly_n(2_usize, |c| c.is_ascii_digit()));
42    /// ```
43    fn exactly_n<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool;
44
45    /// Consumes the iterator, counting the number of items that pass each predicate and returns true iff 
46    /// there were exactly `m` passing items for the `predicate_m`, and exactly `n` passing items for `predicate_n`. 
47    ///
48    /// # Example
49    /// ```rust
50    /// use exotic_iter::*;
51    /// let more_digits = "abc12345";
52    /// let balanced_digits = "abcd1234";
53    /// let more_letters = "abcde123";
54    /// assert_eq!(false, more_digits.chars().exactly_m_n(4_usize, |c| c.is_ascii_alphabetic(), 4_usize, |c| c.is_ascii_digit()));
55    /// assert_eq!(true, balanced_digits.chars().exactly_m_n(4_usize, |c| c.is_ascii_alphabetic(), 4_usize, |c| c.is_ascii_digit()));
56    /// assert_eq!(false, more_letters.chars().exactly_m_n(4_usize, |c| c.is_ascii_alphabetic(), 4_usize, |c| c.is_ascii_digit()));
57    /// ```
58    fn exactly_m_n<Pm: FnMut(&Self::Item) -> bool, Pn: FnMut(&Self::Item) -> bool>(self, m: usize, predicate_m: Pm, n: usize, predicate_n: Pn) -> bool;
59
60    /// Consumes the iterator and returns true iff either all of the items in the iterator passed the predicate, or none of them passed.
61    /// Returns early on the first mixed result.
62    ///
63    /// # Example
64    /// ```rust
65    /// use exotic_iter::*;
66    /// let all_true = vec![true, true, true];
67    /// let some_true = vec![true, false, true];
68    /// let none_true = vec![false, false, false];
69    /// assert_eq!(true, all_true.into_iter().all_or_none(|b| *b));
70    /// assert_eq!(false, some_true.into_iter().all_or_none(|b| *b));
71    /// assert_eq!(true, none_true.into_iter().all_or_none(|b| *b));
72    /// ```
73    fn all_or_none<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> bool;
74
75    /// Consumes the iterator and returns true if exactly half of the items passed the predicate; as all things should be.
76    ///
77    /// # Example
78    /// ```rust
79    /// use exotic_iter::*;
80    /// let two_even = vec![1, 2, 3, 4];
81    /// let three_even = vec![1, 2, 4, 6];
82    /// assert_eq!(true, two_even.into_iter().perfectly_balanced(|n| *n % 2 == 0));
83    /// assert_eq!(false, three_even.into_iter().perfectly_balanced(|n| *n % 2 == 0));
84    /// ```
85    fn perfectly_balanced<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> bool;
86
87    /// Creates an iterator that alternates between items from `self` and `other`, with `self` providing the first value.
88    /// Short-circuits at the first `None` returned, even if one of the iterators still has values left.
89    ///
90    /// # Example
91    /// ```rust
92    /// use exotic_iter::*;
93    /// let odd_numbers = vec![1, 3];
94    /// let even_numbers = vec![2, 4];
95    /// let mut iter = odd_numbers.iter().alternate(even_numbers.iter());
96    /// assert_eq!(Some(&1), iter.next());
97    /// assert_eq!(Some(&2), iter.next());
98    /// assert_eq!(Some(&3), iter.next());
99    /// assert_eq!(Some(&4), iter.next());
100    /// assert_eq!(None, iter.next());
101    /// ```
102    fn alternate<U: IntoIterator<Item = Self::Item>>(self, other: U) -> Alternate<Self, U::IntoIter>;
103}
104
105impl<T: Iterator> ExoticIteratorExt for T {    
106    #[inline]
107    fn at_least<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool {
108        self.filter(predicate).take(n).count() == n
109    }
110    
111    #[inline]
112    fn at_most<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool {
113        self.filter(predicate).skip(n).count() == 0
114    }
115    
116    fn exactly_n<P: FnMut(&Self::Item) -> bool>(self, n: usize, predicate: P) -> bool {
117        let mut predicate = predicate;
118        let mut count: usize = 0;
119        for item in self {
120            if predicate(&item) {
121                count += 1;
122            }
123            if count > n {
124                return false
125            }
126        }
127        count == n
128    }
129    
130    fn exactly_m_n<
131        Pm: FnMut(&Self::Item) -> bool, 
132        Pn: FnMut(&Self::Item) -> bool,
133    >(self, m: usize, predicate_m: Pm, n: usize, predicate_n: Pn) -> bool {
134        let mut predicate_m = predicate_m;
135        let mut predicate_n = predicate_n;
136        let mut count_m: usize = 0;
137        let mut count_n: usize = 0;
138        for item in self {
139            if predicate_m(&item) {
140                count_m += 1;
141            }
142            if predicate_n(&item) {
143                count_n += 1;
144            }
145            if count_m > m || count_n > n {
146                return false
147            }
148        }
149        (count_m, count_n) == (m, n)
150    }
151    
152    fn perfectly_balanced<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> bool {
153        let mut predicate = predicate;
154        let mut count: usize = 0;
155        let mut total: usize = 0;
156        for item in self {
157            total += 1;
158            if predicate(&item) {
159                count += 1;
160            }
161        }
162        total % 2 == 0 && total / 2 == count
163    }
164    
165    fn all_or_none<P: FnMut(&Self::Item) -> bool>(self, predicate: P) -> bool {
166        let mut predicate = predicate;
167        let mut has_pass = false;
168        let mut has_fail = false;
169        for item in self {
170            if predicate(&item) {
171                has_pass = true;
172            } else {
173                has_fail = true;
174            }
175            if has_pass && has_fail {
176                return false
177            }
178        }
179        true
180    }
181
182    fn alternate<U: IntoIterator<Item = Self::Item>>(self, other: U) -> Alternate<Self, <U as IntoIterator>::IntoIter> {
183        Alternate::new(self, other.into_iter())
184    }
185}