use core::iter::FusedIterator;
use crate::EitherOrBoth;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ChainedIterEitherOrBoth<T>(EitherOrBoth<T, T>);
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct IntoIterEitherOrBoth<T>(Items<T>);
#[derive(Debug, Clone, PartialEq, Eq)]
struct Items<T> {
inner: EitherOrBoth<Option<T>>,
}
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct IterEitherOrBoth<'a, T>(Items<&'a T>);
#[derive(Debug, Default, PartialEq, Eq)]
pub struct IterMutEitherOrBoth<'a, T>(Items<&'a mut T>);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SwapIterEitherOrBoth<L, R>(EitherOrBoth<L, R>);
impl<T> ChainedIterEitherOrBoth<T> {
#[inline]
pub(crate) const fn new(either_or_both: EitherOrBoth<T, T>) -> Self {
Self(either_or_both)
}
}
impl<T> Default for ChainedIterEitherOrBoth<T>
where
T: Default,
{
#[inline]
fn default() -> Self {
Self(EitherOrBoth::Left(T::default()))
}
}
impl<T> DoubleEndedIterator for ChainedIterEitherOrBoth<T>
where
T: DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self.0.as_mut() {
EitherOrBoth::Both(left, right) => right.next_back().or_else(|| left.next_back()),
EitherOrBoth::Left(side) | EitherOrBoth::Right(side) => side.next_back(),
}
}
}
impl<T> FusedIterator for ChainedIterEitherOrBoth<T> where T: FusedIterator {}
impl<T> Iterator for ChainedIterEitherOrBoth<T>
where
T: Iterator,
{
type Item = T::Item;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.0.as_mut() {
EitherOrBoth::Both(left, right) => left.next().or_else(|| right.next()),
EitherOrBoth::Left(iter) | EitherOrBoth::Right(iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0
.as_ref()
.map(Iterator::size_hint)
.reduce(|(l_lower, l_upper), (r_lower, r_upper)| {
(
l_lower.saturating_add(r_lower),
l_upper.and_then(|l| r_upper.and_then(|r| l.checked_add(r))),
)
})
}
}
impl<T> IntoIterEitherOrBoth<T> {
#[inline]
pub(crate) fn new(either_or_both: EitherOrBoth<T, T>) -> Self {
Self(either_or_both.into())
}
}
impl<T> DoubleEndedIterator for IntoIterEitherOrBoth<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<T> ExactSizeIterator for IntoIterEitherOrBoth<T> {}
impl<T> FusedIterator for IntoIterEitherOrBoth<T> {}
impl<T> Iterator for IntoIterEitherOrBoth<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<T> From<EitherOrBoth<T>> for Items<T> {
#[inline]
fn from(value: EitherOrBoth<T>) -> Self {
Self {
inner: value.map(Some),
}
}
}
impl<T> Default for Items<T> {
#[inline]
fn default() -> Self {
Self {
inner: EitherOrBoth::Left(None),
}
}
}
impl<T> DoubleEndedIterator for Items<T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self.inner.as_mut() {
EitherOrBoth::Both(_, right) | EitherOrBoth::Right(right) if right.is_some() => {
right.take()
}
EitherOrBoth::Both(left, None) | EitherOrBoth::Left(left) if left.is_some() => {
left.take()
}
_ => None,
}
}
}
impl<T> ExactSizeIterator for Items<T> {}
impl<T> FusedIterator for Items<T> {}
impl<T> Iterator for Items<T> {
type Item = T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.inner.as_mut() {
EitherOrBoth::Both(left, _) | EitherOrBoth::Left(left) if left.is_some() => left.take(),
EitherOrBoth::Both(None, right) | EitherOrBoth::Right(right) if right.is_some() => {
right.take()
}
_ => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match &self.inner {
EitherOrBoth::Both(Some(_), Some(_)) => (2, Some(2)),
EitherOrBoth::Left(Some(_))
| EitherOrBoth::Right(Some(_))
| EitherOrBoth::Both(None, Some(_))
| EitherOrBoth::Both(Some(_), None) => (1, Some(1)),
_ => (0, Some(0)),
}
}
}
impl<'a, T> IterEitherOrBoth<'a, T> {
#[inline]
pub(crate) fn new(either_or_both: &'a EitherOrBoth<T>) -> Self {
Self(either_or_both.as_ref().into())
}
}
impl<T> DoubleEndedIterator for IterEitherOrBoth<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<T> ExactSizeIterator for IterEitherOrBoth<'_, T> {}
impl<T> FusedIterator for IterEitherOrBoth<'_, T> {}
impl<'a, T> Iterator for IterEitherOrBoth<'a, T> {
type Item = &'a T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<'a, T> IterMutEitherOrBoth<'a, T> {
#[inline]
pub(crate) fn new(either_or_both: &'a mut EitherOrBoth<T>) -> Self {
Self(either_or_both.as_mut().into())
}
}
impl<T> DoubleEndedIterator for IterMutEitherOrBoth<'_, T> {
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
self.0.next_back()
}
}
impl<T> ExactSizeIterator for IterMutEitherOrBoth<'_, T> {}
impl<T> FusedIterator for IterMutEitherOrBoth<'_, T> {}
impl<'a, T> Iterator for IterMutEitherOrBoth<'a, T> {
type Item = &'a mut T;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
self.0.next()
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.0.size_hint()
}
}
impl<L, R> SwapIterEitherOrBoth<L, R> {
#[inline]
pub(crate) const fn new(either_or_both: EitherOrBoth<L, R>) -> Self {
Self(either_or_both)
}
}
impl<L, R> DoubleEndedIterator for SwapIterEitherOrBoth<L, R>
where
L: DoubleEndedIterator,
R: DoubleEndedIterator,
{
#[inline]
fn next_back(&mut self) -> Option<Self::Item> {
match self.0.as_mut() {
EitherOrBoth::Both(left, right) => (left.next_back(), right.next_back()).try_into().ok(),
EitherOrBoth::Left(left) => left.next_back().map(EitherOrBoth::Left),
EitherOrBoth::Right(right) => right.next_back().map(EitherOrBoth::Right),
}
}
}
impl<L, R> ExactSizeIterator for SwapIterEitherOrBoth<L, R>
where
L: ExactSizeIterator,
R: ExactSizeIterator,
{
}
impl<L, R> FusedIterator for SwapIterEitherOrBoth<L, R>
where
L: FusedIterator,
R: FusedIterator,
{
}
impl<L, R> Iterator for SwapIterEitherOrBoth<L, R>
where
L: Iterator,
R: Iterator,
{
type Item = EitherOrBoth<L::Item, R::Item>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
match self.0.as_mut() {
EitherOrBoth::Both(left, right) => (left.next(), right.next()).try_into().ok(),
EitherOrBoth::Left(left) => left.next().map(EitherOrBoth::Left),
EitherOrBoth::Right(right) => right.next().map(EitherOrBoth::Right),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.0
.as_ref()
.bimap(Iterator::size_hint, Iterator::size_hint)
.reduce(|(l_lower, l_upper), (r_lower, r_upper)| {
(
l_lower.max(r_lower),
l_upper.and_then(|l| r_upper.map(|r| l.max(r))),
)
})
}
}
#[cfg(test)]
mod tests {
use rstest::rstest;
use EitherOrBoth::*;
use super::*;
#[rstest]
#[case::both(Both(1, 2), [Some(1), Some(2), None])]
#[case::left(Left(1), [Some(1), None, None])]
#[case::right(Right(2), [Some(2), None, None])]
fn items_next(#[case] either_or_both: EitherOrBoth<i32>, #[case] expected: [Option<i32>; 3]) {
let mut expected_iter = expected.into_iter();
let mut items = Items::from(either_or_both);
assert_eq!(items.next(), expected_iter.next().unwrap());
assert_eq!(items.next(), expected_iter.next().unwrap());
assert_eq!(items.next(), expected_iter.next().unwrap());
}
#[rstest]
#[case::both(Both(1, 2), [Some(2), Some(1), None])]
#[case::left(Left(1), [Some(1), None, None])]
#[case::right(Right(2), [Some(2), None, None])]
fn items_next_back(
#[case] either_or_both: EitherOrBoth<i32>,
#[case] expected: [Option<i32>; 3],
) {
let mut expected_iter = expected.into_iter();
let mut items = Items::from(either_or_both);
assert_eq!(items.next_back(), expected_iter.next().unwrap());
assert_eq!(items.next_back(), expected_iter.next().unwrap());
assert_eq!(items.next_back(), expected_iter.next().unwrap());
}
#[rstest]
#[case::both(Both(1, 2), [(2, Some(2)), (1, Some(1)), (0, Some(0))])]
#[case::left(Left(1), [(1, Some(1)), (0, Some(0)), (0, Some(0))])]
#[case::right(Right(2), [(1, Some(1)), (0, Some(0)), (0, Some(0))])]
fn items_size_hint(
#[case] either_or_both: EitherOrBoth<i32>,
#[case] expected: [(usize, Option<usize>); 3],
) {
let mut expected_iter = expected.into_iter();
let mut iter = Items::from(either_or_both);
assert_eq!(iter.size_hint(), expected_iter.next().unwrap());
iter.next();
assert_eq!(iter.size_hint(), expected_iter.next().unwrap());
iter.next();
assert_eq!(iter.size_hint(), expected_iter.next().unwrap());
}
#[test]
fn items_default() {
assert_eq!(Items { inner: Left(None) }, Items::<i32>::default());
}
#[test]
fn chained_iter_default() {
assert_eq!(
ChainedIterEitherOrBoth(Left('\0')),
ChainedIterEitherOrBoth::<char>::default()
);
}
}