The basic question is: if an implementation of the Iterator trait returns a Result<T, E>, what should the iterator do after an error is returned from next() that makes it impossible to continue iterating?
Some context:
As a learning project, I'm attempting to implement a parsing library to parse STUN messages, as defined in RFC5389 in Rust. STUN is a binary network protocol, and as such I would be parsing byte slices. Specifically, the protocol specifies that zero or more dynamically-sized attributes can be encoded into the message. Thus, I am trying to construct an iterator which can be used to iterate over the bytes, yielding subslices for each attribute.
Thus, I have something like this...
pub struct StunAttributeIterator<'a> {
data: &'a [u8],
}
impl<'a> Iterator for StunAttributeIterator<'a> {
type Item = Result<StunAttribute<'a>, StunAttributeError>;
fn next(&mut self) -> Option<Self::Item> {
if self.data.len() == 0 {
return None;
}
// Ensure there are enough bytes left in the stream to parse the next attribute.
if self.data.len() < ATTRIBUTE_TYPE_LENGTH_BYTES {
return Some(Err(StunAttributeError::UnexpectedEndOfStream));
}
// Parse the data and get a slice of the dynamic bytes to return
let data = ...;
// Modify the iterator to have the slice move to the start of the next attribute
self.data = ...;
return Some(Ok(StunAttribute { data }));
}
}
There are a number of things that could go wrong here, and I've included an example in the if statement. If something goes wrong, it's a good indication that the byte stream being parsed is malformed, and thus there is no reason to continue attempting to parse.
On the one hand, I could just leave the code as-is, but I worry that this could create some infinite loops; if the error is ignored next() could be continuously called returning an Err each time. On the other, I could change the iterator so that on a subsequent call to next() after the error None is returned.
Are there guidelines/best practices for what to do as the implementer of the iterator this situation? I know some iterator adapters are aware of iterators that return Result<T, E>, but probably not all.