Skip to content

add_method_mut does 2 different kinds of mutation #691

@vanyle

Description

@vanyle

Context:

I was implementing a Lua API using mlua and ran into the RecursiveMutCallback error.
This is because I want to call a method defined with add_method_mut recursively.

My code is traversing a tree and mutating the nodes along the way.

There is the issue: for my implementation, I do not need to mutate state, so the FnMut trait on add_method_mut is not needed for me. However, I do need mutable access to the object on which the method is called, so add_method is not an option.

Basically, I would need an API like this:

fn add_method_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
    M: Fn(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static, // <-- notice the Fn instead of the FnMut, but &mut stays
    A: FromLuaMulti,
    R: IntoLuaMulti,

Currently, a workaround is to wrap my T inside a RefCell which fix my issue, but it makes my code for verbose and adds a bit of overhead.

What would you think of adding on the UserDataMethods trait a function like this?

// It would need a better name obviously
fn add_method_self_mut<M, A, R>(&mut self, name: impl Into<String>, method: M)
where
    M: Fn(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
    A: FromLuaMulti,
    R: IntoLuaMulti,

One might think that we could make it so that, add_method could take a &mut T as input:

fn add_method<M, A, R>(&mut self, name: impl Into<String>, method: M)
    where
        M: Fn(&Lua, &mut T, A) -> Result<R> + MaybeSend + 'static,
        A: FromLuaMulti,
        R: IntoLuaMulti,
    {
        let name = name.into();
        let callback = self.box_method(&name, method); // you'd need to update box_method to use `borrow_userdata_scoped_mut` for this to work.
        self.raw.methods.push((name, callback));
    }

However, in that case if a method calls another method recusively on the same object, one would now get a UserDataBorrowMutError.

This is why a third method, in addition to add_method and add_method_mut is needed in my opinion.

If you agree, I am willing to implement it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions