mlua-rs/rlua

__call metamethod and rlua::Function

lenscas opened this issue · 2 comments

in this example

local x = setmetatable({},{__call = function()print(\"nice\")end})

x can not be used to call a function defined in rust that accepts a Function, despite normal lua being able to use it as one.

Should the function type be expanded to also allow for values implementing __call or is there already an easy way to make a function that accepts both?

Context: There was a discussion on teal's gitter about the __call metamethod and its function type.This let me to check how rlua handled it and the result seemed surprising for the 2 other people in the discussion.

Full code example

use rlua::{Function, Lua, UserData, Value};

struct Test {}

impl UserData for Test {
    fn add_methods<'lua, T: rlua::UserDataMethods<'lua, Self>>(methods: &mut T) {
        methods.add_function("test", |_, value: Function| value.call::<_, Value>(()))
    }
}

fn main() {
    Lua::new().context(|ctx| {
        ctx.globals().set("test", Test {}).unwrap();
        ctx.load(
            "local x = setmetatable({},{__call = function()print(\"nice\")end})
            x() --this prints "nice"
            test.test(x) --this goes wrong
        ",
        )
        .exec()
        .unwrap();
    });
}

Hi,
I agree that there is a problem with rlua here, although I don't think making Function able to be instantiated with a non-function is the right solution - that is meant to be an actual function (i.e. `type(x) == 'function' in Lua).

Instead the Rust-side call method should be available on rlua::Value instead of Function - from the Lua API point of view a Function and Table-with-__call are treated the same anyway. I think the same argument holds for other operations which can be handled with metamethods - such as Table::set() which can be implemented on UserData too.

So I think your example should work with one change (value: Value), but it doesn't now.

khvzak commented

rlua is going to be deprecated soon and this feature is already supported by mlua, see TableExt::call method.
If any further extension of this functionality is required I would recommend to open a new issue in the mlua repo.