Field lifetime in a struct and function taking &mut self

Hi!

I am a beginner and first time poster here trying to encapsulate a quick_xml parser thus:

use quick_xml::{events::Event, Reader};
use std::io::BufRead;

struct QuickXmlHelper<'a, T: BufRead> {
    reader: Reader<T>,
    buf: Vec<u8>,
    current: Option<Event<'a>>,
}

impl<'a, T: BufRead> QuickXmlHelper<'a, T> {
    pub fn next(&mut self) -> Result<()> {
        self.buf.clear();
        self.current.replace(self.reader.read_event(&mut self.buf)?);
        Ok(())
    }

    // more functions which make this actually useful omitted
}

Unfortunately this leads to a compiler error:

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
  --> src\main.rs:14:53
   |
14 |         self.current.replace(self.reader.read_event(&mut self.buf)?);
   |                                                     ^^^^^^^^^^^^^
   |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 12:5...
  --> src\main.rs:12:5
   |
12 |     pub fn next(&mut self) -> Result<()> {
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
note: ...so that reference does not outlive borrowed content
  --> src\main.rs:14:53
   |
14 |         self.current.replace(self.reader.read_event(&mut self.buf)?);
   |                                                     ^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 11:6...
  --> src\main.rs:11:6
   |
11 | impl<'a, T: BufRead> QuickXmlHelper<'a, T> {
   |      ^^
note: ...so that the expression is assignable
  --> src\main.rs:14:30
   |
14 |         self.current.replace(self.reader.read_event(&mut self.buf)?);
   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: expected `Event<'a>`
              found `Event<'_>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `lifetime-test`

The Event returned by reader.read_event() references the passed vector. I want to store the returned event in the same struct. I cannot make the fn take &'a mut self because then I can't call it twice.

Is there a way to make this work?

Thanks for your help!

-- Count Count

The problem is that current has a lifetime annotation, which means "this field contains references that point outside the struct", but actually the references point to buf, which is inside the struct.

This is called a self-referential struct, i.e. a struct where one field borrows from another. These are not possible to write in safe Rust.

Try to rewrite your code to not do this. For example, you might try this:

use quick_xml::{events::Event, Reader};
use std::io::BufRead;

struct QuickXmlHelper<T> {
    reader: Reader<T>,
    buf: Vec<u8>,
}

struct QuickXmlNext<'a> {
    current: Event<'a>,
}

impl<T: BufRead> QuickXmlHelper<T> {
    pub fn next(&mut self) -> Result<QuickXmlNext<'a>> {
        self.buf.clear();
        Ok(QuickXmlNext { current: self.reader.read_event(&mut self.buf)? })
    }
}
3 Likes

Thanks so much. After reading up on self-referential structs in Rust that makes total sense.