1

For a project I'm using a library in Rust which has the following structs & traits:

struct Server<C> {
    c: C,
}

impl<C: Customization> Server<C> {
    type R<'s> = ResultImpl<'s, C> where Self: 's;

    fn query<'s>(&mut self) -> Self::R<'_> {
        ResultImpl(self)
    }
}

trait Customization {}

struct CustomizationImpl<'c> {
    reference: &'c Foo,
}

struct Foo {}

impl Customization for CustomizationImpl<'_> {}

trait Result {}

struct ResultImpl<'s, C: Customization>(&'s mut Server<C>);

impl<'s, C: Customization> Result for ResultImpl<'s, C> {}

I know, it seems a bit odd that a Result holds a reference to a Server, but let's assume we can't change the code.

Now I want a wrapper around the Server struct. What I tried was the following:

struct Wrapper<'w> {
    server: Server<CustomizationImpl<'w>>,
}

impl<'w> Wrapper<'w> {
    fn query(&'w mut self) -> ResultImpl<'_, CustomizationImpl> {
        self.server.query()
    }
}

But then, I can't call query() more than once on Wrapper.

//compiles
let mut server = Server {
    c: CustomizationImpl { reference: &Foo {} }
};
server.query();
server.query();
    
//does not compile
let mut wrapper = Wrapper {
    server: Server { c: CustomizationImpl { reference: &Foo {} } },
};
wrapper.query();
wrapper.query();

With error error[E0499]: cannot borrow wrapper as mutable more than once at a time. You can also find my code at https://play.rust-lang.org/?version=nightly&mode=debug&edition=2021&gist=eebfd28e33f5354ffe9b46ff121f5f89

Is there any way to wrap the Server struct?

2
  • Just remove the 'w from &'w mut self in query(). Commented Dec 15, 2022 at 22:18
  • If I do so, I'll get another error: error: lifetime may not live long enough Commented Dec 15, 2022 at 23:15

1 Answer 1

1

Your Wrapper lifetime declarations are wrong. Your code is actually equivalent to this one:

impl<'w> Wrapper<'w> {
    fn query(&'w mut self) -> ResultImpl<'w, CustomizationImpl<'w>> {
        self.server.query()
    }
}

But the two lifetimes in the output type should be unrelated. And creating a value of a type such as &'x Type<'x> is known to cause issues such as yours.

The solution is something like this, having the lifetime of self and that of the generic separated:

impl<'w> Wrapper<'w> {
    fn query<'s>(&'s mut self) -> ResultImpl<'s, CustomizationImpl<'w>> {
        self.server.query()
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

A nitpick: &'x Type<'x> is usually fine (it is not very different from using the same lifetime for two different & references); it is only the mutable version &'x mut Type<'x> that causes trouble (because &mut T is invariant in T).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.