Life time on nested Self

I'm trying to create a nice api for temporarily using a different context on a struct.

I have a struct called Parser that has a run method that in turn will run other methods, but theses other methods may require a different "context" that should be reset after the method is ran.

What I'm trying to achieve is something like this:

impl Parser {
    fn run(&mut self) -> Result<Something> {
        let t = self.read();
        match t {
            SomeThing => self.run2(),
            OtherThing => self.with_context().run2(),
        }
    }
}

Where with_context creates a new instance of Self, but with a different context.
Like:

fn with_context(&mut self) -> Self {
    Self {
         ctx: SomeContext::new(),
         data: &mut self.data,
    }
}

The goal of course is to avoid having to remember cleanup if it would be done like this:

let old_context = self.get_context();
self.set_context(NewContext::new());
self.run2();
self.set_context(old_context);

But I'm stuck because the data is borrowed so the struct have life time parameters, and I don't understand how to lifetime the with_cctx method:

struct Parser<'a> {
    ctx: Option<Context>,
    data: &'a mut Cursor<&'a str>,
}

impl <'a> Parser<'a> {
    fn with_ctx<'b>(&'b mut self) -> Parser {
        Parser {
            ctx: Some(Ctx1),
            data: &mut self.data,
        }
    }
}

I think it should work, because the new parser with context will live shorter than the parent parser. But I get this error:

cannot infer an appropriate lifetime for lifetime parameter 'a due to conflicting requirements

  1. first, the lifetime cannot outlive the anonymous lifetime defined on the method body at (the with_ctx function block)
  2. but, the lifetime must be valid for the lifetime 'a as defined on the impl...

How to I explain to rust that I'm returning a Self instance that will live shorter than the Self instance I'm currently inside?

Here is a full example:

This is almost always wrong. The reason is simple: by writing this, you essentially tell the compiler "I'd like to borrow this Cursor exclusively for as long as the reference inside it is alive", so the Cursor itself becomes unusable forever. You probably want to split the references, i.e. make it &'a mut Cursor<&'b str>.

3 Likes

Agh! That solved it, thanks!

struct Parser<'a, 'b> {
    ctx: Option<Context>,
    data: &'a mut Cursor<&'b str>,
}

impl <'a, 'b> Parser<'a, 'b> {
    fn new(data: &'a mut Cursor<&'b str>) -> Self {
        Parser {
            ctx: None,
            data,
        }
    }

    fn with_ctx(&mut self) -> Parser<'_, 'b> {
        Parser {
            ctx: Some(Ctx1),
            data: &mut self.data,
        }
    }

Here is a working playground:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.