How do you copy a pointer or reference whenever you know it is safe?

I am trying to create an entity struct that allows you to pass a boxed function to it. I'm having an issue though where it doesn't allow me to have to mutable references to the struct.

This code, to my knowledge, is safe.

type Lambda = Box<dyn Fn(&mut Entity)>;
pub struct Entity {
    pub location: Vec3,
    pub rotation: Vec3,
    pub scale   : Vec3,
    pub render  : Lambda
}

impl Entity {

    pub fn new(location: Vec3, rotation: Vec3, scale: Vec3, render: Lambda) -> Self {
        Self{location: location, rotation: rotation, scale: scale, render: render }
    }

    pub fn get_transform(&self) -> Matrix {
        Matrix::transform(&self.location, &self.rotation, &self.scale)
    }

    pub fn render(&mut self) {
        let f = &mut self.render;
       // This is the code that throws the error.
        f(self);
    }

How can you fix this?

The problem is that the self.render field could be mutated or even destroyed during the f(self) call, which would leave f as a dangling reference.

One way to solve this is by moving the Lambda out of the Entity before calling it, and then moving it back in afterward:

impl Entity {
    pub fn render(&mut self) {
        use std::mem::replace;
        
        let temp: Lambda = Box::new(|_| {});
        let f = replace(&mut self.render, temp);
        f(self);
        self.render = f;
    }
}

Or you could pass the Lambda some arguments that do not include a way for it to mutate itself. For example, you could pass it each of the other fields as a separate argument. Or you could gather the other fields into a sub-struct.

3 Likes

Thanks for the reply. I think i'm going to go with your second idea (about creating a second struct for the other data). This really helps a lot. Thanks again.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.