I'm trying to increase the structure of a Rust and GTK-RS application, but I cannot figure out how to deal with event connections. I see that the problem is in wrong lifetime, but I do not really understand how it could be fixed.
#[derive(Debug)]
struct CreatingProfileUI {
window: gtk::MessageDialog,
profile_name_entry: gtk::Entry,
add_btn: gtk::Button,
cancel_btn: gtk::Button,
}
#[derive(Debug)]
struct UI {
window: gtk::Window,
// Header
url_entry: gtk::Entry,
open_btn: gtk::Button,
// Body
add_profile_btn: gtk::Button,
remove_profile_btn: gtk::Button,
profiles_textview: gtk::TextView,
// Creating profile
creating_profile: CreatingProfileUI,
// Statusbar
statusbar: gtk::Statusbar,
}
impl UI {
fn init(&self) {
self.add_profile_btn
.connect_clicked(move |_| { &self.creating_profile.window.run(); });
}
}
And I get this error:
error[E0477]: the type `[closure#src/main.rs:109:46: 111:6 self:&UI]` does not fulfill the required lifetime
--> src/main.rs:109:30
|
109 | self.add_profile_btn.connect_clicked(move |_| {
| ^^^^^^^^^^^^^^^
|
= note: type must satisfy the static lifetime
You can't move non-static references into GTK callbacks. You need something static or something heap allocated (e.g. in a Box/RefCell/Rc/etc.).
Callbacks are not called from the scope where you connect to the signal, but at some later point from the main loop. It is required that whatever you pass into the closure is still alive then, which would be anything 'static, heap-allocated or allocated on the stack between main and where the main loop runs. The last part can't currently be nicely expressed with Rust/GTK-rs.
See the example at the bottom in the gtk-rs docs for an example. It uses an Rc<RefCell<_>>.
Related
In my application (a compiler), I'd like to create data cyclic data structures of various kinds throughout my program's execution that all have the same lifetime (in my case, lasting until the end of compilation). In addition,
I don't need to worry about multi-threading
I only need to append information - no need to delete or garbage collect
I only need immutable references to my data
This seemed like a good use case for an Arena, but I saw that this would require passing the arena around to every function in my program, which seemed like a large overhead.
So instead I found a macro called thread_local! that I can use to define global data. Using this, I thought I might be able to define a custom type that wraps an index into the array, and implement Deref on that type:
use std::cell::RefCell;
enum Floop {
CaseA,
CaseB,
CaseC(FloopRef),
CaseD(FloopRef),
CaseE(Vec<FloopRef>),
}
thread_local! {
static FLOOP_ARRAY: RefCell<Vec<Box<Floop>>> = RefCell::new(Vec::new());
}
pub struct FloopRef(usize);
impl std::ops::Deref for FloopRef {
type Target = Floop;
fn deref(&self) -> &Self::Target {
return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
}
}
pub fn main() {
// initialize some data
FLOOP_ARRAY.with(|floops| {
floops.borrow_mut().push(Box::new(Floop::CaseA));
let idx = floops.borrow_mut().len();
floops.borrow_mut().push(Box::new(Floop::CaseC(FloopRef(idx))));
});
}
Unfortunately I run into lifetime errors:
error: lifetime may not live long enough
--> src/main.rs:20:36
|
20 | return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
| ------- ^^^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'2`
| | |
| | return type of closure is &'2 Box<Floop>
| has type `&'1 RefCell<Vec<Box<Floop>>>`
error[E0515]: cannot return value referencing temporary value
--> src/main.rs:20:36
|
20 | return FLOOP_ARRAY.with(|floops| &floops.borrow()[self.0]);
| ^---------------^^^^^^^^
| ||
| |temporary value created here
| returns a value referencing data owned by the current function
What I'd like to tell the compiler is that I promise I'm never going to remove entries from the Array and that I'm not going to share values across threads and that the array will last until the end of the program so that I can in essence just return a &'static reference to a Floop object. But Rust doesn't seem to be convinced this is safe.
Is there any kind of Rust helper library that would let me do something like this? Or are there safety holes even when I guarantee I only append / only use data with a single thread?
If you would have a reference, you could send the data to another thread, then watch it after it has been dropped because the creating thread was finished.
Even if you would solve this problem, this would still require unsafe code, as the compiler can't be convinced that growing the Vec won't invalidate existing references. This is true in this case since you're using Box, but the compiler cannot know that.
If you pinky promise to never touch the data after the creating thread has finished, you can use the following code. Note that this code is technically UB as when the Vec will grow, we will move all Boxes, and at least currently, moving a Box invalidates all references deriven from it:
enum Floop {
CaseA,
CaseB,
CaseC(&'static Floop),
CaseD(&'static Floop),
CaseE(Vec<&'static Floop>),
}
thread_local! {
static FLOOP_ARRAY: RefCell<Vec<Box<Floop>>> = RefCell::new(Vec::new());
}
fn alloc_floop(floop: Floop) -> &'static mut Floop {
FLOOP_ARRAY.with(|floops| {
let mut floops = floops.borrow_mut();
floops.push(Box::new(floop));
let floop = &mut **floops.last_mut().unwrap() as *mut Floop;
// SAFETY: We never access the data after it has been dropped, and we are
// the only who access this `Box` as we access a `Box` only immediately
// after pushing it.
unsafe { &mut *floop }
})
}
fn main() {
let floop_a = alloc_floop(Floop::CaseA);
let floop_b = alloc_floop(Floop::CaseC(floop_a));
}
A better solution would be something like a thread-safe arena that you can use in a static, but sadly, I found no crate that implements that.
The tutorials and examples for gtk-rs are honestly really incomplete and spotty, so I'm trying to piece together how to modify the application's state, as well as the state of some of the child elements, inside a button callback. So, in brief, I have:
// ...
mod imp {
pub struct Window {
#[template_child]
pub headerbar: TemplateChild<gtk::HeaderBar>,
#[template_child]
pub open_button: TemplateChild<gtk::Button>,
// Internal state
pub state: Rc<RefCell<ScribeDownWindowState>>,
}
#[derive(Default)]
pub struct ScribeDownWindowState {
pub project_path: Option<String>,
}
}
In the ObjectImpl for this struct, I have the constructed method, which calls the parent constructed method, then calls setup_callbacks on the parent object, which is the Window type that actually is part of the GTK inheritance hierarchy:
mod imp;
glib::wrapper! {
pub struct Window(ObjectSubclass<imp::Window>)
#extends gtk::ApplicationWindow, gtk::Window, gtk::Widget,
#implements gio::ActionGroup, gio::ActionMap;
}
impl Window {
pub fn new<P: glib::IsA<gtk::Application>>(app: &P) -> Self {
glib::Object::new(&[("application", app)]).expect("Failed to create ScribeDownWindow")
}
fn setup_callbacks(&self) {
let state = self.imp().state;
let headerbar = Rc::new(&self.imp().headerbar);
self.imp().open_button
.connect_clicked(clone!(#strong state, #strong headerbar => move |_| {
let s = state.borrow_mut();
s.project_path = Some("fuck".to_string());
headerbar.set_subtitle(Some("fuck"));
}))
}
}
I need to access both the state and headerbar properties of the imp::Window struct, and modify the project_path property of state and call set_subtitle on the headerbar. I've tried all sorts of variations of this, using all combinations of variables and Rcs and RefCells and I just cannot seem to get past this error (or some permutation of it):
error[E0759]: `self` has an anonymous lifetime `'_` but it needs to satisfy a `'static` lifetime requirement
--> src/scribedown_window/mod.rs:22:39
|
20 | fn setup_callbacks(&self) {
| ----- this data with an anonymous lifetime `'_`...
21 | let state = self.imp().state;
22 | let headerbar = Rc::new(&self.imp().headerbar);
| ---- ^^^
| |
| ...is captured here...
23 | self.imp().open_button.connect_clicked(
| --------------- ...and is required to live as long as `'static` here
There has to be a way to get what I need done done, if you couldn't modify any other interface objects inside a button click callback your UI would be seriously hindered, but I don't see how.
The solution to this problem was to create a struct to hold both the UI state and the application state, like so:
pub struct App {
pub window: crate::scribedown_window::Window,
pub state: State,
pub document_list_model: Option<document_list::Model>,
}
With this struct in hand, you can wrap it in an Rc<RefCell<T>> so that other threads and scopes can access it (just not thread-safely/at the same time, you need a Mutex or Arc for that):
let scribedown = Rc::new(RefCell::new(app::App {
window: win,
state: app::State {
project: None,
open_files: vec![],
},
document_list_model: None,
}));
Now, you can just pass a reference counted pointer to this central state holder to all the callbacks you want, and the callbacks themselves will keep the state alive and keep access to it, while also enforcing a crash if multiple callbacks try to modify the RefCell at the same time. Note that for this to work, all the methods to set up the application's UI callbacks need to be passed the reference counted state variable, scribedown, so they can't be methods of the App struct taking &self, since that would be useless and borrow it. They can be static methods though:
app::App::connect_all(scribedown.clone());
Then, to wire up the callbacks, each callback needs its own pointer to the state to use, and on top of that, since you can't move a cloned reference counted pointer out of the enclosing scope, and you don't want to move the original reference counted pointer out, you need to create an outer RCP to then use to clone the actual RCP for the callback. That ends up looking like this:
// NOTE: the outer pointers to `sd`, formatted like `sd_for_*`, are
// done in order to prevent the callback from borrowing the original
// pointer when it creates its own pointer, which we need to keep free
// to continue making more pointers. This happens because using
// something inside a `move` callback borrows it.
// Connect open button callback
let sd_for_button = sd.clone();
{
let osd = sd.borrow();
let button = &osd.window.imp().open_button;
button.connect_clicked(move |_| {
// Launch dialog in new thread so it doesn't hang this one
gtk::glib::MainContext::default()
.spawn_local(Self::open_project_dialog(Rc::clone(&sd_for_button)));
});
}
I'm not sure this is the "official" or idiomatic solution to this, but I looked at the source code for Fractal (a Matrix messenger client written in Rust with GTK-rs), and they seemed to be using a similar solution.
You can clone self itself for the closure:
fn setup_callbacks(&self) {
self.imp().open_button
.connect_clicked(clone!(#weak self as this => move |_| {
this.imp().state.borrot_mut().project_path = Some("nice".to_string());
this.imp().headerbar.set_subtitle(Some("nice"));
}));
}
What I would like to achieve using the Rust language is to execute a closure or method after X seconds (without waiting for it). Being more used to languages like C#, a simple solution would be to spawn a thread, sleep for X seconds, and execute whatever needs to be done.
I tried this:
fn fire_and_forget(&self) {
thread::spawn(|| {
sleep(Duration::from_secs(10));
self.do_something();
});
}
Obviously, this doesn't work. Depending on my context, I get errors like error[E0277]: cannot be sent between threads safely or error[E0759]: self has an anonymous lifetime '_ but it needs to satisfy a 'static lifetime requirement.
I hope there is solution for this. This "context" I am referring to is quite specific: this fire_and_forget method will be called from the outside so I am not sure I can change its signature with generic lifetimes.
Any idea if there is a solution / workaround / unsafe way for this?
If you check out thread::spawn's signature, you'll see that the closure is required to have a 'static lifetime. This means that it must own all of its data and can not borrow from its environment. This rule exists because there is nothing that guarantees that the parent thread will outlive the newly spawned thread and thus there's no guarantee that any references inside the thread::spawn closure stay valid.
There are a few work-arounds here, although they depend on the structure of self and your program logic. They all boil down to getting owned data in the end and moving that owned data into the closure.
Let's assume you want to capture self's state at the time of calling fire_and_forget and Self: Clone. In that case you can write the following:
let slf = self.clone(); // obtain an owned version of `slf`
thread::spawn(move || { // `move` makes the closure take ownership of `slf`
sleep(Duration::from_secs(10));
slf.do_something() // borrows data from the closure, not the environment
})
If Self doesn't implement Clone or it's not okay to use the old state, you'll need some kind of synchronization / shared access to its current state, e.g. achievable through Arc<Mutex<State>>. Then you'll have to clone the Arc, move it into the closure and call do_something with the shared reference to State.
struct State {
}
struct Foo {
state: Arc<Mutex<State>>,
}
impl Foo {
fn do_something(state: &State) {
}
fn fire_and_forget(&self) {
let owned_state = Arc::clone(&self.state); // obtain an owned version of `state`
thread::spawn(move || { // `move` makes the closure take ownership of `state`
sleep(Duration::from_secs(10));
let state = owned_state.lock().unwrap(); // get exclusive access to state
Self::do_something(&*state) // borrows data from the closure, not the environment
});
}
}
Ultimately the solution will depend on your specific requirements, but as a general rule, a closure can't be 'static if it borrows from its environment.
Appologies if this is very simple. I'm learning rust and getting used to the strange borrowing system. Usually, you can get the desired behavior just by changing the syntax of your method calls, however, in this case, there seems to be now way.
A simplified version of my code is this: EventPump if from SDL.
struct Example {
pump: EventPump
}
impl Example {
fn method(&mut self) {
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
However, I am getting the following error:
error[E0502]: cannot borrow `*self` as immutable because it is also borrowed as mutable
--> src\game.rs:53:67
|
30 | for event in self.pump.poll_iter();
| ---------------------
| |
| mutable borrow occurs here
| mutable borrow later used here
...
53 | self.other_method();
| ^^^^ immutable borrow occurs here
There is probably some proper way to do this so my struct can maintain ownership of itself, but I have not been able to find it.
I have tried the following:
Turn it into a while loop with explicit while let event = iterator.next(), same error
Making the function mutable, the error now says that no two mutable references are allowed either. I guess the entire "immutability" part of the error message is actually irrelevant.
I could perhaps copy the entire contents of the iterable into a vector or such, but that would defeat the purpose of a iterator, and what if the iterator is not finite? There has to be a better way right...
If someone with more rust experience could help me out it would be much appreciated.
If you want an attribute of a struct to be mutable when there is an immutable reference of a struct in the same block, you'll need RefCell. This is called interior mutability.
If an interior mutability of struct Example is desired, then you will need a RefCell.
use sdl2::{EventPump};
struct Example {
pump: RefCell<EventPump> // wrap in RefCell
}
impl Example {
// you have to decide whether you want a mutable or immutable chained methods
// i.e. method and other_method should be of same mutability because
// other method is called in method
fn method(&self) {
// borrow a mutable reference of pump inside a method with immutable self
let mut pump = self.pump.borrow_mut();
for event in pump.poll_iter() {
self.other_method();
}
}
fn other_method(&self) {
}
}
If you have a pattern like that:
fn method(&mut self) {
for item in self.some_iterator_that_borrow_mut() {
self.other_method();
}
}
The borrow rule that states exactly one mutable reference is broken:
there are one mutable and one immutable reference to self.
To avoid the double reference problem consume the iterator and collect the items into
a temporary collection, for example into a Vec:
impl Example {
fn method(&mut self) {
for event in self.pump.poll_iter().collect::<Vec<_>>(); {
self.other_method();
}
}
fn other_method(&self) {}
}
This question already has answers here:
The compiler suggests I add a 'static lifetime because the parameter type may not live long enough, but I don't think that's what I want
(2 answers)
Closed 5 years ago.
I'm working on a toy ray tracer project in Rust and am hung up on a lifetime-related error. I've stripped down my code to the following self-contained failing case:
struct Material {}
pub struct Sphere<'a> {
material: &'a Material,
}
pub trait AnySceneObject {}
impl<'a> AnySceneObject for Sphere<'a> {}
pub struct Scene {
objects: Vec<Box<AnySceneObject>>,
}
fn main() {
let material = Material {};
let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
Scene { objects: vec![boxed_sphere] };
}
which complains
error[E0597]: `material` does not live long enough
--> main.rs:17:74
|
17 | let boxed_sphere: Box<AnySceneObject> = Box::new(Sphere { material: &material });
| ^^^^^^^^ does not live long enough
18 | Scene { objects: vec![boxed_sphere] };
19 | }
| - borrowed value only lives until here
|
= note: borrowed value must be valid for the static lifetime...
error: aborting due to previous error(s)
I want to use traits to define objects in the scene, but I want the Scene object to own them. My current understanding is that this means I need Box or something equivalent because trait objects are of unknown size.
I also want objects to share references to Materials, since there won't be that many of them and though they're relatively simple and Copyable, I don't want literally tens or hundreds of thousands of identical copies of the same thing (hence using &'a Material).
I'm confused why it's problematic to pass &material here though: since values are dropped latest-first, wouldn't Scene be dropped first, allowing boxed_sphere to be dropped (since it now owns a Vec that owns that Box), which it then is, allowing material to be dropped, no problem? It seems like it should live at least as long as the other two values in the function, since I'm holding onto the value with the name material for the scope of the whole function.
Also somewhat confusingly, commenting out the instantiation of Scene fixes the issue for reasons I don't understand.
First of all, if you have hundreds of thousands of scene objects, putting them in a box (which is basically a heap object) is definitely not a good idea.
The error is called because the Box's content must not have any reference that might expire. You can move a Box around and it may never be deleted until the end of the process, so any references it holds must have 'static lifetime.
You can fix it by using Box<T + 'a> to indicate that it will have a limited lifetime:
pub struct Scene<'a> {
objects: Vec<Box<AnySceneObject + 'a>>,
}
You can also use Vec<&Trait> to store a collection of references to different objects implementing a trait. The following code compiles:
pub struct Scene<'a> {
objects: Vec<&'a AnySceneObject>,
}
fn main() {
let material = Material {};
let sphere = Sphere { material: &material };
Scene {
objects: vec![&sphere]
};
}
If you know all possible implementations of your trait, you can replace it with a enum. This would make the code more performant, as you would have a vector owning enums instead of references.