Skip to content

Commit 02cc2f4

Browse files
committed
Swich zip_longest to yield EitherOrBoth instead of pairs of options.
1 parent 500e1e2 commit 02cc2f4

File tree

2 files changed

+44
-20
lines changed

2 files changed

+44
-20
lines changed

src/libcore/iter.rs

+37-14
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ use num::{ToPrimitive, Int};
6464
use ops::{Add, Deref};
6565
use option::{Option, Some, None};
6666
use uint;
67+
use self::EitherOrBoth::{Left, Right, Both};
6768

6869
#[deprecated = "renamed to Extend"] pub use self::Extend as Extendable;
6970

@@ -802,7 +803,7 @@ impl<'a, A, B, T: ExactSizeIterator<A>> ExactSizeIterator<B> for Map<'a, A, B, T
802803
impl<A, B, T, U> ExactSizeIterator<(A, B)> for Zip<T, U>
803804
where T: ExactSizeIterator<A>, U: ExactSizeIterator<B> {}
804805
#[unstable = "trait is unstable"]
805-
impl<A, B, T, U> ExactSizeIterator<(Option<A>, Option<B>)> for ZipLongest<T, U>
806+
impl<A, B, T, U> ExactSizeIterator<EitherOrBoth<A, B>> for ZipLongest<T, U>
806807
where T: ExactSizeIterator<A>, U: ExactSizeIterator<B> {}
807808

808809
/// An double-ended iterator with the direction inverted
@@ -1400,12 +1401,14 @@ pub struct ZipLongest<T, U> {
14001401
b: U
14011402
}
14021403

1403-
impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(Option<A>, Option<B>)> for ZipLongest<T, U> {
1404+
impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
14041405
#[inline]
1405-
fn next(&mut self) -> Option<(Option<A>, Option<B>)> {
1406+
fn next(&mut self) -> Option<EitherOrBoth<A, B>> {
14061407
match (self.a.next(), self.b.next()) {
14071408
(None, None) => None,
1408-
pair_of_options => Some(pair_of_options),
1409+
(Some(a), None) => Some(Left(a)),
1410+
(None, Some(b)) => Some(Right(b)),
1411+
(Some(a), Some(b)) => Some(Both(a, b)),
14091412
}
14101413
}
14111414

@@ -1425,36 +1428,56 @@ impl<A, B, T: Iterator<A>, U: Iterator<B>> Iterator<(Option<A>, Option<B>)> for
14251428
}
14261429
}
14271430

1428-
impl<A, B, T: ExactSize<A>, U: ExactSize<B>> DoubleEndedIterator<(Option<A>, Option<B>)>
1431+
impl<A, B, T: ExactSizeIterator<A>, U: ExactSizeIterator<B>> DoubleEndedIterator<EitherOrBoth<A, B>>
14291432
for ZipLongest<T, U> {
14301433
#[inline]
1431-
fn next_back(&mut self) -> Option<(Option<A>, Option<B>)> {
1434+
fn next_back(&mut self) -> Option<EitherOrBoth<A, B>> {
14321435
use cmp::{Equal, Greater, Less};
14331436
match self.a.len().cmp(&self.b.len()) {
14341437
Equal => match (self.a.next_back(), self.b.next_back()) {
14351438
(None, None) => None,
1436-
pair_of_options => Some(pair_of_options),
1439+
(Some(a), Some(b)) => Some(Both(a, b)),
1440+
// These can only happen if .len() is inconsistent with .next_back()
1441+
(Some(a), None) => Some(Left(a)),
1442+
(None, Some(b)) => Some(Right(b)),
14371443
},
1438-
Greater => self.a.next_back().map(|x| (Some(x), None)),
1439-
Less => self.b.next_back().map(|y| (None, Some(y))),
1444+
Greater => self.a.next_back().map(Left),
1445+
Less => self.b.next_back().map(Right),
14401446
}
14411447
}
14421448
}
14431449

14441450
impl<A, B, T: RandomAccessIterator<A>, U: RandomAccessIterator<B>>
1445-
RandomAccessIterator<(Option<A>, Option<B>)> for ZipLongest<T, U> {
1451+
RandomAccessIterator<EitherOrBoth<A, B>> for ZipLongest<T, U> {
14461452
#[inline]
14471453
fn indexable(&self) -> uint {
14481454
cmp::max(self.a.indexable(), self.b.indexable())
14491455
}
14501456

14511457
#[inline]
1452-
fn idx(&mut self, index: uint) -> Option<(Option<A>, Option<B>)> {
1458+
fn idx(&mut self, index: uint) -> Option<EitherOrBoth<A, B>> {
14531459
match (self.a.idx(index), self.b.idx(index)) {
14541460
(None, None) => None,
1455-
pair_of_options => Some(pair_of_options),
1456-
}
1457-
}
1461+
(Some(a), None) => Some(Left(a)),
1462+
(None, Some(b)) => Some(Right(b)),
1463+
(Some(a), Some(b)) => Some(Both(a, b)),
1464+
}
1465+
}
1466+
}
1467+
1468+
/// A value yielded by `ZipLongest`.
1469+
/// Contains one or two values,
1470+
/// depending on which of the input iterators are exhausted.
1471+
#[deriving(Clone, PartialEq, Eq, Show)]
1472+
pub enum EitherOrBoth<A, B> {
1473+
/// Neither input iterator is exhausted yet, yielding two values.
1474+
Both(A, B),
1475+
/// The parameter iterator of `.zip_longest()` is exhausted,
1476+
/// only yielding a value from the `self` iterator.
1477+
Left(A),
1478+
/// The `self` iterator of `.zip_longest()` is exhausted,
1479+
/// only yielding a value from the parameter iterator.
1480+
Right(B),
14581481
}
14591482

14601483
/// An iterator which maps the values of `iter` with `f`

src/libcoretest/iter.rs

+7-6
Original file line numberDiff line numberDiff line change
@@ -501,17 +501,18 @@ fn test_double_ended_zip() {
501501

502502
#[test]
503503
fn test_double_ended_zip_longest() {
504+
use core::iter::EitherOrBoth::{Both, Left};
504505
let xs = [1i, 2, 3, 4, 5, 6];
505506
let ys = [1i, 2, 3, 7];
506507
let a = xs.iter().map(|&x| x);
507508
let b = ys.iter().map(|&x| x);
508509
let mut it = a.zip_longest(b);
509-
assert_eq!(it.next(), Some((Some(1), Some(1))));
510-
assert_eq!(it.next(), Some((Some(2), Some(2))));
511-
assert_eq!(it.next_back(), Some((Some(6), None)));
512-
assert_eq!(it.next_back(), Some((Some(5), None)));
513-
assert_eq!(it.next_back(), Some((Some(4), Some(7))));
514-
assert_eq!(it.next(), Some((Some(3), Some(3))));
510+
assert_eq!(it.next(), Some(Both(1, 1)));
511+
assert_eq!(it.next(), Some(Both(2, 2)));
512+
assert_eq!(it.next_back(), Some(Left(6)));
513+
assert_eq!(it.next_back(), Some(Left(5)));
514+
assert_eq!(it.next_back(), Some(Both(4, 7)));
515+
assert_eq!(it.next(), Some(Both(3, 3)));
515516
assert_eq!(it.next(), None);
516517
}
517518

0 commit comments

Comments
 (0)