Rust SDL2 - help with lifetimes


#1

In Rust SDL2 I need to create a texture. The way to do this is to get a TextureCreator from a Window and then use TextureCreator to create the textures. The TextureCreator lives independently from its Window.
However the Texture must not outlive the TextureCreator. I don’t know how to encapsulate this in a struct so that the compiler knows that.

(compiled with stable 1.18)

I’ve put this all into a gist and pasted below.

Thanks in advance.

P

extern crate sdl2;

use sdl2::video;
use sdl2::render;
use sdl2::video::Window;
use sdl2::video::WindowContext;
use sdl2::render::Canvas;
use sdl2::render::TextureCreator;
use sdl2::render::Texture;

struct Thing<'a> {
    texture_creator: TextureCreator<WindowContext>,
    texture: Texture<'a>,
}

impl<'a> Thing<'a> {
    pub fn new(c: &Canvas<Window>) -> Thing<'a> {
        let tc = c.texture_creator();
        let tex = tc.create_texture_streaming(None, 128, 128).unwrap();
        Thing {
            texture_creator: tc,
            texture: tex,
        }
    }
}

fn main() {
    let sdl = sdl2::init().unwrap();
    let sdl_video = sdl.video().unwrap();
    let win = sdl_video.window("Test", 320, 240).build().unwrap();
    let canvas = win.into_canvas().build().unwrap();
    let thing = Thing::new(&canvas);
    println!("It's your {:?}", thing.texture.query());
}

Error:

error[E0597]: `tc` does not live long enough
  --> main.rs:19:19
   |
19 |         let tex = tc.create_texture_streaming(None, 128, 128).unwrap();
   |                   ^^ does not live long enough
...
24 |     }
   |     - borrowed value only lives until here
   |
note: borrowed value must be valid for the lifetime 'a as defined on the impl at 16:1...
  --> main.rs:16:1
   |
16 | / impl<'a> Thing<'a> {
17 | |     pub fn new(c: &Canvas<Window>) -> Thing<'a> {
18 | |         let tc = c.texture_creator();
19 | |         let tex = tc.create_texture_streaming(None, 128, 128).unwrap();
...  |
24 | |     }
25 | | }
   | |_^

#2

The problem here is that you’re essentially trying to create a self-referential struct. The TextureCreator returns a reference to a Texture, which means the texture’s lifetime is dependent on the texture creator’s (as you’ve also mentioned). Then you move the texture creator and the texture reference into the Thing. At this point, the original texture creator, tc, is gone - it’s been moved into Thing, and resides at a different (stack) address (ignore possible compiler optimizations). Your texture reference, then, would be pointing at invalid memory. That’s the gist of the issue the compiler is preventing.

Is it possible for Thing to hold just a refererence to texture creator (and texture)?

There are some crates, like rental and owning_ref, that aim to faciliate such self referential structs, so perhaps take a look at them if you can’t (or don’t want to) restructure your code.


#3

Thanks vitalyd,
I think I understand the issue now. I’ll try and restructure the code. It is only a ‘learning rust’ project - it did work OK with a previous version of rust-sdl2 until they changed the way that textures are created.


#4

Hi Pedro, did you solve this issue finally ? I am facing the exact same issue, programmming a function that returns a texture AND its texture_creator, the compiler complains that texture_creator does not live long enough (even if I am moving it by returning it at the end of the function…).