I am making a game in Rust and have a few different trait GameModule
s that are a part of the main App
.
pub struct AppView<'a> {
pub frame_delta: &'a f64,
pub area: &'a Rect
}
pub trait GameModule: WidgetRef {
/// Update the AppComponent before each render.
///
/// Exits app on `Ok(false)` or `Err(_)`.
fn update(&mut self, world: Rc<RefCell<World>>, app_view: &AppView) -> Result<bool>;
/// Handle key events.
///
/// Exits app on `Ok(false)` or `Err(_)`.
fn key_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, key_event: KeyEvent) -> Result<bool>;
/// Handle mouse events. ///
/// Exits app on `Ok(false)` or `Err(_)`.
fn mouse_event(&mut self, world: Rc<RefCell<World>>, app_view: &AppView, mouse_event: MouseEvent) -> Result<bool>;
}
I have a main controller that is an GameModule
and has a list of AppModule
s, called TabWidget
that updates the correct GameModule
. I have an update(&mut self) -> Result<bool>
function in pub struct App
that has
pub fn update(&mut self) -> Result<bool> {
let app_view = AppView {
area: &self.tab_area,
frame_delta: &self.frame_delta,
};
self.tab_widget.update(self.world.clone(), &app_view)
}
This code above works, but I attempted, first to write a function:
pub fn app_view(&self) -> AppView {
AppView {
frame_time: &self.frame_time,
area: &self.tab_area
}
}
When I used this function in App::update(&mut self) -> Result<bool>
, suddenly I encountered a borrowing error.
pub fn update(&mut self) -> Result<bool> {
let app_view = self.app_view();
self.tab_widget.update(self.world.clone(), &app_view)
}
and
pub fn update(&mut self) -> Result<bool> {
self.tab_widget.update(self.world.clone(), &self.app_view)
}
both refused to compile. I think I understand that Rust here is implicitly borrowing self, but App is 'static, and this implementation is for App<'static>, so when I tried:
pub fn app_view(self) -> AppView {
// ...
}
it required that AppView be assigned the static lifetime which didn't seem like it would make sense.
What are the workarounds here? Am I misunderstanding Rust? Why does one work and the other doesn't?
As it turns out, what I am attempting here falls under RFC #1215 but in my case can be simplified by allowing AppView to be constructed from copies of the data passed in, not references. And in the case that later I do require them to be references, for heavier loads, my semantics allow me to just create one AppView and re-use it for all the functions called in that frame.
let's try to replicate it, see rust playground replica
fn update(&mut self) -> Result<bool, String>
{
let app_view = self.app_view();
self.tab_widget.update(self.world.clone(), &app_view);
Ok(true)
}
error[E0502]: cannot borrow `self.tab_widget` as mutable because it is also borrowed as immutable
--> src\main.rs
|
79 | let app_view = self.app_view();
| ---- immutable borrow occurs here
80 | self.tab_widget.update(self.world.clone(), &app_view);
| ^^^^^^^^^^^^^^^^------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | immutable borrow later used by call
| mutable borrow occurs here
the error is clear, self.app_view()
borrows self
completely in app_view
, therefore self.tab_widget.update
cannot borrow the other part (self.tab_widget
) mutably. and you cannot make a function that only borrows a part of a struct, this is a current limitation in rust, see How can multiple parts of self be borrowed here? Isn't self borrowed mutably as well as immutably here?
AppView
is only holding a float and a rectangle that's 2 more floats at most, it can cheaply copy them, it doesn't need to hold references and therefore borrow App
, now the code should compile.
pub struct AppView {
pub frame_delta: f64,
pub area: Rect
}
another way is to construct AppView
inside update
, you are allowed to borrow multiple parts of a struct, you just need all those borrows to be in the same function.
fn update(&mut self) -> Result<bool, String> {
let app_view = AppView{
frame_delta: &self.frame_time,
area: &self.tab_area,
};
self.tab_widget.update(self.world.clone(), &app_view);
Ok(true)
}