use core::iter::*;

#[test]
fn test_intersperse() {
    let v = std::iter::empty().intersperse(0u32).collect::<Vec<_>>();
    assert_eq!(v, vec![]);

    let v = std::iter::once(1).intersperse(0).collect::<Vec<_>>();
    assert_eq!(v, vec![1]);

    let xs = ["a", "", "b", "c"];
    let v: Vec<&str> = xs.iter().map(|x| *x).intersperse(", ").collect();
    let text: String = v.concat();
    assert_eq!(text, "a, , b, c".to_string());

    let ys = [0, 1, 2, 3];
    let mut it = ys[..0].iter().map(|x| *x).intersperse(1);
    assert!(it.next() == None);
}

#[test]
fn test_intersperse_size_hint() {
    let iter = std::iter::empty::<i32>().intersperse(0);
    assert_eq!(iter.size_hint(), (0, Some(0)));

    let xs = ["a", "", "b", "c"];
    let mut iter = xs.iter().map(|x| *x).intersperse(", ");
    assert_eq!(iter.size_hint(), (7, Some(7)));

    assert_eq!(iter.next(), Some("a"));
    assert_eq!(iter.size_hint(), (6, Some(6)));
    assert_eq!(iter.next(), Some(", "));
    assert_eq!(iter.size_hint(), (5, Some(5)));

    assert_eq!([].iter().intersperse(&()).size_hint(), (0, Some(0)));
}

#[test]
fn test_fold_specialization_intersperse() {
    let mut iter = (1..2).intersperse(0);
    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));

    let mut iter = (1..3).intersperse(0);
    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));

    let mut iter = (1..4).intersperse(0);
    iter.clone().for_each(|x| assert_eq!(Some(x), iter.next()));
}

#[test]
fn test_try_fold_specialization_intersperse_ok() {
    let mut iter = (1..2).intersperse(0);
    iter.clone().try_for_each(|x| {
        assert_eq!(Some(x), iter.next());
        Some(())
    });

    let mut iter = (1..3).intersperse(0);
    iter.clone().try_for_each(|x| {
        assert_eq!(Some(x), iter.next());
        Some(())
    });

    let mut iter = (1..4).intersperse(0);
    iter.clone().try_for_each(|x| {
        assert_eq!(Some(x), iter.next());
        Some(())
    });
}

#[test]
fn test_intersperse_with() {
    #[derive(PartialEq, Debug)]
    struct NotClone {
        u: u32,
    }
    let r = [NotClone { u: 0 }, NotClone { u: 1 }]
        .into_iter()
        .intersperse_with(|| NotClone { u: 2 })
        .collect::<Vec<_>>();
    assert_eq!(r, vec![NotClone { u: 0 }, NotClone { u: 2 }, NotClone { u: 1 }]);

    let mut ctr = 100;
    let separator = || {
        ctr *= 2;
        ctr
    };
    let r = (0..3).intersperse_with(separator).collect::<Vec<_>>();
    assert_eq!(r, vec![0, 200, 1, 400, 2]);
}

#[test]
fn test_intersperse_fold() {
    let v = (1..4).intersperse(9).fold(Vec::new(), |mut acc, x| {
        acc.push(x);
        acc
    });
    assert_eq!(v.as_slice(), [1, 9, 2, 9, 3]);

    let mut iter = (1..4).intersperse(9);
    assert_eq!(iter.next(), Some(1));
    let v = iter.fold(Vec::new(), |mut acc, x| {
        acc.push(x);
        acc
    });
    assert_eq!(v.as_slice(), [9, 2, 9, 3]);

    struct NoneAtStart(i32); // Produces: None, Some(2), Some(3), None, ...
    impl Iterator for NoneAtStart {
        type Item = i32;
        fn next(&mut self) -> Option<i32> {
            self.0 += 1;
            Some(self.0).filter(|i| i % 3 != 1)
        }
    }

    let v = NoneAtStart(0).intersperse(1000).fold(0, |a, b| a + b);
    assert_eq!(v, 0);
}

#[test]
fn test_intersperse_collect_string() {
    let contents = [1, 2, 3];

    let contents_string = contents
        .into_iter()
        .map(|id| id.to_string())
        .intersperse(", ".to_owned())
        .collect::<String>();
    assert_eq!(contents_string, "1, 2, 3");
}

#[test]
fn test_try_fold_specialization_intersperse_err() {
    let orig_iter = ["a", "b"].iter().copied().intersperse("-");

    // Abort after the first item.
    let mut iter = orig_iter.clone();
    iter.try_for_each(|_| None::<()>);
    assert_eq!(iter.next(), Some("-"));
    assert_eq!(iter.next(), Some("b"));
    assert_eq!(iter.next(), None);

    // Abort after the second item.
    let mut iter = orig_iter.clone();
    iter.try_for_each(|item| if item == "-" { None } else { Some(()) });
    assert_eq!(iter.next(), Some("b"));
    assert_eq!(iter.next(), None);

    // Abort after the third item.
    let mut iter = orig_iter.clone();
    iter.try_for_each(|item| if item == "b" { None } else { Some(()) });
    assert_eq!(iter.next(), None);
}

