Reputation: 23
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?
Upvotes: 1
Views: 1270
Reputation: 98398
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()
}
}
Upvotes: 1