__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.
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.