itertools/
exactly_one_err.rs

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 = 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 = f.debug_struct("ExactlyOneError");
106        match &self.first_two {
107            Some(Either::Left([first, second])) => {
108                dbg.field("first", first).field("second", second);
109            }
110            Some(Either::Right(second)) => {
111                dbg.field("second", second);
112            }
113            None => {}
114        }
115        dbg.field("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}