Option as_ref autoref

Hi,

I am failing to understand the issue the compiler has with the following setup.

I do not understand, why the as_ref call is relevant to any lifetime, since I am copying all relevant information into "Message", I do not borrow anything from chunk.
I do copy a reference with a longer lifetime than chunk from withing chunk, yes.

pub struct MessageIterator<'a> {
    records: RecordsIterator<'a>,
    chunk: Option<record_types::Chunk<'a>>,
    index_in_chunk: usize
}

impl<'a> std::iter::Iterator for MessageIterator<'a> {
    type Item = Message<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(chunk) = self.chunk.as_ref() { // <-------------- Error is here
                match chunk.iter_msgs().skip(self.index_in_chunk).next() {
                    Some(Ok(m)) => Some(Message { // if this Some is replaced with None, it compiles
                        topic: String::from(""),
                        time: m.time,
                        data: m.data,
                    }),
                    _ => None,
                }
        } else {
            None
        }
    }
}

The compiler error is:

error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
   --> external/rosbag-rs/src/lib.rs:227:41
    |
227 |         if let Some(chunk) = self.chunk.as_ref() {
    |                                         ^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 226:5...
   --> external/rosbag-rs/src/lib.rs:226:5
    |
226 | /     fn next(&mut self) -> Option<Self::Item> {
227 | |         if let Some(chunk) = self.chunk.as_ref() {
228 | |                 match chunk.iter_msgs().skip(self.index_in_chunk).next() {
229 | |                     Some(Ok(m)) => Some(Message {
...   |
250 | |         }
251 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> external/rosbag-rs/src/lib.rs:227:30
    |
227 |         if let Some(chunk) = self.chunk.as_ref() {
    |                              ^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 223:6...
   --> external/rosbag-rs/src/lib.rs:223:6
    |
223 | impl<'a> std::iter::Iterator for MessageIterator<'a> {
    |      ^^
    = note: ...so that the types are compatible:
            expected std::iter::Iterator
               found std::iter::Iterator

I know it's definitely related to the "Message" construction, because when I do not construct a message,
there is no error:

impl<'a> std::iter::Iterator for MessageIterator<'a> {
    type Item = Message<'a>;
    fn next(&mut self) -> Option<Self::Item> {
        if let Some(chunk) = self.chunk.as_ref() {
                match chunk.iter_msgs().skip(self.index_in_chunk).next() {
                    Some(Ok(m)) => None
                    _ => None,
                }
        } else {
            None
        }
    }
}

This is what "Message" is:

pub struct Message<'a> {
    pub topic: String,
    pub time: u64,
    pub data: &'a [u8],
}

If I read Cow and rosbag's documentations correctly when you create an iterator with iter_msgs its lifetime is tied to the lifetime it originated from, in this case chunk. And chunk is only valid within the if let block.

So in the end the compiler won't let you return something with a lifetime inside next.
If what I'm saying is correct this function is the origin of your issue because of how AsRef is implemented for Cow.

1 Like

To fix this you will need to copy out data into a Vec<u8> or something similar so that it isn't tied to the lifetime of the message in the chunk. (i.e. remove the lifetime annotation on Message)

Thank you guys!
I wasn’t interpreting the error message correctly.
Or I could make Chunk have an Rc instead of the Cow, right?

Yes, as long as it get's rid of the lifetime annotation it should work.

2 Likes