#[test]
fn test_non_fused_iterator_intersperse() {
    #[derive(Debug)]
    struct TestCounter {
        counter: usize,
    }

    /// Given a counter of 0, this produces:
    /// `None` -> `Some(2)` -> `None` -> `Some(4)` -> `None` -> `Some(6)`
    /// -> and then `None` endlessly
    impl Iterator for TestCounter {
        type Item = usize;
        fn next(&mut self) -> Option<Self::Item> {
            if self.counter > 6 {
                None
            } else if self.counter % 2 == 0 {
                self.counter += 1;
                None
            } else {
                self.counter += 1;
                Some(self.counter)
            }
        }
    }

    let counter = 0;
    // places a 1 between `Some(_)` items
    let non_fused_iter = TestCounter { counter };
    let mut intersperse_iter = non_fused_iter.intersperse(1);
    // Interspersed iter produces:
    // `None` -> `Some(2)` -> `None` -> `Some(1)` -> Some(4)` -> `None` ->  `Some(1)` ->
    // `Some(6)` -> and then `None` endlessly
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(2));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(4));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(6));
    assert_eq!(intersperse_iter.next(), None);

    // Extra check to make sure it is `None` after processing all items
    assert_eq!(intersperse_iter.next(), None);
}

#[test]
fn test_non_fused_iterator_intersperse_2() {
    #[derive(Debug)]
    struct TestCounter {
        counter: usize,
    }

    // Given a counter of 0, this produces:
    // `Some(1)` -> `Some(2)` -> `None` -> `Some(4)` -> `Some(5)` ->
    // and then `None` endlessly
    impl Iterator for TestCounter {
        type Item = usize;
        fn next(&mut self) -> Option<Self::Item> {
            if self.counter < 5 {
                self.counter += 1;
                if self.counter % 3 != 0 {
                    return Some(self.counter);
                } else {
                    return None;
                }
            }
            self.counter += 1;
            None
        }
    }

    let counter = 0;
    // places a 100 between `Some(_)` items
    let non_fused_iter = TestCounter { counter };
    let mut intersperse_iter = non_fused_iter.intersperse(100);
    // Interspersed iter produces:
    // `Some(1)` -> `Some(100)` -> `Some(2)` -> `None` -> `Some(100)`
    //  -> `Some(4)` -> `Some(100)` -> `Some(5)` -> `None` endlessly
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(2));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(4));
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(5));
    assert_eq!(intersperse_iter.next(), None);

    // Extra check to make sure it is `None` after processing 6 items
    assert_eq!(intersperse_iter.next(), None);
}

#[test]
fn test_non_fused_iterator_intersperse_with() {
    #[derive(Debug)]
    struct TestCounter {
        counter: usize,
    }

    // Given a counter of 0, this produces:
    // `None` -> `Some(2)` -> `None` -> `Some(4)` -> `None` -> `Some(6)`
    // -> and then `None` endlessly
    impl Iterator for TestCounter {
        type Item = usize;
        fn next(&mut self) -> Option<Self::Item> {
            if self.counter > 6 {
                None
            } else if self.counter % 2 == 0 {
                self.counter += 1;
                None
            } else {
                self.counter += 1;
                Some(self.counter)
            }
        }
    }

    let counter = 0;
    let non_fused_iter = TestCounter { counter };
    // places a 2 between `Some(_)` items
    let mut intersperse_iter = non_fused_iter.intersperse_with(|| 1);
    // Interspersed iter produces:
    // `None` -> `Some(2)` -> `None` -> `Some(1)` -> Some(4)` -> `None` ->  `Some(1)` ->
    // `Some(6)` -> and then `None` endlessly
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(2));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(4));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(6));
    assert_eq!(intersperse_iter.next(), None);

    // Extra check to make sure it is `None` after processing 6 items
    assert_eq!(intersperse_iter.next(), None);
}

#[test]
fn test_non_fused_iterator_intersperse_with_2() {
    #[derive(Debug)]
    struct TestCounter {
        counter: usize,
    }

    // Given a counter of 0, this produces:
    // `Some(1)` -> `Some(2)` -> `None` -> `Some(4)` -> `Some(5)` ->
    // and then `None` endlessly
    impl Iterator for TestCounter {
        type Item = usize;
        fn next(&mut self) -> Option<Self::Item> {
            if self.counter < 5 {
                self.counter += 1;
                if self.counter % 3 != 0 {
                    return Some(self.counter);
                } else {
                    return None;
                }
            }
            self.counter += 1;
            None
        }
    }

    let counter = 0;
    // places a 100 between `Some(_)` items
    let non_fused_iter = TestCounter { counter };
    let mut intersperse_iter = non_fused_iter.intersperse_with(|| 100);
    // Interspersed iter produces:
    // `Some(1)` -> `Some(100)` -> `Some(2)` -> `None` -> `Some(100)`
    //  -> `Some(4)` -> `Some(100)` -> `Some(5)` -> `None` endlessly
    assert_eq!(intersperse_iter.next(), Some(1));
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(2));
    assert_eq!(intersperse_iter.next(), None);
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(4));
    assert_eq!(intersperse_iter.next(), Some(100));
    assert_eq!(intersperse_iter.next(), Some(5));
    assert_eq!(intersperse_iter.next(), None);

    // Extra check to make sure it is `None` after processing 6 items
    assert_eq!(intersperse_iter.next(), None);
}
