I'm creating a game of 2048 with a UI using Slint. I have a ownership (?) issue when I have 2 different actions that can modify my game. They cannot be called at the same time (but the compiler does not know that). I don't find this kind of issue on the documentation.
mod board;
use board::Board;
use slint::{ModelRc, SharedString, Weak};
slint::include_modules!();
fn update_app(ui: AppWindow, game: &Board) {
...
}
fn main() -> Result<(), slint::PlatformError> {
let mut game = Board::new(32);
let ui = AppWindow::new()?;
let ui_handle = ui.as_weak();
update_app(ui_handle.unwrap(), &game);
ui.on_restart(move |seed| {
println!("Restarting with seed: {}", seed);
game.restart(seed.parse().unwrap()); // if commented, OK
update_app(ui_handle.unwrap(), &game); // if commented, OK
});
ui.on_play(move |direction| { // otherwise error here: use of moved value: `game` value used here after move
println!("Playing with direction: {:?}", direction);
game.apply_action(direction as u8);
update_app(ui_handle.unwrap(), &game);
});
ui.run()
}
What is the standard approach for this kind of problem? ChatGPT proposed to use a "Reference Counted" but I could not make it work.
The solution has been found using a Reference Counted for the game and duplicate the weak references to the ui (1 per action)
mod board;
use std::{cell::RefCell, rc::Rc};
use board::Board;
use slint::{ModelRc, SharedString};
slint::include_modules!();
fn update_app(ui: AppWindow, game: Rc<RefCell<Board>>) {
...
}
fn main() -> Result<(), slint::PlatformError> {
let game = Rc::new(RefCell::new(Board::new(32)));
let ui = AppWindow::new()?;
let ui_handle = ui.as_weak();
let ui_handle_on_play = ui.as_weak();
let ui_handle_on_restart = ui.as_weak();
let game_on_restart = Rc::clone(&game);
let game_on_play = Rc::clone(&game);
ui.on_restart(move |seed| {
game_on_restart.borrow_mut().restart(seed.parse().unwrap());
update_app(game_on_restart.unwrap(), Rc::clone(&game_on_restart));
});
ui.on_play(move |direction| {
game_on_play.borrow_mut().apply_action(direction as u8);
update_app(ui_handle_on_play.unwrap(), Rc::clone(&game_on_play));
});
// setup and run the UI
update_app(ui_handle1.unwrap(), Rc::clone(&game));
ui.run()?;
Ok(())
}