Skip to content

magicant/fuzed-iterator-rs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Fuzed iterator

fuzed-iterator at crates.io fuzed-iterator at docs.rs Build status Changelog

fuzed-iterator is a Rust library crate that provides a simple iterator wrapper that causes a panic if the iterator is used after it has once returned None.

Many iterators in std implement the FusedIterator trait, which guarantees that the iterator will never return Some after returning None. This may make programmers incorrectly assume that any iterator works like a FusedIterator, leading to bugs when a non-fused iterator is used.

The Fuze wrapper provided by this crate can be used to wrap any iterator, causing a panic if the iterator is used after returning None for the first time. This can be used to catch bugs where a non-fused iterator is used in a context where a fused iterator is expected. In your unit tests (or integration tests), pass iterators through Fuze to your functions that expect an iterator (not necessarily fused), and the tests will panic if the function calls Iterator::next excessively.

Example

use fuzed_iterator::IteratorExt as _;
let mut iter = (0..3).fuze();
assert_eq!(iter.next(), Some(0));
assert_eq!(iter.next(), Some(1));
assert_eq!(iter.next(), Some(2));
assert_eq!(iter.next(), None);
iter.next(); // Another `next` call would panic!
/// Collects items from an iterator into a vector, but drops the first item.
fn drop_first_and_collect<I: IntoIterator<Item = i32>>(i: I) -> Vec<i32> {
    // This implementation is wrong because `next` may be called again even after it
    // returned `None`.
    let mut i = i.into_iter();
    _ = i.next();
    i.collect()
}

// Because of the wrong implementation, this test case would fail with a panic.
# /*
#[test]
# */
fn test_drop_first_and_collect_with_empty_array() {
    use fuzed_iterator::IteratorExt as _;
    let result = drop_first_and_collect([].into_iter().fuze());
    assert_eq!(result, []);
}
# test_drop_first_and_collect_with_empty_array();
/// Collects items from an iterator into a vector, but drops the first item.
fn drop_first_and_collect<I: IntoIterator<Item = i32>>(i: I) -> Vec<i32> {
    // This is the correct implementation.
    let mut i = i.into_iter();
    if i.next().is_none() {
        return vec![];
    }
    i.collect()
}

// Test passed!
# /*
#[test]
# */
fn test_drop_first_and_collect_with_empty_array() {
    use fuzed_iterator::IteratorExt as _;
    let result = drop_first_and_collect([].into_iter().fuze());
    assert_eq!(result, []);
}
# test_drop_first_and_collect_with_empty_array();

License

MIT or Apache 2.0, at your option

About

Rust iterator wrapper for detecting incorrect use of non-fused iterators

Topics

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-Apache
MIT
LICENSE-MIT

Stars

Watchers

Forks

Languages