Add MaybeSend requirement to Lua futures

This commit is contained in:
Alex Orlenko
2024-08-10 17:55:04 +01:00
parent 0c08cdaf7c
commit c58f67b140
10 changed files with 60 additions and 46 deletions
+3 -5
View File
@@ -559,17 +559,15 @@ impl Function {
A: FromLuaMulti,
R: IntoLuaMulti,
F: Fn(&Lua, A) -> FR + MaybeSend + 'static,
FR: Future<Output = Result<R>> + 'static,
FR: Future<Output = Result<R>> + MaybeSend + 'static,
{
WrappedAsyncFunction(Box::new(move |rawlua, args| unsafe {
let lua = rawlua.lua();
WrappedAsyncFunction(Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, None, lua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = func(lua, args);
let weak = rawlua.weak().clone();
Box::pin(async move { fut.await?.push_into_stack_multi(&weak.lock()) })
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}))
}
}
+2 -1
View File
@@ -100,6 +100,7 @@ mod value;
pub mod prelude;
pub use bstr::BString;
pub use ffi::{self, lua_CFunction, lua_State};
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
@@ -113,7 +114,7 @@ pub use crate::stdlib::StdLib;
pub use crate::string::{BorrowedBytes, BorrowedStr, String};
pub use crate::table::{Table, TableExt, TablePairs, TableSequence};
pub use crate::thread::{Thread, ThreadStatus};
pub use crate::types::{AppDataRef, AppDataRefMut, Integer, LightUserData, Number, RegistryKey};
pub use crate::types::{AppDataRef, AppDataRefMut, Integer, LightUserData, MaybeSend, Number, RegistryKey};
pub use crate::userdata::{
AnyUserData, AnyUserDataExt, MetaMethod, UserData, UserDataFields, UserDataMetatable, UserDataMethods,
UserDataRef, UserDataRefMut, UserDataRegistry,
+11 -5
View File
@@ -1,6 +1,5 @@
use std::any::TypeId;
use std::cell::RefCell;
// use std::collections::VecDeque;
use std::marker::PhantomData;
use std::ops::Deref;
use std::os::raw::{c_int, c_void};
@@ -1163,17 +1162,16 @@ impl Lua {
'lua: 'a,
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
(self.lock()).create_async_callback(Box::new(move |rawlua, args| unsafe {
let lua = rawlua.lua();
(self.lock()).create_async_callback(Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, None, lua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = func(lua, args);
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}))
}
@@ -1840,6 +1838,14 @@ impl Lua {
pub(crate) fn weak(&self) -> WeakLua {
WeakLua(XRc::downgrade(&self.0))
}
/// Returns a handle to the unprotected Lua state without any synchronization.
///
/// This is useful where we know that the lock is already held by the caller.
#[inline(always)]
pub(crate) unsafe fn raw_lua(&self) -> &RawLua {
&*self.0.data_ptr()
}
}
impl WeakLua {
+1 -1
View File
@@ -1092,7 +1092,7 @@ impl RawLua {
let args = MultiValue::from_stack_multi(nargs, rawlua)?;
let func = &*(*upvalue).data;
let fut = func(rawlua, args);
let fut = func(rawlua.lua(), args);
let extra = XRc::clone(&(*upvalue).extra);
let protect = !rawlua.unlikely_memory_error();
push_internal_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;
+4
View File
@@ -528,4 +528,8 @@ mod assertions {
static_assertions::assert_not_impl_any!(Thread: Send);
#[cfg(feature = "send")]
static_assertions::assert_impl_all!(Thread: Send, Sync);
#[cfg(all(feature = "async", not(feature = "send")))]
static_assertions::assert_not_impl_any!(AsyncThread<()>: Send);
#[cfg(all(feature = "async", feature = "send"))]
static_assertions::assert_impl_all!(AsyncThread<()>: Send, Sync);
}
+10 -3
View File
@@ -13,7 +13,13 @@ use crate::hook::Debug;
use crate::state::{ExtraData, Lua, RawLua, WeakLua};
#[cfg(feature = "async")]
use {crate::value::MultiValue, futures_util::future::LocalBoxFuture};
use crate::value::MultiValue;
#[cfg(all(feature = "async", feature = "send"))]
pub(crate) type BoxFuture<'a, T> = futures_util::future::BoxFuture<'a, T>;
#[cfg(all(feature = "async", not(feature = "send")))]
pub(crate) type BoxFuture<'a, T> = futures_util::future::LocalBoxFuture<'a, T>;
#[cfg(all(feature = "luau", feature = "serialize"))]
use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
@@ -57,13 +63,13 @@ pub(crate) type CallbackUpvalue = Upvalue<Callback<'static>>;
#[cfg(feature = "async")]
pub(crate) type AsyncCallback<'a> =
Box<dyn Fn(&'a RawLua, MultiValue) -> LocalBoxFuture<'a, Result<c_int>> + 'static>;
Box<dyn Fn(&'a Lua, MultiValue) -> BoxFuture<'a, Result<c_int>> + 'static>;
#[cfg(feature = "async")]
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static>>;
#[cfg(feature = "async")]
pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<c_int>>>;
pub(crate) type AsyncPollUpvalue = Upvalue<BoxFuture<'static, Result<c_int>>>;
/// Type to set next Luau VM action after executing interrupt function.
#[cfg(any(feature = "luau", doc))]
@@ -91,6 +97,7 @@ pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()> + Send
#[cfg(all(not(feature = "send"), feature = "lua54"))]
pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()>>;
/// A trait that adds `Send` requirement if `send` feature is enabled.
#[cfg(feature = "send")]
pub trait MaybeSend: Send {}
#[cfg(feature = "send")]
+6 -6
View File
@@ -287,7 +287,7 @@ pub trait UserDataMethods<'a, T> {
T: 'static,
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
/// Add an async method which accepts a `&mut T` as the first parameter and returns Future.
@@ -304,7 +304,7 @@ pub trait UserDataMethods<'a, T> {
T: 'static,
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
/// Add a regular method as a function which accepts generic arguments, the first argument will
@@ -348,7 +348,7 @@ pub trait UserDataMethods<'a, T> {
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
/// Add a metamethod which accepts a `&T` as the first parameter.
@@ -393,7 +393,7 @@ pub trait UserDataMethods<'a, T> {
T: 'static,
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
/// Add an async metamethod which accepts a `&mut T` as the first parameter and returns Future.
@@ -410,7 +410,7 @@ pub trait UserDataMethods<'a, T> {
T: 'static,
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
/// Add a metamethod which accepts generic arguments.
@@ -448,7 +448,7 @@ pub trait UserDataMethods<'a, T> {
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti;
}
+17 -20
View File
@@ -132,7 +132,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
@@ -145,15 +145,14 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
};
}
Box::new(move |rawlua, mut args| unsafe {
Box::new(move |lua, mut args| unsafe {
let this = args
.pop_front()
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
let lua = rawlua.lua();
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
let args = A::from_lua_args(args, 2, Some(&name), lua);
let (ref_thread, index) = (rawlua.ref_thread(), this.0.index);
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
match try_self_arg!(this.type_id()) {
Some(id) if id == TypeId::of::<T>() => {
let ud = try_self_arg!(borrow_userdata_ref::<T>(ref_thread, index));
@@ -162,7 +161,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = method(lua, ud.get_ref(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}
_ => {
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
@@ -177,7 +176,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
@@ -190,15 +189,14 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
};
}
Box::new(move |rawlua, mut args| unsafe {
Box::new(move |lua, mut args| unsafe {
let this = args
.pop_front()
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
let lua = rawlua.lua();
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
let args = A::from_lua_args(args, 2, Some(&name), lua);
let (ref_thread, index) = (rawlua.ref_thread(), this.0.index);
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
match try_self_arg!(this.type_id()) {
Some(id) if id == TypeId::of::<T>() => {
let mut ud = try_self_arg!(borrow_userdata_mut::<T>(ref_thread, index));
@@ -207,7 +205,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = method(lua, ud.get_mut(), args);
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
}
_ => {
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
@@ -252,18 +250,17 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = get_function_name::<T>(name);
Box::new(move |rawlua, args| unsafe {
let lua = rawlua.lua();
Box::new(move |lua, args| unsafe {
let args = match A::from_lua_args(args, 1, Some(&name), lua) {
Ok(args) => args,
Err(e) => return Box::pin(future::ready(Err(e))),
};
let fut = function(lua, args);
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
})
}
@@ -397,7 +394,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -410,7 +407,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -445,7 +442,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -480,7 +477,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -493,7 +490,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
A: FromLuaMulti,
MR: Future<Output = Result<R>> + 'a,
MR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();
@@ -528,7 +525,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
where
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
A: FromLuaMulti,
FR: Future<Output = Result<R>> + 'a,
FR: Future<Output = Result<R>> + MaybeSend + 'a,
R: IntoLuaMulti,
{
let name = name.to_string();