]>
Commit | Line | Data |
---|---|---|
f20569fa XL |
1 | use std::iter::ExactSizeIterator; |
2 | ||
3 | use size_hint; | |
4 | ||
5 | /// Iterator returned for the error case of `IterTools::exactly_one()` | |
6 | /// This iterator yields exactly the same elements as the input iterator. | |
7 | /// | |
8 | /// During the execution of exactly_one the iterator must be mutated. This wrapper | |
9 | /// effectively "restores" the state of the input iterator when it's handed back. | |
10 | /// | |
11 | /// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not | |
12 | /// use a `Vec`. | |
13 | #[derive(Debug, Clone)] | |
14 | pub struct ExactlyOneError<I> | |
15 | where | |
16 | I: Iterator, | |
17 | { | |
18 | first_two: (Option<I::Item>, Option<I::Item>), | |
19 | inner: I, | |
20 | } | |
21 | ||
22 | impl<I> ExactlyOneError<I> | |
23 | where | |
24 | I: Iterator, | |
25 | { | |
26 | /// Creates a new `ExactlyOneErr` iterator. | |
27 | pub(crate) fn new(first_two: (Option<I::Item>, Option<I::Item>), inner: I) -> Self { | |
28 | Self { first_two, inner } | |
29 | } | |
30 | } | |
31 | ||
32 | impl<I> Iterator for ExactlyOneError<I> | |
33 | where | |
34 | I: Iterator, | |
35 | { | |
36 | type Item = I::Item; | |
37 | ||
38 | fn next(&mut self) -> Option<Self::Item> { | |
39 | self.first_two | |
40 | .0 | |
41 | .take() | |
42 | .or_else(|| self.first_two.1.take()) | |
43 | .or_else(|| self.inner.next()) | |
44 | } | |
45 | ||
46 | fn size_hint(&self) -> (usize, Option<usize>) { | |
47 | let mut additional_len = 0; | |
48 | if self.first_two.0.is_some() { | |
49 | additional_len += 1; | |
50 | } | |
51 | if self.first_two.1.is_some() { | |
52 | additional_len += 1; | |
53 | } | |
54 | size_hint::add_scalar(self.inner.size_hint(), additional_len) | |
55 | } | |
56 | } | |
57 | ||
58 | impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {} |