0

In the process of an entity-component system, I'm having this issue where I want all my objects in my scene to be able to use methods on the scene as mutable. However, I don't think keeping a reference to the scene is a good idea, as the scene is the structure containing the objects (so it would make a cycling reference), and I can't have multiple mutables references.

The idea that i got is that my objects have a function that borrows the scene : each time I want to do something on the scene from my object, I borrow the scene and then drop the borrow.

This is what I tried so far :

This is my Scene structure

pub struct GameScene {
    // array of all objects
    objects: Vec<GearObject>,
    components: ComponentTable,
}

And there is my object :

pub struct GearObject<'o, 's:'o> {
    transform: Transform,
    id: u32,
    get_scene: &'o dyn Fn() -> &'s mut GameScene,
}

impl<'s:'o, 'o> GearObject<'o, 's> {
    pub fn empty(id: u32, scene_borrow: &'s mut GameScene) -> GearObject<'o, 's> {
        // creates an empty gearObject
        return GearObject {
            id: id,
            transform: Transform::origin(),
            get_scene: &|| scene_borrow,
        };
    }
}

The idea was that my 'get_scene' would be a function that could borrow the scene However, I'm not sure if I'm doing this correctly, the code doesn't even compile ("cannot infer an appropriate lifetime for lifetime parameter 's due to conflicting requirements")

Does this keeps a reference to my scene, or is it doing what I was expecting, only borrowing the scene when called? Also, Why do I have a lifetime issue here ? am I not guaranting that my scene lives longer than my function to get it ?

  • 1
    No, this can't work as you have it written. Simply, it doesn't solve your problem -- your `get_scene` field might as well be `&'a mut GameScene`, because the closure you're creating extends the borrow of the `scene_borrow` argument. Further, you can't borrow a temporary closure if it captures from the environment. You'd need an owned closure, like `Box &'s mut GameScene>` but that would still extend the borrow of `scene_borrow`. – cdhowie Apr 27 '22 at 08:13
  • Even if you solve that, you effectively have a self-referential structure -- `GameScene` owns `GearObject` values, which have a reference back to `GameScene` (obscured by the closure right now) and [Rust doesn't like that](https://stackoverflow.com/q/32300132/501250) because if the `GameScene` value is moved in memory, the references it holds to itself become invalidated. – cdhowie Apr 27 '22 at 08:17
  • @cdhowie alright, so it won't work. Are there any ways for my GearObject to borrow the scene ? – LucioleMaléfique Apr 27 '22 at 08:35
  • `Rc>` or `Arc>` or change your function prototypes so that each function that wants to use the scene has a `&mut GameScene` parameter. – Jmb Apr 27 '22 at 10:01
  • `Rc`/`Arc` can work, but you'll have a reference cycle. The `GearObject` values should be given weak references, otherwise you'll have to manually empty `GameScene.objects` to avoid a memory leak. – cdhowie Apr 27 '22 at 20:04
  • Agree that if you really want to have that reference, it must be a `Weak` reference. – Finomnis Apr 27 '22 at 21:45

0 Answers0