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}