I would like to build an iterator that returns a number of elements, each element computed by a different block of code. Each block of code may or may not return an element. I'm looking for the best way to represent an iterator like this.
Minimized examples follow. Though the blocks return constants, in the real code, whether each block returns an item is based on context. Also, in the real code, there are many blocks of code (not just three), millions/billions of calls are made to this iterator, and large trees are constructed, so both space and time complexity are important.
One attempt:
pub fn it1() -> impl Iterator<Item = usize> {
let mut state = 0;
std::iter::from_fn(move || {
loop {
state += 1;
match state {
1 => (), // Code A, does not emit item
2 => break Some(3), // Code B, emits item
3 => break Some(45), // Code C, emits item
_ => break None,
}
}
})
}
This seems efficient since non-values don't take any resources, but a variable is needed to track which computation is taking place which seems prone to error.
Another:
pub fn it2() -> impl Iterator<Item = usize> {
[
{
None // Code A runs, does not emit item
},
{
Some(3)// Code B runs, emits item
},
{
Some(45) // Code C runs, emits item
},
]
.into_iter()
.filter_map(|x| x)
}
This does not need the state variable but needs an array. It also needs to keep the non-values and then do another pass to remove them, which is inefficient (?) with large numbers of items.
Third:
pub fn it3() -> impl Iterator<Item = usize> {
std::iter::empty()
.chain(std::iter::once_with(|| {
// Code A runs, does not emit item
None
}))
.chain(std::iter::once_with(|| {
// Code B runs, emits item
Some(3)
}))
.chain(std::iter::once_with(|| {
// Code C runs, emits item
Some(45)
}))
.filter_map(|x| x)
}
This does not need the array but incurs function call overhead (?) and still has the second pass to filter out non-values. Also possible many iterator chain calls, once_with calls, etc. incur unnecessary overhead.
Are there established patterns on how to build this? Obvious, preferred/idiomatic or best practices approaches?