Add `call()` function to `TableExt` to call tables with `__call` metamethod as functions

This commit is contained in:
Alex Orlenko 2021-11-21 23:47:45 +00:00
parent 55c8af1e6b
commit 170818c469
No known key found for this signature in database
GPG Key ID: 4C150C250863B96D
2 changed files with 52 additions and 2 deletions

View File

@ -502,6 +502,24 @@ impl<'lua> AsRef<Table<'lua>> for Table<'lua> {
/// An extension trait for `Table`s that provides a variety of convenient functionality.
pub trait TableExt<'lua> {
/// Calls the table as function assuming it has `__call` metamethod.
///
/// The metamethod is called with the table as its first argument, followed by the passed arguments.
fn call<A, R>(&self, args: A) -> Result<R>
where
A: ToLuaMulti<'lua>,
R: FromLuaMulti<'lua>;
/// Asynchronously calls the table as function assuming it has `__call` metamethod.
///
/// The metamethod is called with the table as its first argument, followed by the passed arguments.
#[cfg(feature = "async")]
fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
where
'lua: 'fut,
A: ToLuaMulti<'lua>,
R: FromLuaMulti<'lua> + 'fut;
/// Gets the function associated to `key` from the table and executes it,
/// passing the table itself along with `args` as function arguments.
///
@ -564,6 +582,25 @@ pub trait TableExt<'lua> {
}
impl<'lua> TableExt<'lua> for Table<'lua> {
fn call<A, R>(&self, args: A) -> Result<R>
where
A: ToLuaMulti<'lua>,
R: FromLuaMulti<'lua>,
{
// Convert table to a function and call via pcall that respects the `__call` metamethod.
Function(self.0.clone()).call(args)
}
#[cfg(feature = "async")]
fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result<R>>
where
'lua: 'fut,
A: ToLuaMulti<'lua>,
R: FromLuaMulti<'lua> + 'fut,
{
Function(self.0.clone()).call_async(args)
}
fn call_method<K, A, R>(&self, key: K, args: A) -> Result<R>
where
K: ToLua<'lua>,

View File

@ -1,4 +1,4 @@
use mlua::{Lua, Nil, Result, Table, TableExt, Value};
use mlua::{Error, Lua, Nil, Result, Table, TableExt, Value};
#[test]
fn test_set_get() -> Result<()> {
@ -266,7 +266,12 @@ fn test_table_call() -> Result<()> {
lua.load(
r#"
table = {a = 1}
table = {a = 1, b = 2}
setmetatable(table, {
__call = function(t, key)
return "call_"..t[key]
end
})
function table.func(key)
return "func_"..key
@ -281,11 +286,19 @@ fn test_table_call() -> Result<()> {
let table: Table = lua.globals().get("table")?;
assert_eq!(table.call::<_, String>("b")?, "call_2");
assert_eq!(table.call_function::<_, _, String>("func", "a")?, "func_a");
assert_eq!(
table.call_method::<_, _, String>("method", "a")?,
"method_1"
);
// Test calling non-callable table
let table2 = lua.create_table()?;
assert!(matches!(
table2.call::<_, ()>(()),
Err(Error::RuntimeError(_))
));
Ok(())
}