I'm going in circles trying to figure out how to properly manage the setup of textures. I'm using https://github.com/Rust-SDL2/rust-sdl2/. I've tired to extract out a minimal example from my whole codebase, so hopefully I haven't missed any details in the translation. This is a simple game FYI.
What I'm trying to do is store a TextureCreator
[1] and Texture
[2] in the same
struct. What's happening here is SDL makes TextureCreator
the owner of every Texture
created with it, which means I have to use explicit lifetimes. I've got it setup so that I
can create a new Engine
instance with the 'a
lifetime for the ResMan
struct. But as
soon as I define and call the res_man.load_texture
method, things go bonkers and I
haven't been able to figure out how to properly do it in a way the borrowchecker doesn't
make me run around in circles. You will notice I used a RefCell
to try and attempt to
fix it, but the borrowchecker seems to want some explicit lifetimes specified in the
load_texture function.
I'm open to scrapping all of this for something more rustic if you can enlighten me.
use std::cell::RefCell;
use std::collections::HashMap;
use sdl2::image::{LoadTexture};
use sdl2::render::{Canvas, Texture, TextureCreator};
use sdl2::video::{Window, WindowContext};
use sdl2::{Sdl, VideoSubsystem};
const BLOCK_TEXTURE_PATH: &str = "../assets/block.png";
fn main() {
let engine = Engine::new();
engine.start();
}
pub struct ResMan<'a> {
texture_creator: RefCell<TextureCreator<WindowContext>>,
res_map: HashMap<&'static str, Texture<'a>>,
}
impl<'a> ResMan<'a> {
pub fn new(canvas: &Canvas<Window>) -> ResMan<'a> {
ResMan {
texture_creator: RefCell::new(canvas.texture_creator()),
res_map: HashMap::with_capacity(10),
}
}
// here's horrible code that's on fire,
pub fn load_texture(&self, path: &'static str) {
let texture_creator = self.texture_creator.borrow_mut();
let block_texture = texture_creator.load_texture(path).unwrap();
self.res_map.insert(path, block_texture);
}
}
pub struct Engine<'a> {
sdl_context: Sdl,
video_subsystem: VideoSubsystem,
canvas: Canvas<Window>,
res_man: ResMan<'a>,
}
impl<'a> Engine<'a> {
pub fn new() -> Engine<'a> {
let sdl_context = sdl2::init().unwrap();
let video_subsystem = sdl_context.video().unwrap();
let window = Engine::open_window(&video_subsystem).unwrap();
let canvas = Engine::create_canvas(window).unwrap();
let mut res_man = ResMan::new(&canvas);
res_man.load_texture(BLOCK_TEXTURE_PATH);
Engine {
sdl_context,
video_subsystem,
canvas,
res_man,
}
}
fn open_window(video_subsystem: &VideoSubsystem) -> Result<Window, String> {
video_subsystem
.window("rust-sdl2 demo", 10 * 32, 20 * 32)
.position_centered()
.build()
.map_err(|e| e.to_string())
}
fn create_canvas(window: Window) -> Result<Canvas<Window>, String> {
window
.into_canvas()
.accelerated()
.build()
.map_err(|e| e.to_string())
}
pub fn start(&self) {
// main loop
}
}
1: https://docs.rs/sdl2/0.32.2/sdl2/render/struct.TextureCreator.html
2: https://docs.rs/sdl2/0.32.2/sdl2/render/struct.Texture.html
Error message,
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/main.rs:31:52
|
31 | let texture_creator = self.texture_creator.borrow_mut();
| ^^^^^^^^^^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:5...
--> src/main.rs:30:5
|
30 | / pub fn load_texture(&self, path: &'static str) {
31 | | let texture_creator = self.texture_creator.borrow_mut();
32 | | let block_texture = texture_creator.load_texture(path).unwrap();
33 | | self.res_map.insert(path, block_texture);
34 | | }
| |_____^
note: ...so that reference does not outlive borrowed content
--> src/main.rs:31:31
|
31 | let texture_creator = self.texture_creator.borrow_mut();
| ^^^^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 21:6...
--> src/main.rs:21:6
|
21 | impl<'a> ResMan<'a> {
| ^^
= note: ...so that the expression is assignable:
expected sdl2::render::Texture<'a>
found sdl2::render::Texture<'_>
error: aborting due to previous error
error: Could not compile `ffs`.