1use core::iter::{Chain, Once, once};
4
5#[derive(Clone, Debug)]
16pub struct NonEmpty<I: Iterator> {
17 first: I::Item,
18 rest: I,
19}
20
21impl<I: Iterator> NonEmpty<I> {
22 pub const fn new(first: I::Item, rest: I) -> Self {
24 Self { first, rest }
25 }
26
27 pub fn try_new(mut items: I) -> Option<Self> {
29 let first = items.next()?;
30 Some(Self::new(first, items))
31 }
32
33 pub fn into_parts(self) -> (I::Item, I) {
35 (self.first, self.rest)
36 }
37}
38
39impl<I: Iterator> IntoIterator for NonEmpty<I> {
40 type Item = I::Item;
41 type IntoIter = Chain<Once<I::Item>, I>;
42
43 fn into_iter(self) -> Self::IntoIter {
44 once(self.first).chain(self.rest)
45 }
46}
47
48#[cfg(not(any(
72 commonware_stability_GAMMA,
73 commonware_stability_DELTA,
74 commonware_stability_EPSILON,
75 commonware_stability_RESERVED
76)))] #[macro_export]
78macro_rules! non_empty {
79 (@$items:expr) => {{
80 $crate::iter::NonEmpty::try_new(::core::iter::IntoIterator::into_iter($items))
81 .expect("iterator must be non-empty")
82 }};
83 ($first:expr $(, $rest:expr)* $(,)?) => {
84 $crate::iter::NonEmpty::new(
85 $first,
86 ::core::iter::IntoIterator::into_iter([$($rest),*]),
87 )
88 };
89}
90
91pub fn zip_eq<A: IntoIterator, B: IntoIterator>(a: A, b: B) -> ZipEq<A::IntoIter, B::IntoIter> {
105 ZipEq {
106 a: a.into_iter(),
107 b: b.into_iter(),
108 }
109}
110
111#[derive(Clone, Debug)]
113pub struct ZipEq<A, B> {
114 a: A,
115 b: B,
116}
117
118impl<A: Iterator, B: Iterator> Iterator for ZipEq<A, B> {
119 type Item = (A::Item, B::Item);
120
121 fn next(&mut self) -> Option<Self::Item> {
122 match (self.a.next(), self.b.next()) {
123 (Some(a), Some(b)) => Some((a, b)),
124 (None, None) => None,
125 (Some(_), None) => panic!("zip_eq: right iterator exhausted first"),
126 (None, Some(_)) => panic!("zip_eq: left iterator exhausted first"),
127 }
128 }
129
130 fn size_hint(&self) -> (usize, Option<usize>) {
131 let (a_low, a_high) = self.a.size_hint();
132 let (b_low, b_high) = self.b.size_hint();
133 let high = match (a_high, b_high) {
134 (Some(a), Some(b)) => Some(a.min(b)),
135 (Some(a), None) => Some(a),
136 (None, Some(b)) => Some(b),
137 (None, None) => None,
138 };
139 (a_low.min(b_low), high)
140 }
141}
142
143impl<A: ExactSizeIterator, B: ExactSizeIterator> ExactSizeIterator for ZipEq<A, B> {}
144
145#[cfg(test)]
146mod tests {
147 use super::{NonEmpty, zip_eq};
148
149 #[test]
150 fn try_new_rejects_empty() {
151 assert!(NonEmpty::try_new(core::iter::empty::<u8>()).is_none());
152 }
153
154 #[test]
155 fn iteration_preserves_every_item() {
156 let items = NonEmpty::try_new([1, 2, 3].into_iter()).expect("items are non-empty");
157 assert_eq!(items.into_iter().collect::<Vec<_>>(), vec![1, 2, 3]);
158 }
159
160 #[test]
161 fn into_parts_separates_first_from_rest() {
162 let items = NonEmpty::new(1, [2, 3].into_iter());
163 let (first, rest) = items.into_parts();
164
165 assert_eq!(first, 1);
166 assert_eq!(rest.collect::<Vec<_>>(), vec![2, 3]);
167 }
168
169 #[test]
170 fn macro_constructs_non_empty_iterators() {
171 assert_eq!(non_empty![1].into_iter().collect::<Vec<_>>(), vec![1]);
172 assert_eq!(
173 non_empty![1, 2, 3].into_iter().collect::<Vec<_>>(),
174 vec![1, 2, 3]
175 );
176 assert_eq!(
177 non_empty![@1..4].into_iter().collect::<Vec<_>>(),
178 vec![1, 2, 3]
179 );
180 }
181
182 #[test]
183 fn zip_eq_pairs_equal_lengths() {
184 let pairs: Vec<_> = zip_eq([1, 2, 3], ["a", "b", "c"]).collect();
185
186 assert_eq!(pairs, vec![(1, "a"), (2, "b"), (3, "c")]);
187 }
188
189 #[test]
190 #[should_panic(expected = "right iterator exhausted first")]
191 fn zip_eq_panics_when_right_is_shorter() {
192 zip_eq([1, 2], [1]).count();
193 }
194
195 #[test]
196 #[should_panic(expected = "left iterator exhausted first")]
197 fn zip_eq_panics_when_left_is_shorter() {
198 zip_eq([1], [1, 2]).count();
199 }
200
201 #[test]
202 #[should_panic(expected = "iterator must be non-empty")]
203 fn macro_rejects_empty_iterators() {
204 let _ = non_empty![@core::iter::empty::<u8>()];
205 }
206
207 mod colliding_method {
208 trait CollidingIntoIterator {
209 fn into_iter(self);
210 }
211
212 impl<T, const N: usize> CollidingIntoIterator for [T; N] {
213 fn into_iter(self) {}
214 }
215
216 #[test]
217 fn macro_ignores_colliding_into_iterator_methods() {
218 CollidingIntoIterator::into_iter([0]);
219
220 assert_eq!(
221 non_empty![1, 2, 3].into_iter().collect::<Vec<_>>(),
222 vec![1, 2, 3]
223 );
224 assert_eq!(
225 non_empty![@[1, 2, 3]].into_iter().collect::<Vec<_>>(),
226 vec![1, 2, 3]
227 );
228 }
229 }
230}