69db91b8b2
A successful advance is now signalled by returning `0` and other values now represent the remaining number of steps that couldn't be advanced as opposed to the amount of steps that have been advanced during a partial advance_by. This simplifies adapters a bit, replacing some `match`/`if` with arithmetic. Whether this is beneficial overall depends on whether `advance_by` is mostly used as a building-block for other iterator methods and adapters or whether we also see uses by users where `Result` might be more useful.
281 lines
8.9 KiB
Rust
281 lines
8.9 KiB
Rust
use super::*;
|
|
use core::iter::*;
|
|
|
|
#[test]
|
|
fn test_iterator_chain() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
|
|
let it = xs.iter().chain(&ys);
|
|
let mut i = 0;
|
|
for &x in it {
|
|
assert_eq!(x, expected[i]);
|
|
i += 1;
|
|
}
|
|
assert_eq!(i, expected.len());
|
|
|
|
let ys = (30..).step_by(10).take(4);
|
|
let it = xs.iter().cloned().chain(ys);
|
|
let mut i = 0;
|
|
for x in it {
|
|
assert_eq!(x, expected[i]);
|
|
i += 1;
|
|
}
|
|
assert_eq!(i, expected.len());
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_advance_by() {
|
|
fn test_chain(xs: &[i32], ys: &[i32]) {
|
|
let len = xs.len() + ys.len();
|
|
|
|
for i in 0..xs.len() {
|
|
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
|
assert_eq!(0, iter.advance_by(i));
|
|
assert_eq!(iter.next(), Some(&xs[i]));
|
|
assert_eq!(iter.advance_by(100), 100 - (len - i - 1));
|
|
assert_eq!(0, iter.advance_by(0));
|
|
}
|
|
|
|
for i in 0..ys.len() {
|
|
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
|
assert_eq!(iter.advance_by(xs.len() + i), 0);
|
|
assert_eq!(iter.next(), Some(&ys[i]));
|
|
assert_eq!(iter.advance_by(100), 100 - (ys.len() - i - 1));
|
|
assert_eq!(iter.advance_by(0), 0);
|
|
}
|
|
|
|
let mut iter = xs.iter().chain(ys);
|
|
assert_eq!(iter.advance_by(len), 0);
|
|
assert_eq!(iter.next(), None);
|
|
assert_eq!(iter.advance_by(0), 0);
|
|
|
|
let mut iter = xs.iter().chain(ys);
|
|
assert_eq!(iter.advance_by(len + 1), 1);
|
|
assert_eq!(iter.advance_by(0), 0);
|
|
}
|
|
|
|
test_chain(&[], &[]);
|
|
test_chain(&[], &[0, 1, 2, 3, 4, 5]);
|
|
test_chain(&[0, 1, 2, 3, 4, 5], &[]);
|
|
test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_advance_back_by() {
|
|
fn test_chain(xs: &[i32], ys: &[i32]) {
|
|
let len = xs.len() + ys.len();
|
|
|
|
for i in 0..ys.len() {
|
|
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
|
assert_eq!(iter.advance_back_by(i), 0);
|
|
assert_eq!(iter.next_back(), Some(&ys[ys.len() - i - 1]));
|
|
assert_eq!(iter.advance_back_by(100), 100 - (len - i - 1));
|
|
assert_eq!(iter.advance_back_by(0), 0);
|
|
}
|
|
|
|
for i in 0..xs.len() {
|
|
let mut iter = Unfuse::new(xs).chain(Unfuse::new(ys));
|
|
assert_eq!(iter.advance_back_by(ys.len() + i), 0);
|
|
assert_eq!(iter.next_back(), Some(&xs[xs.len() - i - 1]));
|
|
assert_eq!(iter.advance_back_by(100), 100 - (xs.len() - i - 1));
|
|
assert_eq!(iter.advance_back_by(0), 0);
|
|
}
|
|
|
|
let mut iter = xs.iter().chain(ys);
|
|
assert_eq!(iter.advance_back_by(len), 0);
|
|
assert_eq!(iter.next_back(), None);
|
|
assert_eq!(iter.advance_back_by(0), 0);
|
|
|
|
let mut iter = xs.iter().chain(ys);
|
|
assert_eq!(iter.advance_back_by(len + 1), 1);
|
|
assert_eq!(iter.advance_back_by(0), 0);
|
|
}
|
|
|
|
test_chain(&[], &[]);
|
|
test_chain(&[], &[0, 1, 2, 3, 4, 5]);
|
|
test_chain(&[0, 1, 2, 3, 4, 5], &[]);
|
|
test_chain(&[0, 1, 2, 3, 4, 5], &[30, 40, 50, 60]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_nth() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let zs = [];
|
|
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
|
|
for (i, x) in expected.iter().enumerate() {
|
|
assert_eq!(Some(x), xs.iter().chain(&ys).nth(i));
|
|
}
|
|
assert_eq!(zs.iter().chain(&xs).nth(0), Some(&0));
|
|
|
|
let mut it = xs.iter().chain(&zs);
|
|
assert_eq!(it.nth(5), Some(&5));
|
|
assert_eq!(it.next(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_nth_back() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let zs = [];
|
|
let expected = [0, 1, 2, 3, 4, 5, 30, 40, 50, 60];
|
|
for (i, x) in expected.iter().rev().enumerate() {
|
|
assert_eq!(Some(x), xs.iter().chain(&ys).nth_back(i));
|
|
}
|
|
assert_eq!(zs.iter().chain(&xs).nth_back(0), Some(&5));
|
|
|
|
let mut it = xs.iter().chain(&zs);
|
|
assert_eq!(it.nth_back(5), Some(&0));
|
|
assert_eq!(it.next(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_last() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let zs = [];
|
|
assert_eq!(xs.iter().chain(&ys).last(), Some(&60));
|
|
assert_eq!(zs.iter().chain(&ys).last(), Some(&60));
|
|
assert_eq!(ys.iter().chain(&zs).last(), Some(&60));
|
|
assert_eq!(zs.iter().chain(&zs).last(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_count() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let zs = [];
|
|
assert_eq!(xs.iter().chain(&ys).count(), 10);
|
|
assert_eq!(zs.iter().chain(&ys).count(), 4);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_find() {
|
|
let xs = [0, 1, 2, 3, 4, 5];
|
|
let ys = [30, 40, 50, 60];
|
|
let mut iter = xs.iter().chain(&ys);
|
|
assert_eq!(iter.find(|&&i| i == 4), Some(&4));
|
|
assert_eq!(iter.next(), Some(&5));
|
|
assert_eq!(iter.find(|&&i| i == 40), Some(&40));
|
|
assert_eq!(iter.next(), Some(&50));
|
|
assert_eq!(iter.find(|&&i| i == 100), None);
|
|
assert_eq!(iter.next(), None);
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_size_hint() {
|
|
// this chains an iterator of length 0 with an iterator of length 1,
|
|
// so after calling `.next()` once, the iterator is empty and the
|
|
// state is `ChainState::Back`. `.size_hint()` should now disregard
|
|
// the size hint of the left iterator
|
|
let mut iter = Toggle { is_empty: true }.chain(once(()));
|
|
assert_eq!(iter.next(), Some(()));
|
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
|
|
|
let mut iter = once(()).chain(Toggle { is_empty: true });
|
|
assert_eq!(iter.next_back(), Some(()));
|
|
assert_eq!(iter.size_hint(), (0, Some(0)));
|
|
}
|
|
|
|
#[test]
|
|
fn test_iterator_chain_unfused() {
|
|
// Chain shouldn't be fused in its second iterator, depending on direction
|
|
let mut iter = NonFused::new(empty()).chain(Toggle { is_empty: true });
|
|
assert!(iter.next().is_none());
|
|
assert!(iter.next().is_some());
|
|
assert!(iter.next().is_none());
|
|
|
|
let mut iter = Toggle { is_empty: true }.chain(NonFused::new(empty()));
|
|
assert!(iter.next_back().is_none());
|
|
assert!(iter.next_back().is_some());
|
|
assert!(iter.next_back().is_none());
|
|
}
|
|
|
|
#[test]
|
|
fn test_chain_fold() {
|
|
let xs = [1, 2, 3];
|
|
let ys = [1, 2, 0];
|
|
|
|
let mut iter = xs.iter().chain(&ys);
|
|
iter.next();
|
|
let mut result = Vec::new();
|
|
iter.fold((), |(), &elt| result.push(elt));
|
|
assert_eq!(&[2, 3, 1, 2, 0], &result[..]);
|
|
}
|
|
|
|
#[test]
|
|
fn test_chain_try_folds() {
|
|
let c = || (0..10).chain(10..20);
|
|
|
|
let f = &|acc, x| i32::checked_add(2 * acc, x);
|
|
assert_eq!(c().try_fold(7, f), (0..20).try_fold(7, f));
|
|
assert_eq!(c().try_rfold(7, f), (0..20).rev().try_fold(7, f));
|
|
|
|
let mut iter = c();
|
|
assert_eq!(iter.position(|x| x == 5), Some(5));
|
|
assert_eq!(iter.next(), Some(6), "stopped in front, state Both");
|
|
assert_eq!(iter.position(|x| x == 13), Some(6));
|
|
assert_eq!(iter.next(), Some(14), "stopped in back, state Back");
|
|
assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((15..20).sum()));
|
|
|
|
let mut iter = c().rev(); // use rev to access try_rfold
|
|
assert_eq!(iter.position(|x| x == 15), Some(4));
|
|
assert_eq!(iter.next(), Some(14), "stopped in back, state Both");
|
|
assert_eq!(iter.position(|x| x == 5), Some(8));
|
|
assert_eq!(iter.next(), Some(4), "stopped in front, state Front");
|
|
assert_eq!(iter.try_fold(0, |acc, x| Some(acc + x)), Some((0..4).sum()));
|
|
|
|
let mut iter = c();
|
|
iter.by_ref().rev().nth(14); // skip the last 15, ending in state Front
|
|
assert_eq!(iter.try_fold(7, f), (0..5).try_fold(7, f));
|
|
|
|
let mut iter = c();
|
|
iter.nth(14); // skip the first 15, ending in state Back
|
|
assert_eq!(iter.try_rfold(7, f), (15..20).try_rfold(7, f));
|
|
}
|
|
|
|
#[test]
|
|
fn test_double_ended_chain() {
|
|
let xs = [1, 2, 3, 4, 5];
|
|
let ys = [7, 9, 11];
|
|
let mut it = xs.iter().chain(&ys).rev();
|
|
assert_eq!(it.next().unwrap(), &11);
|
|
assert_eq!(it.next().unwrap(), &9);
|
|
assert_eq!(it.next_back().unwrap(), &1);
|
|
assert_eq!(it.next_back().unwrap(), &2);
|
|
assert_eq!(it.next_back().unwrap(), &3);
|
|
assert_eq!(it.next_back().unwrap(), &4);
|
|
assert_eq!(it.next_back().unwrap(), &5);
|
|
assert_eq!(it.next_back().unwrap(), &7);
|
|
assert_eq!(it.next_back(), None);
|
|
|
|
// test that .chain() is well behaved with an unfused iterator
|
|
struct CrazyIterator(bool);
|
|
impl CrazyIterator {
|
|
fn new() -> CrazyIterator {
|
|
CrazyIterator(false)
|
|
}
|
|
}
|
|
impl Iterator for CrazyIterator {
|
|
type Item = i32;
|
|
fn next(&mut self) -> Option<i32> {
|
|
if self.0 {
|
|
Some(99)
|
|
} else {
|
|
self.0 = true;
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl DoubleEndedIterator for CrazyIterator {
|
|
fn next_back(&mut self) -> Option<i32> {
|
|
self.next()
|
|
}
|
|
}
|
|
|
|
assert_eq!(CrazyIterator::new().chain(0..10).rev().last(), Some(0));
|
|
assert!((0..10).chain(CrazyIterator::new()).rev().any(|i| i == 0));
|
|
}
|