'Do iterators define semantics for what `next()` should return after an error?

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.



Solution 1:[1]

You could register a separate mapping for the base class. It is really strange that you have to do that, though. I use AutoMapper for mapping and haven't seen a quirk like this. This quirk kind of defeats the point of inheritance and seems like a bug in the utility.

BsonClassMap.RegisterClassMap<BaseEntity>(cm => {
    cm.AutoMap();
    cm.SetIgnoreExtraElements(true);
    cm.MapMember(x => x.Id).SetElementName("ProductID").SetSerializer(new StringSerializerFromInt());
    //...
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 John Glenn