Skip to content

Commit c58f67b

Browse files
committed
Add MaybeSend requirement to Lua futures
1 parent 0c08cda commit c58f67b

File tree

10 files changed

+60
-46
lines changed

10 files changed

+60
-46
lines changed

examples/async_tcp_server.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use std::net::SocketAddr;
44
use tokio::io::{AsyncReadExt, AsyncWriteExt};
55
use tokio::net::{TcpListener, TcpStream};
66

7-
use mlua::{chunk, Function, Lua, String as LuaString, UserData, UserDataMethods};
7+
use mlua::{chunk, BString, Function, Lua, UserData, UserDataMethods};
88

99
struct LuaTcpStream(TcpStream);
1010

@@ -19,8 +19,8 @@ impl UserData for LuaTcpStream {
1919
lua.create_string(&buf)
2020
});
2121

22-
methods.add_async_method_mut("write", |_, this, data: LuaString| async move {
23-
let n = this.0.write(&data.as_bytes()).await?;
22+
methods.add_async_method_mut("write", |_, this, data: BString| async move {
23+
let n = this.0.write(&data).await?;
2424
Ok(n)
2525
});
2626

src/function.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -559,17 +559,15 @@ impl Function {
559559
A: FromLuaMulti,
560560
R: IntoLuaMulti,
561561
F: Fn(&Lua, A) -> FR + MaybeSend + 'static,
562-
FR: Future<Output = Result<R>> + 'static,
562+
FR: Future<Output = Result<R>> + MaybeSend + 'static,
563563
{
564-
WrappedAsyncFunction(Box::new(move |rawlua, args| unsafe {
565-
let lua = rawlua.lua();
564+
WrappedAsyncFunction(Box::new(move |lua, args| unsafe {
566565
let args = match A::from_lua_args(args, 1, None, lua) {
567566
Ok(args) => args,
568567
Err(e) => return Box::pin(future::ready(Err(e))),
569568
};
570569
let fut = func(lua, args);
571-
let weak = rawlua.weak().clone();
572-
Box::pin(async move { fut.await?.push_into_stack_multi(&weak.lock()) })
570+
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
573571
}))
574572
}
575573
}

src/lib.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ mod value;
100100

101101
pub mod prelude;
102102

103+
pub use bstr::BString;
103104
pub use ffi::{self, lua_CFunction, lua_State};
104105

105106
pub use crate::chunk::{AsChunk, Chunk, ChunkMode};
@@ -113,7 +114,7 @@ pub use crate::stdlib::StdLib;
113114
pub use crate::string::{BorrowedBytes, BorrowedStr, String};
114115
pub use crate::table::{Table, TableExt, TablePairs, TableSequence};
115116
pub use crate::thread::{Thread, ThreadStatus};
116-
pub use crate::types::{AppDataRef, AppDataRefMut, Integer, LightUserData, Number, RegistryKey};
117+
pub use crate::types::{AppDataRef, AppDataRefMut, Integer, LightUserData, MaybeSend, Number, RegistryKey};
117118
pub use crate::userdata::{
118119
AnyUserData, AnyUserDataExt, MetaMethod, UserData, UserDataFields, UserDataMetatable, UserDataMethods,
119120
UserDataRef, UserDataRefMut, UserDataRegistry,

src/state.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use std::any::TypeId;
22
use std::cell::RefCell;
3-
// use std::collections::VecDeque;
43
use std::marker::PhantomData;
54
use std::ops::Deref;
65
use std::os::raw::{c_int, c_void};
@@ -1163,17 +1162,16 @@ impl Lua {
11631162
'lua: 'a,
11641163
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
11651164
A: FromLuaMulti,
1166-
FR: Future<Output = Result<R>> + 'a,
1165+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
11671166
R: IntoLuaMulti,
11681167
{
1169-
(self.lock()).create_async_callback(Box::new(move |rawlua, args| unsafe {
1170-
let lua = rawlua.lua();
1168+
(self.lock()).create_async_callback(Box::new(move |lua, args| unsafe {
11711169
let args = match A::from_lua_args(args, 1, None, lua) {
11721170
Ok(args) => args,
11731171
Err(e) => return Box::pin(future::ready(Err(e))),
11741172
};
11751173
let fut = func(lua, args);
1176-
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
1174+
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
11771175
}))
11781176
}
11791177

@@ -1840,6 +1838,14 @@ impl Lua {
18401838
pub(crate) fn weak(&self) -> WeakLua {
18411839
WeakLua(XRc::downgrade(&self.0))
18421840
}
1841+
1842+
/// Returns a handle to the unprotected Lua state without any synchronization.
1843+
///
1844+
/// This is useful where we know that the lock is already held by the caller.
1845+
#[inline(always)]
1846+
pub(crate) unsafe fn raw_lua(&self) -> &RawLua {
1847+
&*self.0.data_ptr()
1848+
}
18431849
}
18441850

18451851
impl WeakLua {

src/state/raw.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1092,7 +1092,7 @@ impl RawLua {
10921092

10931093
let args = MultiValue::from_stack_multi(nargs, rawlua)?;
10941094
let func = &*(*upvalue).data;
1095-
let fut = func(rawlua, args);
1095+
let fut = func(rawlua.lua(), args);
10961096
let extra = XRc::clone(&(*upvalue).extra);
10971097
let protect = !rawlua.unlikely_memory_error();
10981098
push_internal_userdata(state, AsyncPollUpvalue { data: fut, extra }, protect)?;

src/thread.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,4 +528,8 @@ mod assertions {
528528
static_assertions::assert_not_impl_any!(Thread: Send);
529529
#[cfg(feature = "send")]
530530
static_assertions::assert_impl_all!(Thread: Send, Sync);
531+
#[cfg(all(feature = "async", not(feature = "send")))]
532+
static_assertions::assert_not_impl_any!(AsyncThread<()>: Send);
533+
#[cfg(all(feature = "async", feature = "send"))]
534+
static_assertions::assert_impl_all!(AsyncThread<()>: Send, Sync);
531535
}

src/types.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@ use crate::hook::Debug;
1313
use crate::state::{ExtraData, Lua, RawLua, WeakLua};
1414

1515
#[cfg(feature = "async")]
16-
use {crate::value::MultiValue, futures_util::future::LocalBoxFuture};
16+
use crate::value::MultiValue;
17+
18+
#[cfg(all(feature = "async", feature = "send"))]
19+
pub(crate) type BoxFuture<'a, T> = futures_util::future::BoxFuture<'a, T>;
20+
21+
#[cfg(all(feature = "async", not(feature = "send")))]
22+
pub(crate) type BoxFuture<'a, T> = futures_util::future::LocalBoxFuture<'a, T>;
1723

1824
#[cfg(all(feature = "luau", feature = "serialize"))]
1925
use serde::ser::{Serialize, SerializeTupleStruct, Serializer};
@@ -57,13 +63,13 @@ pub(crate) type CallbackUpvalue = Upvalue<Callback<'static>>;
5763

5864
#[cfg(feature = "async")]
5965
pub(crate) type AsyncCallback<'a> =
60-
Box<dyn Fn(&'a RawLua, MultiValue) -> LocalBoxFuture<'a, Result<c_int>> + 'static>;
66+
Box<dyn Fn(&'a Lua, MultiValue) -> BoxFuture<'a, Result<c_int>> + 'static>;
6167

6268
#[cfg(feature = "async")]
6369
pub(crate) type AsyncCallbackUpvalue = Upvalue<AsyncCallback<'static>>;
6470

6571
#[cfg(feature = "async")]
66-
pub(crate) type AsyncPollUpvalue = Upvalue<LocalBoxFuture<'static, Result<c_int>>>;
72+
pub(crate) type AsyncPollUpvalue = Upvalue<BoxFuture<'static, Result<c_int>>>;
6773

6874
/// Type to set next Luau VM action after executing interrupt function.
6975
#[cfg(any(feature = "luau", doc))]
@@ -91,6 +97,7 @@ pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()> + Send
9197
#[cfg(all(not(feature = "send"), feature = "lua54"))]
9298
pub(crate) type WarnCallback = Box<dyn Fn(&Lua, &str, bool) -> Result<()>>;
9399

100+
/// A trait that adds `Send` requirement if `send` feature is enabled.
94101
#[cfg(feature = "send")]
95102
pub trait MaybeSend: Send {}
96103
#[cfg(feature = "send")]

src/userdata.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ pub trait UserDataMethods<'a, T> {
287287
T: 'static,
288288
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
289289
A: FromLuaMulti,
290-
MR: Future<Output = Result<R>> + 'a,
290+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
291291
R: IntoLuaMulti;
292292

293293
/// 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> {
304304
T: 'static,
305305
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
306306
A: FromLuaMulti,
307-
MR: Future<Output = Result<R>> + 'a,
307+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
308308
R: IntoLuaMulti;
309309

310310
/// Add a regular method as a function which accepts generic arguments, the first argument will
@@ -348,7 +348,7 @@ pub trait UserDataMethods<'a, T> {
348348
where
349349
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
350350
A: FromLuaMulti,
351-
FR: Future<Output = Result<R>> + 'a,
351+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
352352
R: IntoLuaMulti;
353353

354354
/// Add a metamethod which accepts a `&T` as the first parameter.
@@ -393,7 +393,7 @@ pub trait UserDataMethods<'a, T> {
393393
T: 'static,
394394
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
395395
A: FromLuaMulti,
396-
MR: Future<Output = Result<R>> + 'a,
396+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
397397
R: IntoLuaMulti;
398398

399399
/// 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> {
410410
T: 'static,
411411
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
412412
A: FromLuaMulti,
413-
MR: Future<Output = Result<R>> + 'a,
413+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
414414
R: IntoLuaMulti;
415415

416416
/// Add a metamethod which accepts generic arguments.
@@ -448,7 +448,7 @@ pub trait UserDataMethods<'a, T> {
448448
where
449449
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
450450
A: FromLuaMulti,
451-
FR: Future<Output = Result<R>> + 'a,
451+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
452452
R: IntoLuaMulti;
453453
}
454454

src/userdata/registry.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
132132
where
133133
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
134134
A: FromLuaMulti,
135-
MR: Future<Output = Result<R>> + 'a,
135+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
136136
R: IntoLuaMulti,
137137
{
138138
let name = get_function_name::<T>(name);
@@ -145,15 +145,14 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
145145
};
146146
}
147147

148-
Box::new(move |rawlua, mut args| unsafe {
148+
Box::new(move |lua, mut args| unsafe {
149149
let this = args
150150
.pop_front()
151151
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
152-
let lua = rawlua.lua();
153152
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
154153
let args = A::from_lua_args(args, 2, Some(&name), lua);
155154

156-
let (ref_thread, index) = (rawlua.ref_thread(), this.0.index);
155+
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
157156
match try_self_arg!(this.type_id()) {
158157
Some(id) if id == TypeId::of::<T>() => {
159158
let ud = try_self_arg!(borrow_userdata_ref::<T>(ref_thread, index));
@@ -162,7 +161,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
162161
Err(e) => return Box::pin(future::ready(Err(e))),
163162
};
164163
let fut = method(lua, ud.get_ref(), args);
165-
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
164+
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
166165
}
167166
_ => {
168167
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
@@ -177,7 +176,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
177176
where
178177
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
179178
A: FromLuaMulti,
180-
MR: Future<Output = Result<R>> + 'a,
179+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
181180
R: IntoLuaMulti,
182181
{
183182
let name = get_function_name::<T>(name);
@@ -190,15 +189,14 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
190189
};
191190
}
192191

193-
Box::new(move |rawlua, mut args| unsafe {
192+
Box::new(move |lua, mut args| unsafe {
194193
let this = args
195194
.pop_front()
196195
.ok_or_else(|| Error::from_lua_conversion("missing argument", "userdata", None));
197-
let lua = rawlua.lua();
198196
let this = try_self_arg!(AnyUserData::from_lua(try_self_arg!(this), lua));
199197
let args = A::from_lua_args(args, 2, Some(&name), lua);
200198

201-
let (ref_thread, index) = (rawlua.ref_thread(), this.0.index);
199+
let (ref_thread, index) = (lua.raw_lua().ref_thread(), this.0.index);
202200
match try_self_arg!(this.type_id()) {
203201
Some(id) if id == TypeId::of::<T>() => {
204202
let mut ud = try_self_arg!(borrow_userdata_mut::<T>(ref_thread, index));
@@ -207,7 +205,7 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
207205
Err(e) => return Box::pin(future::ready(Err(e))),
208206
};
209207
let fut = method(lua, ud.get_mut(), args);
210-
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
208+
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
211209
}
212210
_ => {
213211
let err = Error::bad_self_argument(&name, Error::UserDataTypeMismatch);
@@ -252,18 +250,17 @@ impl<'a, T: 'static> UserDataRegistry<'a, T> {
252250
where
253251
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
254252
A: FromLuaMulti,
255-
FR: Future<Output = Result<R>> + 'a,
253+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
256254
R: IntoLuaMulti,
257255
{
258256
let name = get_function_name::<T>(name);
259-
Box::new(move |rawlua, args| unsafe {
260-
let lua = rawlua.lua();
257+
Box::new(move |lua, args| unsafe {
261258
let args = match A::from_lua_args(args, 1, Some(&name), lua) {
262259
Ok(args) => args,
263260
Err(e) => return Box::pin(future::ready(Err(e))),
264261
};
265262
let fut = function(lua, args);
266-
Box::pin(async move { fut.await?.push_into_stack_multi(rawlua) })
263+
Box::pin(async move { fut.await?.push_into_stack_multi(lua.raw_lua()) })
267264
})
268265
}
269266

@@ -397,7 +394,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
397394
where
398395
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
399396
A: FromLuaMulti,
400-
MR: Future<Output = Result<R>> + 'a,
397+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
401398
R: IntoLuaMulti,
402399
{
403400
let name = name.to_string();
@@ -410,7 +407,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
410407
where
411408
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
412409
A: FromLuaMulti,
413-
MR: Future<Output = Result<R>> + 'a,
410+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
414411
R: IntoLuaMulti,
415412
{
416413
let name = name.to_string();
@@ -445,7 +442,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
445442
where
446443
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
447444
A: FromLuaMulti,
448-
FR: Future<Output = Result<R>> + 'a,
445+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
449446
R: IntoLuaMulti,
450447
{
451448
let name = name.to_string();
@@ -480,7 +477,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
480477
where
481478
M: Fn(&'a Lua, &'a T, A) -> MR + MaybeSend + 'static,
482479
A: FromLuaMulti,
483-
MR: Future<Output = Result<R>> + 'a,
480+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
484481
R: IntoLuaMulti,
485482
{
486483
let name = name.to_string();
@@ -493,7 +490,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
493490
where
494491
M: Fn(&'a Lua, &'a mut T, A) -> MR + MaybeSend + 'static,
495492
A: FromLuaMulti,
496-
MR: Future<Output = Result<R>> + 'a,
493+
MR: Future<Output = Result<R>> + MaybeSend + 'a,
497494
R: IntoLuaMulti,
498495
{
499496
let name = name.to_string();
@@ -528,7 +525,7 @@ impl<'a, T: 'static> UserDataMethods<'a, T> for UserDataRegistry<'a, T> {
528525
where
529526
F: Fn(&'a Lua, A) -> FR + MaybeSend + 'static,
530527
A: FromLuaMulti,
531-
FR: Future<Output = Result<R>> + 'a,
528+
FR: Future<Output = Result<R>> + MaybeSend + 'a,
532529
R: IntoLuaMulti,
533530
{
534531
let name = name.to_string();

tests/async.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
#![cfg(feature = "async")]
22

3-
use std::sync::{Arc, Mutex};
3+
use std::sync::Arc;
44
use std::time::Duration;
55

66
use futures_util::stream::TryStreamExt;
7+
use tokio::sync::Mutex;
78

89
use mlua::{
910
AnyUserDataExt, Error, Function, Lua, LuaOptions, MultiValue, Result, StdLib, Table, TableExt, UserData,
@@ -504,7 +505,7 @@ async fn test_async_terminate() -> Result<()> {
504505
let func = lua.create_async_function(move |_, ()| {
505506
let mutex = mutex2.clone();
506507
async move {
507-
let _guard = mutex.lock();
508+
let _guard = mutex.lock().await;
508509
sleep_ms(100).await;
509510
Ok(())
510511
}

0 commit comments

Comments
 (0)