1

There are several questions on SO asking this same thing:
Is there a way to store a texture inside a struct using rust-sdl2?
Managing SDL2 (rust) Texture lifetime

And these were supposedly answered in:
Cannot infer an appropriate lifetime for autoref due to conflicting requirements
Why can't I store a value and a reference to that value in the same struct?

I also looked at the examples in the rust-sdl2 repo, but I still can't figure this out.

My goal is to have a struct that holds a canvas and a texture so I can repeatedly update the texture with new pixel data from a streaming camera. I got this to work but I was creating a new texture in every loop iteration which didn't seem right and also caused a memory leak. So I decided to hold the texture in a struct and just update it on every call to draw. This seemed like the right thing to do, but rust-sdl makes this seemingly impossible due to lifetime constraints on Texture. I followed the compiler suggestions about adding lifetimes and what not, but now I'm stuck. Here's what I have so far:

use sdl2::pixels::PixelFormatEnum;
use sdl2::render::{Canvas, Texture, TextureCreator};
use sdl2::video::{Window, WindowContext};


pub struct View<'tex> {
    canvas: Canvas<Window>,
    texture: &'tex Texture<'tex>,
}

impl<'tex> View<'tex> {
    fn new(width: u32, height: u32) -> Self {
        let sdl_context = sdl2::init().unwrap();
        let subsystem = sdl_context.video().unwrap();

        let window = subsystem
            .window("sdl2 - test", width, height)
            .position_centered()
            .build()
            .unwrap();

        let canvas = window.into_canvas().build().unwrap();
        let texture_creator: &'tex TextureCreator<WindowContext> = &canvas.texture_creator();
        let texture: &'tex Texture = &texture_creator
            .create_texture_streaming(PixelFormatEnum::ARGB8888, width as u32, width as u32)
            .map_err(|e| e.to_string()).unwrap();

        Self {
            canvas,
            texture,
        }
    }
}

fn main() {
    let view = View::new(500, 500);
}

But I am stuck at this error:

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:23:69
   |
11 | impl<'tex> View<'tex> {
   |      ---- lifetime `'tex` defined here
...
23 |         let texture_creator: &'tex TextureCreator<WindowContext> = &canvas.texture_creator();
   |                              -----------------------------------    ^^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use
   |                              |
   |                              type annotation requires that borrow lasts for `'tex`
...
32 |     }
   |     - temporary value is freed at the end of this statement

I also thought about creating the canvas and the texture in main and passing them to new so that they &'static lifetime, but that goes down another rabbit hole where I need to also create the window in main and pretty much negates any kind of abstraction I was attempting.

How do I store a reference to the Texture so I can avoid repeatedly allocating it?

noel
  • 2,257
  • 3
  • 24
  • 39
  • 1
    The issue is that `Texture` references the data held within the `TextureCreator` (that's what the lifetime represents), so you cannot drop the latter while holding onto the former. However, if you try and store them both in the same struct, you're likely to run into issues due to it being self-referential. I don't think this part of the sdl2-rs API is very well designed, personally. – Joe Clay Dec 13 '22 at 09:15

0 Answers0