diff --git a/src/exactly_one_err.rs b/src/exactly_one_err.rs index e951d4106..d780f1455 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; @@ -22,7 +22,7 @@ where I: Iterator, { first_two: Option>, - inner: I, + inner: Fuse, } impl ExactlyOneError @@ -31,7 +31,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 { @@ -89,6 +92,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 674848512..bccf0c653 100644 --- a/tests/quick.rs +++ b/tests/quick.rs @@ -1400,6 +1400,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();