From c1168d3ec1ed6f437bcbb0304b9974f706b332de Mon Sep 17 00:00:00 2001 From: Alex Orlenko Date: Wed, 21 Jun 2023 12:44:24 +0100 Subject: [PATCH] Refactor `call_async()` functions to use static dispatch outside of traits --- src/chunk.rs | 28 +++++++------------- src/function.rs | 30 ++++++++++----------- src/lua.rs | 5 ++-- src/table.rs | 48 +++++++++++++++++----------------- src/userdata_ext.rs | 64 +++++++++++++++++++++++++-------------------- 5 files changed, 87 insertions(+), 88 deletions(-) diff --git a/src/chunk.rs b/src/chunk.rs index b3b3cb5..76454fb 100644 --- a/src/chunk.rs +++ b/src/chunk.rs @@ -11,9 +11,6 @@ use crate::lua::Lua; use crate::table::Table; use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti}; -#[cfg(feature = "async")] -use futures_util::future::{self, LocalBoxFuture}; - /// Trait for types [loadable by Lua] and convertible to a [`Chunk`] /// /// [loadable by Lua]: https://www.lua.org/manual/5.4/manual.html#3.3.2 @@ -312,8 +309,8 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// [`exec`]: #method.exec #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn exec_async(self) -> LocalBoxFuture<'lua, Result<()>> { - self.call_async(()) + pub async fn exec_async(self) -> Result<()> { + self.call_async(()).await } /// Evaluate the chunk as either an expression or block. @@ -344,17 +341,16 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// [`eval`]: #method.eval #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn eval_async<'fut, R>(self) -> LocalBoxFuture<'fut, Result> + pub async fn eval_async(self) -> Result where - 'lua: 'fut, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { if self.detect_mode() == ChunkMode::Binary { - self.call_async(()) + self.call_async(()).await } else if let Ok(function) = self.to_expression() { - function.call_async(()) + function.call_async(()).await } else { - self.call_async(()) + self.call_async(()).await } } @@ -374,16 +370,12 @@ impl<'lua, 'a> Chunk<'lua, 'a> { /// [`call`]: #method.call #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn call_async<'fut, A, R>(self, args: A) -> LocalBoxFuture<'fut, Result> + pub async fn call_async(self, args: A) -> Result where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { - match self.into_function() { - Ok(func) => func.call_async(args), - Err(e) => Box::pin(future::err(e)), - } + self.into_function()?.call_async(args).await } /// Load this chunk into a regular `Function`. diff --git a/src/function.rs b/src/function.rs index cd8f97f..80c111f 100644 --- a/src/function.rs +++ b/src/function.rs @@ -17,7 +17,7 @@ use crate::value::{FromLuaMulti, IntoLua, IntoLuaMulti}; #[cfg(feature = "async")] use { crate::types::AsyncCallback, - futures_util::future::{self, Future, LocalBoxFuture, TryFutureExt}, + futures_util::future::{self, Future}, }; /// Handle to an internal Lua function. @@ -77,7 +77,7 @@ pub struct FunctionInfo { #[cfg_attr(docsrs, doc(cfg(feature = "luau")))] #[derive(Clone, Debug, PartialEq, Eq)] pub struct CoverageInfo { - pub function: Option, + pub function: Option, pub line_defined: i32, pub depth: i32, pub hits: Vec, @@ -188,21 +188,18 @@ impl<'lua> Function<'lua> { /// [`AsyncThread`]: crate::AsyncThread #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - pub fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result> + pub fn call_async(&self, args: A) -> impl Future> + 'lua where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { let lua = self.0.lua; - match lua.create_recycled_thread(self) { - Ok(t) => { - let mut t = t.into_async(args); - t.set_recyclable(true); - Box::pin(t) - } - Err(e) => Box::pin(future::err(e)), - } + let thread_res = lua.create_recycled_thread(self).map(|th| { + let mut th = th.into_async(args); + th.set_recyclable(true); + th + }); + async move { thread_res?.await } } /// Returns a function that, when called, calls `self`, passing `args` as the first set of @@ -544,12 +541,12 @@ impl OwnedFunction { #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] #[inline] - pub fn call_async<'lua, A, R>(&'lua self, args: A) -> LocalBoxFuture<'lua, Result> + pub async fn call_async<'lua, A, R>(&'lua self, args: A) -> Result where A: IntoLuaMulti<'lua>, R: FromLuaMulti<'lua> + 'lua, { - self.to_ref().call_async(args) + self.to_ref().call_async(args).await } } @@ -604,7 +601,8 @@ impl<'lua> Function<'lua> { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; - Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.into_lua_multi(lua)))) + let fut = func(lua, args); + Box::pin(async move { fut.await?.into_lua_multi(lua) }) })) } } diff --git a/src/lua.rs b/src/lua.rs index d860c69..0f9194e 100644 --- a/src/lua.rs +++ b/src/lua.rs @@ -58,7 +58,7 @@ use crate::{ #[cfg(feature = "async")] use { crate::types::{AsyncCallback, AsyncCallbackUpvalue, AsyncPollUpvalue}, - futures_util::future::{self, Future, TryFutureExt}, + futures_util::future::{self, Future}, futures_util::task::{noop_waker_ref, Context, Poll, Waker}, }; @@ -1619,7 +1619,8 @@ impl Lua { Ok(args) => args, Err(e) => return Box::pin(future::err(e)), }; - Box::pin(func(lua, args).and_then(move |ret| future::ready(ret.into_lua_multi(lua)))) + let fut = func(lua, args); + Box::pin(async move { fut.await?.into_lua_multi(lua) }) })) } diff --git a/src/table.rs b/src/table.rs index 0f6da68..993be74 100644 --- a/src/table.rs +++ b/src/table.rs @@ -888,11 +888,10 @@ pub trait TableExt<'lua>: Sealed { /// The metamethod is called with the table as its first argument, followed by the passed arguments. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async(&self, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; /// Gets the function associated to `key` from the table and executes it, /// passing the table itself along with `args` as function arguments. @@ -928,12 +927,11 @@ pub trait TableExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_method<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async_method(&self, key: K, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, K: IntoLua<'lua>, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; /// Gets the function associated to `key` from the table and asynchronously executes it, /// passing `args` as function arguments and returning Future. @@ -943,16 +941,11 @@ pub trait TableExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_function<'fut, K, A, R>( - &self, - key: K, - args: A, - ) -> LocalBoxFuture<'fut, Result> + fn call_async_function(&self, key: K, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, K: IntoLua<'lua>, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; } impl<'lua> TableExt<'lua> for Table<'lua> { @@ -966,13 +959,17 @@ impl<'lua> TableExt<'lua> for Table<'lua> { } #[cfg(feature = "async")] - fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async(&self, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { - Function(self.0.clone()).call_async(args) + let args = match args.into_lua_multi(self.0.lua) { + Ok(args) => args, + Err(e) => return Box::pin(future::err(e)), + }; + let func = Function(self.0.clone()); + Box::pin(async move { func.call_async(args).await }) } fn call_method(&self, key: K, args: A) -> Result @@ -997,12 +994,11 @@ impl<'lua> TableExt<'lua> for Table<'lua> { } #[cfg(feature = "async")] - fn call_async_method<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async_method(&self, key: K, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, K: IntoLua<'lua>, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { let lua = self.0.lua; let mut args = match args.into_lua_multi(lua) { @@ -1014,15 +1010,19 @@ impl<'lua> TableExt<'lua> for Table<'lua> { } #[cfg(feature = "async")] - fn call_async_function<'fut, K, A, R>(&self, key: K, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async_function(&self, key: K, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, K: IntoLua<'lua>, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { + let lua = self.0.lua; + let args = match args.into_lua_multi(lua) { + Ok(args) => args, + Err(e) => return Box::pin(future::err(e)), + }; match self.get::<_, Function>(key) { - Ok(func) => func.call_async(args), + Ok(func) => Box::pin(async move { func.call_async(args).await }), Err(e) => Box::pin(future::err(e)), } } diff --git a/src/userdata_ext.rs b/src/userdata_ext.rs index 82f986e..14aea21 100644 --- a/src/userdata_ext.rs +++ b/src/userdata_ext.rs @@ -27,11 +27,10 @@ pub trait AnyUserDataExt<'lua>: Sealed { /// The metamethod is called with the userdata as its first argument, followed by the passed arguments. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async(&self, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; /// Calls the userdata method, assuming it has `__index` metamethod /// and a function associated to `name`. @@ -48,15 +47,14 @@ pub trait AnyUserDataExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_method<'fut, A, R>( + fn call_async_method( &self, name: impl AsRef, args: A, - ) -> LocalBoxFuture<'fut, Result> + ) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; /// Gets the function associated to `key` from the table and executes it, /// passing `args` as function arguments. @@ -78,15 +76,14 @@ pub trait AnyUserDataExt<'lua>: Sealed { /// This might invoke the `__index` metamethod. #[cfg(feature = "async")] #[cfg_attr(docsrs, doc(cfg(feature = "async")))] - fn call_async_function<'fut, A, R>( + fn call_async_function( &self, name: impl AsRef, args: A, - ) -> LocalBoxFuture<'fut, Result> + ) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut; + R: FromLuaMulti<'lua> + 'lua; } impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { @@ -127,18 +124,24 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { } #[cfg(feature = "async")] - fn call_async<'fut, A, R>(&self, args: A) -> LocalBoxFuture<'fut, Result> + fn call_async(&self, args: A) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { let metatable = match self.get_metatable() { Ok(metatable) => metatable, Err(err) => return Box::pin(future::err(err)), }; match metatable.get::(MetaMethod::Call) { - Ok(Value::Function(func)) => func.call_async((self.clone(), args)), + Ok(Value::Function(func)) => { + let mut args = match args.into_lua_multi(self.0.lua) { + Ok(args) => args, + Err(e) => return Box::pin(future::err(e)), + }; + args.push_front(Value::UserData(self.clone())); + Box::pin(async move { func.call_async(args).await }) + } Ok(_) => Box::pin(future::err(Error::RuntimeError( "attempt to call a userdata value".to_string(), ))), @@ -155,15 +158,14 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { } #[cfg(feature = "async")] - fn call_async_method<'fut, A, R>( + fn call_async_method( &self, name: impl AsRef, args: A, - ) -> LocalBoxFuture<'fut, Result> + ) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { self.call_async_function(name, (self.clone(), args)) } @@ -183,22 +185,28 @@ impl<'lua> AnyUserDataExt<'lua> for AnyUserData<'lua> { } #[cfg(feature = "async")] - fn call_async_function<'fut, A, R>( + fn call_async_function( &self, name: impl AsRef, args: A, - ) -> LocalBoxFuture<'fut, Result> + ) -> LocalBoxFuture<'lua, Result> where - 'lua: 'fut, A: IntoLuaMulti<'lua>, - R: FromLuaMulti<'lua> + 'fut, + R: FromLuaMulti<'lua> + 'lua, { match self.get(name.as_ref()) { - Ok(Value::Function(func)) => func.call_async(args), - Ok(val) => Box::pin(future::err(Error::RuntimeError(format!( - "attempt to call a {} value", - val.type_name() - )))), + Ok(Value::Function(func)) => { + let args = match args.into_lua_multi(self.0.lua) { + Ok(args) => args, + Err(e) => return Box::pin(future::err(e)), + }; + Box::pin(async move { func.call_async(args).await }) + } + Ok(val) => { + let type_name = val.type_name(); + let msg = format!("attempt to call a {type_name} value"); + Box::pin(future::err(Error::RuntimeError(msg))) + } Err(err) => Box::pin(future::err(err)), } }