#![no_std]
#![doc = include_str!("../README.md")]
#![warn(missing_docs)]
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub struct Fuze<I> {
inner: Option<I>,
}
impl<I: Default> Default for Fuze<I> {
fn default() -> Self {
Self {
inner: Some(Default::default()),
}
}
}
impl<I> From<I> for Fuze<I> {
fn from(iter: I) -> Self {
Fuze { inner: Some(iter) }
}
}
impl<I> Iterator for Fuze<I>
where
I: Iterator,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
let inner = self
.inner
.as_mut()
.expect("called `Fuze::next` after it returned `None`");
let item = inner.next();
if item.is_none() {
self.inner = None;
}
item
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner
.as_ref()
.map_or((0, None), |inner| inner.size_hint())
}
}
impl<I> DoubleEndedIterator for Fuze<I>
where
I: DoubleEndedIterator,
{
fn next_back(&mut self) -> Option<Self::Item> {
let inner = self
.inner
.as_mut()
.expect("called `Fuze::next_back` after it returned `None`");
let item = inner.next_back();
if item.is_none() {
self.inner = None;
}
item
}
}
pub trait IteratorExt {
fn fuze(self) -> Fuze<Self>
where
Self: Sized;
}
impl<I: Iterator> IteratorExt for I {
fn fuze(self) -> Fuze<Self> {
self.into()
}
}
#[cfg(test)]
mod iterator_tests {
use super::*;
#[test]
fn no_panic_until_first_none() {
let mut i = "foo".chars().fuze();
assert_eq!(i.next(), Some('f'));
assert_eq!(i.next(), Some('o'));
assert_eq!(i.next(), Some('o'));
assert_eq!(i.next(), None);
}
#[test]
#[should_panic = "called `Fuze::next` after it returned `None`"]
fn panic_on_another_next_after_none() {
let mut i = "foo".chars().fuze();
i.by_ref().for_each(drop);
i.next();
}
#[test]
fn no_panic_if_fused() {
let mut i = "foo".chars().fuze().fuse();
i.by_ref().for_each(drop);
assert_eq!(i.next(), None);
}
#[test]
fn size_hint() {
let mut i = [1, 2, 3].iter().fuze();
assert_eq!(i.size_hint(), (3, Some(3)));
i.next();
assert_eq!(i.size_hint(), (2, Some(2)));
i.next();
assert_eq!(i.size_hint(), (1, Some(1)));
i.next();
assert_eq!(i.size_hint(), (0, Some(0)));
i.next();
assert_eq!(i.size_hint(), (0, None));
}
}
#[cfg(test)]
mod double_ended_iterator_tests {
use super::*;
#[test]
fn no_panic_until_first_none() {
let mut i = "foo".chars().fuze();
assert_eq!(i.next_back(), Some('o'));
assert_eq!(i.next_back(), Some('o'));
assert_eq!(i.next_back(), Some('f'));
assert_eq!(i.next_back(), None);
}
#[test]
#[should_panic = "called `Fuze::next_back` after it returned `None`"]
fn panic_on_another_next_back_after_none() {
let mut i = "foo".chars().fuze();
i.by_ref().rev().for_each(drop);
i.next_back();
}
#[test]
fn no_panic_if_fused() {
let mut i = "foo".chars().fuze().fuse();
i.by_ref().rev().for_each(drop);
assert_eq!(i.next_back(), None);
}
}