Hi,
I'm new to Rust and while I think I understand lifetimes more or less, I'm really struggling with a case I have in my application.
I'm trying to implement a relatively simple UI using Rust and SDL2. SDL2 provides a Texture
struct that implements Drop
trait. A single Texture
is shared by multiple Sprite
structs that represent a part of the whole texture. I need the texture to be mutable, so I don't pass it as an ordinary reference, I use Rc<RefCell<Texture<'a>>>
instead. I keep all the Sprite
structs within a SpriteCollection
. Finally, a Widget
struct, representing buttons and other drawable UI elements, is created while being passed a reference to SpriteCollection
so it can access sprites. Simplified code looks like this:
use core::marker::PhantomData;
use std::rc::Rc;
use std::cell::RefCell;
// external library, I can't change this
struct Texture<'a> {
state: i32,
_marker: PhantomData<&'a ()>
}
impl<'a> Drop for Texture<'a> {
fn drop(&mut self) {}
}
// end of external library
struct Sprite<'a> {
texture: Rc<RefCell<Texture<'a>>>
}
struct SpriteCollection<'a> {
sprites: Vec<Sprite<'a>>
}
impl<'a> SpriteCollection<'a> {
fn new(texture: Texture<'a>) -> Self {
let texture = Rc::new(RefCell::new(texture));
let sprite = Sprite { texture: texture.clone() };
let sprites = vec![sprite];
SpriteCollection { sprites }
}
fn sprite(&self, i: i32) -> &Sprite<'a> {
&self.sprites[i as usize]
}
}
struct Widget<'a> {
sprite: &'a Sprite<'a>
}
impl<'a> Widget<'a> {
fn new(sprite_collection: &'a SpriteCollection<'a>) -> Self {
Widget { sprite: sprite_collection.sprite(0) }
}
}
fn main() {
let texture = Texture { state: 0, _marker: PhantomData };
let sprite_collection = SpriteCollection::new(texture);
let _widget = Widget::new(&sprite_collection);
}
When I try to compile the above I get the error:
error[E0597]: `sprite_collection` does not live long enough
--> src/main.rs:50:31
|
50 | let _widget = Widget::new(&sprite_collection);
| ^^^^^^^^^^^^^^^^^^ borrowed value does not live long enough
51 | }
| -
| |
| `sprite_collection` dropped here while still borrowed
| borrow might be used here, when `sprite_collection` is dropped and runs the destructor for type `SpriteCollection<'_>`
I suppose this is caused by a drop check. But I don't understand why it happens - compiler's message suggests that some code may access sprite_collection
after it's dropped, but I don't see how. If I remove the Drop
trait from Texture
, the above snippet compiles, but I can't do this in actual application.
I'd really appreciate it if anyone could explain the problem, so that I can work around it.
Snippet can be found here: