1#[cfg(feature = "use_std")]
2use std::error::Error;
3use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
4
5use std::iter::ExactSizeIterator;
6
7use either::Either;
8
9use 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)]
20pub struct ExactlyOneError<I>
21where
22 I: Iterator,
23{
24 first_two: Option<Either<[I::Item; 2], I::Item>>,
25 inner: I,
26}
27
28impl<I> ExactlyOneError<I>
29where
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
46impl<I> Iterator for ExactlyOneError<I>
47where
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
83impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
84
85impl<I> Display for ExactlyOneError<I>
86where
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
99impl<I> Debug for ExactlyOneError<I>
100where
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")]
120impl<I> Error for ExactlyOneError<I>
121where
122 I: Iterator + Debug,
123 I::Item: Debug,
124{
125}
126