As I am new to Rust, I have been reading about lifetimes and I am slowly wrapping my head around them, along with shared data using Arc and Mutex. I think that the way I am doing this is the correct approach.
If I understand the error correctly (based on what I have read), it is telling me that the callback may live longer than the variable b
so it throws the error. What I am not sure of, is how do I resolve that error?
Note: AppWindow
, AppMenu
, and AppState
are automatically generated by the slint library. However, their definitions are as follows:
AppWindow
- pub struct AppWindow(VRc<ItemTreeVTable, InnerAppWindow>)
AppMenu
- pub struct AppMenu<'a>(&Pin<Rc<InnerAppMenu>>)
AppState
- pub struct AppState<'a>(&Pin<Rc<InnerAppState>>)
Cargo.toml
[dependencies]
slint = "1.8.0"
use std::sync::Arc;
slint::slint! {
import { Button } from "std-widgets.slint";
export component AppWindow inherits Window {
Button { text: "Example"; }
}
export global AppMenu {
in-out property <bool> is-menu-opened: false;
}
export global AppState {
callback close-tab(bool);
callback active-project-changed(int);
in-out property <int> active-project: 0;
}
}
pub fn do_something(app_state: &AppState) {
app_state.set_active_project(1);
}
fn main() -> Result<(), slint::PlatformError> {
let app_window = Arc::new(AppWindow::new()?);
let a = app_window.clone();
let b = app_window.clone();
let app_menu_original: Arc<AppMenu> = Arc::new(a.global::<AppMenu>());
let app_state_original: Arc<AppState> = Arc::new(b.global::<AppState>()); // error is on this line
/* ... My callbacks to hook into slint ... */
let app_state = app_state_original.clone();
app_state_original.clone().on_active_project_changed(move |index| {
do_something(&app_state);
});
let app_state = app_state_original.clone();
app_state_original.clone().on_close_tab(move |value| {
do_something(&app_state);
});
/* ... The end of the program ... */
app_window.clone().run()?;
Ok(())
}
error[E0597]: `b` does not live long enough
--> packages/app/main.rs:46:52
|
44 | let b = app_window.clone();
| - binding `b` declared here
45 | let app_menu_original: Arc<AppMenu> = Arc::new(a.global::<AppMenu>());
46 | let app_state_original: Arc<AppState> = Arc::new(b.global::<AppState>());
| ^---------------------
| |
| borrowed value does not live long enough
| argument requires that `b` is borrowed for `'static`
...
120 | }
| - `b` dropped here while still borrowed
After looking at the docs, I found that there is a alternative way to access AppSate
, and that is to use AppState::get(&app)
.
So, instead of doing a bunch of Arc::clone()
's of AppState
, in the callback I can use AppState::get(&app)
like this (the get could probably be moved to the do_something()
function):
let app = app_window.clone();
AppState::get(&app_window.clone()).on_active_project_changed(move |index| {
let app_state = AppState::get(&app);
do_something(&app_state);
});
This brings AppSate
within the scope of the callback. The new code now looks like this:
use std::sync::Arc;
slint::slint! {
import { Button } from "std-widgets.slint";
export component AppWindow inherits Window {
Button { text: "Example"; }
}
export global AppMenu {
in-out property <bool> is-menu-opened: false;
}
export global AppState {
callback close-tab(bool);
callback active-project-changed(int);
in-out property <int> active-project: 0;
}
}
pub fn do_something(app_state: &AppState) {
app_state.set_active_project(1);
}
fn main() -> Result<(), slint::PlatformError> {
let app_window = Arc::new(AppWindow::new()?);
/* ... My callbacks to hook into slint ... */
let app = app_window.clone();
AppState::get(&app_window.clone()).on_active_project_changed(move |index| {
let app_state = AppState::get(&app);
do_something(&app_state);
});
let app = app_window.clone();
AppState::get(&app_window.clone()).on_close_tab(move |value| {
let app_state = AppState::get(&app);
do_something(&app_state);
});
/* ... The end of the program ... */
app_window.clone().run()?;
Ok(())
}