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)) => Some(second), |
59 | None => self.inner.next(), |
60 | } |
61 | } |
62 | |
63 | fn size_hint(&self) -> (usize, Option<usize>) { |
64 | size_hint::add_scalar(self.inner.size_hint(), self.additional_len()) |
65 | } |
66 | |
67 | fn fold<B, F>(self, mut init: B, mut f: F) -> B |
68 | where |
69 | F: FnMut(B, Self::Item) -> B, |
70 | { |
71 | match self.first_two { |
72 | Some(Either::Left([first, second])) => { |
73 | init = f(init, first); |
74 | init = f(init, second); |
75 | } |
76 | Some(Either::Right(second)) => init = f(init, second), |
77 | None => {} |
78 | } |
79 | self.inner.fold(init, f) |
80 | } |
81 | } |
82 | |
83 | impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {} |
84 | |
85 | impl<I> Display for ExactlyOneError<I> |
86 | where |
87 | I: Iterator, |
88 | { |
89 | fn fmt(&self, f: &mut Formatter) -> FmtResult { |
90 | let additional: usize = self.additional_len(); |
91 | if additional > 0 { |
92 | write!(f, "got at least 2 elements when exactly one was expected" ) |
93 | } else { |
94 | write!(f, "got zero elements when exactly one was expected" ) |
95 | } |
96 | } |
97 | } |
98 | |
99 | impl<I> Debug for ExactlyOneError<I> |
100 | where |
101 | I: Iterator + Debug, |
102 | I::Item: Debug, |
103 | { |
104 | fn fmt(&self, f: &mut Formatter) -> FmtResult { |
105 | let mut dbg: DebugStruct<'_, '_> = f.debug_struct(name:"ExactlyOneError" ); |
106 | match &self.first_two { |
107 | Some(Either::Left([first: &::Item, second: &::Item])) => { |
108 | dbg.field("first" , first).field(name:"second" , value:second); |
109 | } |
110 | Some(Either::Right(second: &::Item)) => { |
111 | dbg.field(name:"second" , value:second); |
112 | } |
113 | None => {} |
114 | } |
115 | dbg.field(name:"inner" , &self.inner).finish() |
116 | } |
117 | } |
118 | |
119 | #[cfg (feature = "use_std" )] |
120 | impl<I> Error for ExactlyOneError<I> |
121 | where |
122 | I: Iterator + Debug, |
123 | I::Item: Debug, |
124 | { |
125 | } |
126 | |