rustcellgame-developmentbevy

Is using a function to manipulate a Cell<T> a code smell in Rust?


I've spent some time developing a new project in rust.

I have a problem understanding whether I am using a Cell in the right way. This is my current problem, generalized.

I need access to a struct World, which has ownership over some Resources. In particular I need (mut) references to the resources. The problem arises when I need mutable access to a resource (requiring &mut World) and a non-mut reference (requiring &World). I cant get such references together as I would violate Rust's reference rules.

The way I'd like to tackle this is by using a Cell. I have this code in my project:

    fn take_world(&self, func: impl FnOnce(World) -> World) {
        let state = self.state_ref();
        let world = state.world
            .take();

        let world = func(world);
        state.world
            .replace(world);
    }

This should let me take the World from the cell, do what I need with the FnOnce, and the automatically replace it.

Do you think this is a good approach? Could it be considered a code smell?

Other solutions might include code refactor, but the World/Resource part come from a library so I cant do much about it.


Solution

  • This is not a code smell by itself.

    Cell is designed to provide interior mutability with no memory overhead, but it does so by disallowing referential access to its contents and can't be used across threads. So effectively you can only get and set the value in a Cell by transferring ownership (or Copy-ing). So not only is this not a code smell, it is pretty much the only way to update a value in a Cell based on its previous value. Wrapping it up in a function is just a natural extension. There is even the soon-to-be-stabilized .update() method that roughly does this for you (though it relies on Copy instead of filling in a Default).

    Whether using Cell for manipulating your World is a code-smell or not would depend on the rest of your design and strays into being opinion-based. You've tagged Bevy, which provides a variety of ways to work with entities & components so I feel there's likely a way to do what you want to do without interior mutability, but that is just speculation.