diff --git a/src/table.rs b/src/table.rs index 4794d97..879a730 100644 --- a/src/table.rs +++ b/src/table.rs @@ -502,6 +502,24 @@ impl<'lua> AsRef> 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(&self, args: A) -> Result + 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> + 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(&self, args: A) -> Result + 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> + where + 'lua: 'fut, + A: ToLuaMulti<'lua>, + R: FromLuaMulti<'lua> + 'fut, + { + Function(self.0.clone()).call_async(args) + } + fn call_method(&self, key: K, args: A) -> Result where K: ToLua<'lua>, diff --git a/tests/table.rs b/tests/table.rs index b22696d..3ee0797 100644 --- a/tests/table.rs +++ b/tests/table.rs @@ -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(()) }