1 | #[cfg (feature = "use_std" )] |
2 | use std::error::Error; |
3 | use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; |
4 | |
5 | use std::iter::ExactSizeIterator; |
6 | |
7 | use either::Either; |
8 | |
9 | use crate::size_hint; |
10 | |
11 | /// Iterator returned for the error case of `IterTools::exactly_one()` |
12 | /// This iterator yields exactly the same elements as the input iterator. |
13 | /// |
14 | /// During the execution of `exactly_one` the iterator must be mutated. This wrapper |
15 | /// effectively "restores" the state of the input iterator when it's handed back. |
16 | /// |
17 | /// This is very similar to `PutBackN` except this iterator only supports 0-2 elements and does not |
18 | /// use a `Vec`. |
19 | #[derive(Clone)] |
20 | pub struct ExactlyOneError<I> |
21 | where |
22 | I: Iterator, |
23 | { |
24 | first_two: Option<Either<[I::Item; 2], I::Item>>, |
25 | inner: I, |
26 | } |
27 | |
28 | impl<I> ExactlyOneError<I> |
29 | where |
30 | I: Iterator, |
31 | { |
32 | /// Creates a new `ExactlyOneErr` iterator. |
33 | pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self { |
34 | Self { first_two, inner } |
35 | } |
36 | |
37 | fn additional_len(&self) -> usize { |
38 | match self.first_two { |
39 | Some(Either::Left(_)) => 2, |
40 | Some(Either::Right(_)) => 1, |
41 | None => 0, |
42 | } |
43 | } |
44 | } |
45 | |
46 | impl<I> Iterator for ExactlyOneError<I> |
47 | where |
48 | I: Iterator, |
49 | { |
50 | type Item = I::Item; |
51 | |
52 | fn next(&mut self) -> Option<Self::Item> { |
53 | match self.first_two.take() { |
54 | Some(Either::Left([first, second])) => { |
55 | self.first_two = Some(Either::Right(second)); |
56 | Some(first) |
57 | }, |
58 | Some(Either::Right(second)) => { |
59 | Some(second) |
60 | } |
61 | None => { |
62 | self.inner.next() |
63 | } |
64 | } |
65 | } |
66 | |
67 | fn size_hint(&self) -> (usize, Option<usize>) { |
68 | size_hint::add_scalar(self.inner.size_hint(), self.additional_len()) |
69 | } |
70 | } |
71 | |
72 | |
73 | impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {} |
74 | |
75 | impl<I> Display for ExactlyOneError<I> |
76 | where I: Iterator, |
77 | { |
78 | fn fmt(&self, f: &mut Formatter) -> FmtResult { |
79 | let additional = self.additional_len(); |
80 | if additional > 0 { |
81 | write!(f, "got at least 2 elements when exactly one was expected" ) |
82 | } else { |
83 | write!(f, "got zero elements when exactly one was expected" ) |
84 | } |
85 | } |
86 | } |
87 | |
88 | impl<I> Debug for ExactlyOneError<I> |
89 | where I: Iterator + Debug, |
90 | I::Item: Debug, |
91 | { |
92 | fn fmt(&self, f: &mut Formatter) -> FmtResult { |
93 | match &self.first_two { |
94 | Some(Either::Left([first, second])) => { |
95 | write!(f, "ExactlyOneError[First: {:?}, Second: {:?}, RemainingIter: {:?}]" , first, second, self.inner) |
96 | }, |
97 | Some(Either::Right(second)) => { |
98 | write!(f, "ExactlyOneError[Second: {:?}, RemainingIter: {:?}]" , second, self.inner) |
99 | } |
100 | None => { |
101 | write!(f, "ExactlyOneError[RemainingIter: {:?}]" , self.inner) |
102 | } |
103 | } |
104 | } |
105 | } |
106 | |
107 | #[cfg (feature = "use_std" )] |
108 | impl<I> Error for ExactlyOneError<I> where I: Iterator + Debug, I::Item: Debug, {} |
109 | |
110 | |
111 | |