diff --git a/src/exactly_one_err.rs b/src/exactly_one_err.rs index 6e79f99fd..84d479dd1 100644 --- a/src/exactly_one_err.rs +++ b/src/exactly_one_err.rs @@ -2,7 +2,7 @@ use std::error::Error; use std::fmt::{Debug, Display, Formatter, Result as FmtResult}; -use std::iter::ExactSizeIterator; +use std::iter::{ExactSizeIterator, Fuse}; use either::Either; @@ -24,7 +24,7 @@ where I: Iterator, { first_two: Option>, - inner: I, + inner: Fuse, } impl ExactlyOneError @@ -33,7 +33,10 @@ where { /// Creates a new `ExactlyOneErr` iterator. pub(crate) fn new(first_two: Option>, inner: I) -> Self { - Self { first_two, inner } + Self { + first_two, + inner: inner.fuse(), + } } fn additional_len(&self) -> usize { @@ -91,6 +94,22 @@ where impl ExactSizeIterator for ExactlyOneError where I: ExactSizeIterator {} +impl DoubleEndedIterator for ExactlyOneError { + fn next_back(&mut self) -> Option { + if let Some(next) = self.inner.next_back() { + return Some(next); + }; + match self.first_two.take() { + Some(Either::Left([first, second])) => { + self.first_two = Some(Either::Right(first)); + Some(second) + } + Some(Either::Right(second)) => Some(second), + None => None, + } + } +} + impl Display for ExactlyOneError where I: Iterator, diff --git a/tests/quick.rs b/tests/quick.rs index 538346bb9..9c1352a29 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -1512,6 +1512,16 @@ quickcheck! { } } +quickcheck! { + fn exactly_one_double_ended(a: Vec) -> TestResult { + let ret = a.iter().copied().exactly_one(); + match a.len() { + 1 => TestResult::passed(), + _ => TestResult::from_bool(a.iter().rev().copied().eq(ret.unwrap_err().rev())), + } + } +} + quickcheck! { fn at_most_one_i32(a: Vec) -> TestResult { let ret = a.iter().cloned().at_most_one();