Lifetimes bubbling up

So, I'm new to Rust and I'm facing this problem for weeks, since the beginning I guess. I've always thought a good way to learn a language is by making a simple game with it, so here I am. I've tried both with SDL2 and with SFML bindings, and with both I end up having the same problem: When you create a sprite, you pass it a texture, and the texture lifetime cannot be smaller than the sprite (otherwise you'd have a sprite displaying garbage).

So, at some point in my code, I end up creating an instance of an struct that requires an explicit lifetime. And in order to make it work, this explicit lifetime ends up being used all over the place, until it reaches main, where you get the error that you can only mutably borrow once.

In case of SFML, the problem comes in Sprite::setTexture (sfml::graphics::Sprite - Rust), where I have to pass a texture with an explicit lifetime, and this is the lifetime which ends up bubbling up everywhere.

How should I approach this problem? I can provide some example code that doesn't compile (the error is cannot infer an appropriate lifetime for autoref due to conflicting requirements)

Thanks in advance,

--
Dani

By accepting a lifetime-bounded reference, the library is requiring you to structure your code so that the compiler can prove that the Sprite is destroyed before the Texture. In the simplest case, this means you can have all your textures owned by main, which provides references into the game loop function. When the game is over, control returns to main() which then cleans up the textures.

Alternatively, you can create and destroy the Sprite structures every frame. This adds some complexity to the main game loop, but lets you use a more flexible strategy for managing the texture data.

The complete hack of a solution is to use Box::leak() to never clean up the textures, and just rely on the OS doing that for you at program exit. That’ll give you ’static references, so you can dispense with the lifetimes altogether.

2 Likes

Creating and destroying textures at every frame won't be very performant I guess. For now I'm using ResourceManager, as in

https://github.com/Rust-SDL2/rust-sdl2/blob/master/examples/resource-manager.rs

But to be honest, I cannot understand how it solves the lifetimes issue.

Not a solution to your issue, but just some thoughts:

I think to a degree, these issues are just a consequence of trying to make those existing C APIs fit in with Rust. The lifetimes are awkward because the underlying code was not written with this kind of memory management in mind, but removing them would make the code completely unsafe.

Most Rust-based game frameworks (that I've seen, at least) use reference counting instead of explicit lifetimes to manage textures and other assets that need to be freed. This makes using them feel a lot more like you might expect coming from other languages (i.e. cheap to clone, cleaned up automatically when no longer used).

If your goal is 'learn the language/learn to make a game' rather than specifically 'learn to use SFML/SDL in Rust', I would recommend trying one of those frameworks instead - there's a good rundown here with some code examples (disclaimer: I wrote Tetra, which is mentioned in the list).

Thanks a lot, I didn't know that article, looks very interesting, and it's good to know that this is not a common problem :slight_smile:

1 Like

Unless you're doing something quite advanced, I don't think there's a ton of situations where you'll have to deal with long-lived structs with lifetime annotations in Rust (for exactly the reasons you've stated already - they can quite awkward to work with).

It's much more common to use them when you're making a short-lived 'view' into another piece of data - e.g. if you were writing a parser and you wanted a Token struct/enum to hold a reference into the input, plus some extra metadata.

In other words, hopefully this doesn't colour your first impressions of Rust too much :slight_smile:

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.