Or, a similar pattern where I match on two successive calls to .next().
Are there other common patterns for this use case? I always feel this is a case of "good, but could be better" whenever I use it, but I can't think of a better pattern.
edit: Here's a version which retains the Error type, if that is important: Rust Playground (The identity transformation err => err can also be unreachable_unchecked() for possible optimizations.)
Yeah that one was confusing me. I agree that my original implementation was flawed due to always calling .next() twice, even when not needed. All the solutions proposed here avoid that (that I can tell). But that's because I may end up with an iterator which might return Some(..) at some point after returning None. I can't assume that the iterator I get is fused, or behaves as such.
That being said, barring catastrophic events, are there situations where calling .next() should/would panic? I feel that would be an anti-pattern. Even if a tcp socket closes and later resumes, or a file system is filled but later gets some space freed, or we're reading some kind event queue in a concurrent system.
Even a non-fusing iterator would, I assume, always just continue to yield None. Are there examples of iterator implementations that don't behave this way?
Realistically, not ones you should worry about, no.
It is possible, because it's legal for any Rust evaluation whatsoever to panic, but you are not expected to prepare for that. If someone passes your code a panicking iterator, and it panics, they get to keep both pieces.
Even if a tcp socket closes and later resumes
This should usually be modelled using an iterator over Result, rather than an iterator that panics, but it is a good example of how your design may end up exploring this corner. Good eye.
Even a non-fusing iterator would, I assume, always just continue to yield None . Are there examples of iterator implementations that don't behave this way?
It's not hard to accidentally build one out of from_fn, unless you're careful about that specific behaviour. The example in the docs will return a lot of None values, but in release builds (where integer overflow does not panic), will eventually start returning Some(value) again, initially with large negative numbers.