Skip to main content

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`
12/// [`exactly_one()`](crate::Itertools::exactly_one) and
13/// [`at_most_one()`](crate::Itertools::at_most_one).
14/// This iterator yields exactly the same elements as the input iterator.
15///
16/// During the execution of `exactly_one` the iterator must be mutated.  This wrapper
17/// effectively "restores" the state of the input iterator when it's handed back.
18///
19/// This is very similar to `PutBackN` except this iterator only supports 0-2 elements and does not
20/// use a `Vec`.
21#[derive(Clone)]
22pub struct ExactlyOneError<I>
23where
24    I: Iterator,
25{
26    first_two: Option<Either<[I::Item; 2], I::Item>>,
27    inner: I,
28}
29
30impl<I> ExactlyOneError<I>
31where
32    I: Iterator,
33{
34    /// Creates a new `ExactlyOneErr` iterator.
35    pub(crate) fn new(first_two: Option<Either<[I::Item; 2], I::Item>>, inner: I) -> Self {
36        Self { first_two, inner }
37    }
38
39    fn additional_len(&self) -> usize {
40        match self.first_two {
41            Some(Either::Left(_)) => 2,
42            Some(Either::Right(_)) => 1,
43            None => 0,
44        }
45    }
46}
47
48impl<I> Iterator for ExactlyOneError<I>
49where
50    I: Iterator,
51{
52    type Item = I::Item;
53
54    fn next(&mut self) -> Option<Self::Item> {
55        match self.first_two.take() {
56            Some(Either::Left([first, second])) => {
57                self.first_two = Some(Either::Right(second));
58                Some(first)
59            }
60            Some(Either::Right(second)) => Some(second),
61            None => self.inner.next(),
62        }
63    }
64
65    fn size_hint(&self) -> (usize, Option<usize>) {
66        size_hint::add_scalar(self.inner.size_hint(), self.additional_len())
67    }
68
69    fn count(self) -> usize
70    where
71        Self: Sized,
72    {
73        self.additional_len() + self.inner.count()
74    }
75
76    fn fold<B, F>(self, mut init: B, mut f: F) -> B
77    where
78        F: FnMut(B, Self::Item) -> B,
79    {
80        match self.first_two {
81            Some(Either::Left([first, second])) => {
82                init = f(init, first);
83                init = f(init, second);
84            }
85            Some(Either::Right(second)) => init = f(init, second),
86            None => {}
87        }
88        self.inner.fold(init, f)
89    }
90}
91
92impl<I> ExactSizeIterator for ExactlyOneError<I> where I: ExactSizeIterator {}
93
94impl<I> Display for ExactlyOneError<I>
95where
96    I: Iterator,
97{
98    fn fmt(&self, f: &mut Formatter) -> FmtResult {
99        let additional = self.additional_len();
100        if additional > 0 {
101            write!(f, "got at least 2 elements when exactly one was expected")
102        } else {
103            write!(f, "got zero elements when exactly one was expected")
104        }
105    }
106}
107
108impl<I> Debug for ExactlyOneError<I>
109where
110    I: Iterator + Debug,
111    I::Item: Debug,
112{
113    fn fmt(&self, f: &mut Formatter) -> FmtResult {
114        let mut dbg = f.debug_struct("ExactlyOneError");
115        match &self.first_two {
116            Some(Either::Left([first, second])) => {
117                dbg.field("first", first).field("second", second);
118            }
119            Some(Either::Right(second)) => {
120                dbg.field("second", second);
121            }
122            None => {}
123        }
124        dbg.field("inner", &self.inner).finish()
125    }
126}
127
128#[cfg(feature = "use_std")]
129impl<I> Error for ExactlyOneError<I>
130where
131    I: Iterator + Debug,
132    I::Item: Debug,
133{
134}