iter_cartesian 0.1.0

A Cartesian product iterator with double-ended iteration and O(1) length queries.
Documentation
use iter_cartesian::CartesianExt;

#[test]
fn exact_size() {
    assert_eq!((0..3).cartesian(0..3).len(), 9);
}

#[test]
fn double_ended_exhaustion() {
    let mut iter = (0..2).cartesian(0..2);
    assert_eq!(iter.next(), Some((0, 0)));
    assert_eq!(iter.next_back(), Some((1, 1)));
    assert_eq!(iter.next(), Some((0, 1)));
    assert_eq!(iter.next_back(), Some((1, 0)));
    assert_eq!(iter.next(), None);
}

#[test]
fn empty_primary() {
    assert_eq!((0..0).cartesian(0..10).next(), None);
}

#[test]
fn two_element_primary() {
    let mut iter = (0..2).cartesian(0..2);
    assert_eq!(iter.len(), 4);
    iter.next();
    assert_eq!(iter.len(), 3);
    iter.next_back();
    assert_eq!(iter.len(), 2);
    iter.next();
    assert_eq!(iter.len(), 1);
    iter.next_back();
    assert_eq!(iter.len(), 0);
}

#[test]
fn forward_only() {
    let got: Vec<_> = (0..3).cartesian(0..3).collect();
    let expected: Vec<_> = (0..3).flat_map(|i| (0..3).map(move |j| (i, j))).collect();
    assert_eq!(got, expected);
}

#[test]
fn backward_only() {
    let got: Vec<_> = (0..3).cartesian(0..3).rev().collect();
    let expected: Vec<_> = (0..3)
        .rev()
        .flat_map(|i| (0..3).rev().map(move |j| (i, j)))
        .collect();
    assert_eq!(got, expected);
}

#[test]
fn len_tracks_consumption() {
    let mut iter = (0..4).cartesian(0..4);
    assert_eq!(iter.len(), 16);
    iter.next();
    assert_eq!(iter.len(), 15);
    iter.next_back();
    assert_eq!(iter.len(), 14);
}

#[test]
fn single_primary() {
    let got: Vec<_> = (0..1).cartesian(0..4).collect();
    assert_eq!(got, [(0, 0), (0, 1), (0, 2), (0, 3)]);
}

#[test]
fn empty_secondary() {
    let mut iter = (0..5).cartesian(0..0);
    assert_eq!(iter.next(), None);
    assert_eq!(iter.len(), 0);
}

/// Regression guard for cursor-crossing: no item may be dropped or duplicated
/// when the two ends meet on the same row.
#[test]
fn interleaved_3x3() {
    let mut iter = (0..3).cartesian(0..3);
    let mut front = vec![];
    let mut back = vec![];
    loop {
        match (iter.next(), iter.next_back()) {
            (None, None) => break,
            (Some(f), None) => {
                front.push(f);
                break;
            }
            (None, Some(b)) => {
                back.push(b);
                break;
            }
            (Some(f), Some(b)) => {
                front.push(f);
                back.push(b);
            }
        }
    }
    back.reverse();
    front.extend(back);
    let mut got = front;
    got.sort_unstable();

    let mut expected: Vec<_> = (0..3).flat_map(|i| (0..3).map(move |j| (i, j))).collect();
    expected.sort_unstable();
    assert_eq!(got, expected);
}

/// `len` must be exact once both cursors have converged onto the same row.
#[test]
fn len_shared_row() {
    let mut iter = (0..3).cartesian(0..4);
    iter.next();
    iter.next();
    iter.next();
    iter.next();
    iter.next_back();
    iter.next_back();
    iter.next_back();
    iter.next_back();
    assert_eq!(iter.len(), 4);
    iter.next();
    assert_eq!(iter.len(), 3);
    iter.next_back();
    assert_eq!(iter.len(), 2);
}

#[cfg(test)]
mod override_tests {
    use super::*;

    #[test]
    fn nth_jumps_rows() {
        let mut iter = (0..5).cartesian(0..10);
        assert_eq!(iter.nth(25), Some((2, 5)));
        assert_eq!(iter.len(), 24);
        assert_eq!(iter.next(), Some((2, 6)));
    }

    #[test]
    fn nth_exhaustion() {
        let mut iter = (0..2).cartesian(0..2);
        assert_eq!(iter.nth(4), None);
        assert_eq!(iter.len(), 0);
    }

    #[test]
    fn nth_on_shared_row() {
        let mut iter = (0..3).cartesian(0..10);
        for _ in 0..10 {
            iter.next();
        }
        for _ in 0..10 {
            iter.next_back();
        }
        assert_eq!(iter.len(), 10);
        assert_eq!(iter.nth(5), Some((1, 5)));
        assert_eq!(iter.len(), 4);
    }

    #[test]
    fn last_is_correct() {
        let iter = (0..10).cartesian(0..10);
        assert_eq!(iter.last(), Some((9, 9)));
    }

    #[test]
    fn count_is_correct() {
        let iter = (0..5).cartesian(0..5);
        assert_eq!(iter.count(), 25);
    }

    #[test]
    fn mixed_nth_and_back() {
        let mut iter = (0..10).cartesian(0..10);
        iter.next_back();
        assert_eq!(iter.nth(0), Some((0, 0)));
        assert_eq!(iter.len(), 98);
        assert_eq!(iter.nth(98), None);
    }
}