Skip to content

Commit e8f87bf

Browse files
committed
Add a LuaMutex type to borrow the InsideCallback
1 parent b8112e1 commit e8f87bf

File tree

4 files changed

+152
-28
lines changed

4 files changed

+152
-28
lines changed

hlua/src/functions_write.rs

Lines changed: 145 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ use std::marker::PhantomData;
1414
use std::fmt::Debug;
1515
use std::mem;
1616
use std::ptr;
17+
use std::sync::Mutex;
18+
use std::sync::MutexGuard;
1719

1820
macro_rules! impl_function {
1921
($name:ident, $($p:ident),*) => (
@@ -63,6 +65,9 @@ pub trait FunctionExt<P> {
6365
fn call_mut(&mut self, params: P) -> Self::Output;
6466
}
6567

68+
// TODO: with one argument we should require LuaRead<&'a mut InsideCallback<'lua>> and
69+
// not LuaRead<&'a InsideCallback<'lua>>
70+
6671
macro_rules! impl_function_ext {
6772
() => (
6873
impl<Z, R> FunctionExt<()> for Function<Z, (), R> where Z: FnMut() -> R {
@@ -78,7 +83,7 @@ macro_rules! impl_function_ext {
7883
impl<'lua, L, Z, R> Push<L> for Function<Z, (), R>
7984
where L: AsMutLua<'lua>,
8085
Z: 'lua + FnMut() -> R,
81-
R: for<'a> Push<&'a mut InsideCallback> + 'static
86+
R: for<'a> Push<&'a mut InsideCallback<'lua>> + 'static
8287
{
8388
type Err = Void; // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
8489

@@ -103,7 +108,7 @@ macro_rules! impl_function_ext {
103108
impl<'lua, L, Z, R> PushOne<L> for Function<Z, (), R>
104109
where L: AsMutLua<'lua>,
105110
Z: 'lua + FnMut() -> R,
106-
R: for<'a> Push<&'a mut InsideCallback> + 'static
111+
R: for<'a> Push<&'a mut InsideCallback<'lua>> + 'static
107112
{
108113
}
109114
);
@@ -123,8 +128,8 @@ macro_rules! impl_function_ext {
123128
impl<'lua, L, Z, R $(,$p: 'static)+> Push<L> for Function<Z, ($($p,)*), R>
124129
where L: AsMutLua<'lua>,
125130
Z: 'lua + FnMut($($p),*) -> R,
126-
($($p,)*): for<'p> LuaRead<&'p mut InsideCallback>,
127-
R: for<'a> Push<&'a mut InsideCallback> + 'static
131+
($($p,)*): for<'i> LuaRead<&'i InsideCallback<'lua>>,
132+
R: for<'a> Push<&'a mut InsideCallback<'lua>> + 'static
128133
{
129134
type Err = Void; // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
130135

@@ -149,8 +154,8 @@ macro_rules! impl_function_ext {
149154
impl<'lua, L, Z, R $(,$p: 'static)+> PushOne<L> for Function<Z, ($($p,)*), R>
150155
where L: AsMutLua<'lua>,
151156
Z: 'lua + FnMut($($p),*) -> R,
152-
($($p,)*): for<'p> LuaRead<&'p mut InsideCallback>,
153-
R: for<'a> Push<&'a mut InsideCallback> + 'static
157+
($($p,)*): for<'i> LuaRead<&'i InsideCallback<'lua>>,
158+
R: for<'a> Push<&'a mut InsideCallback<'lua>> + 'static
154159
{
155160
}
156161
)
@@ -168,43 +173,124 @@ impl_function_ext!(A, B, C, D, E, F, G, H);
168173
impl_function_ext!(A, B, C, D, E, F, G, H, I);
169174
impl_function_ext!(A, B, C, D, E, F, G, H, I, J);
170175

176+
pub struct LuaMutex<'a, 'lua: 'a, T> {
177+
lua: &'a InsideCallback<'lua>,
178+
index: i32,
179+
marker: PhantomData<T>,
180+
}
181+
182+
impl<'lua, 'a: 'm, 'm, T> LuaRead<&'a InsideCallback<'lua>> for LuaMutex<'m, 'lua, T>
183+
where T: LuaRead<InsideCallbackLockGuard<'m>>
184+
{
185+
#[inline]
186+
fn lua_read_at_position(lua: &'a InsideCallback<'lua>, index: i32)
187+
-> Result<Self, &'a InsideCallback<'lua>>
188+
{
189+
Ok(LuaMutex {
190+
lua: lua,
191+
index: index,
192+
marker: PhantomData,
193+
})
194+
}
195+
}
196+
/*
197+
// TODO: is this necessary?
198+
impl<'a, 'b: 'm, 'm, T> LuaRead<&'a mut &'b InsideCallback<'lua>> for LuaMutex<'m, T>
199+
where T: LuaRead<InsideCallbackLockGuard<'m>>
200+
{
201+
#[inline]
202+
fn lua_read_at_position(lua: &'a mut &'b InsideCallback<'lua>, index: i32)
203+
-> Result<Self, &'a mut &'b InsideCallback<'lua>>
204+
{
205+
Ok(LuaMutex {
206+
lua: lua,
207+
index: index,
208+
marker: PhantomData,
209+
})
210+
}
211+
}*/
212+
213+
impl<'a, 'lua, T> LuaMutex<'a, 'lua, T>
214+
where T: LuaRead<InsideCallbackLockGuard<'a>>
215+
{
216+
#[inline]
217+
pub fn lock(&self) -> Option<T> {
218+
let lock = self.lua.lock();
219+
220+
match T::lua_read_at_position(lock, self.index) {
221+
Ok(v) => Some(v),
222+
Err(_) => None
223+
}
224+
}
225+
}
226+
171227
/// Opaque type that represents the Lua context when inside a callback.
172228
///
173229
/// Some types (like `Result`) can only be returned from a callback and not written inside a
174230
/// Lua variable. This type is here to enforce this restriction.
175-
pub struct InsideCallback {
231+
pub struct InsideCallback<'lua> {
176232
lua: LuaContext,
233+
mutex: Mutex<()>,
234+
marker: PhantomData<&'lua ()>,
177235
}
178236

179-
unsafe impl<'a, 'lua> AsLua<'lua> for &'a InsideCallback {
237+
impl<'lua> InsideCallback<'lua> {
238+
pub fn lock(&self) -> InsideCallbackLockGuard {
239+
InsideCallbackLockGuard {
240+
lua: self.lua,
241+
guard: self.mutex.lock().unwrap(),
242+
}
243+
}
244+
}
245+
246+
unsafe impl<'a, 'lua> AsLua<'lua> for &'a InsideCallback<'lua> {
180247
#[inline]
181248
fn as_lua(&self) -> LuaContext {
182249
self.lua
183250
}
184251
}
185252

186-
unsafe impl<'a, 'lua> AsLua<'lua> for &'a mut InsideCallback {
253+
unsafe impl<'a, 'lua> AsLua<'lua> for &'a mut InsideCallback<'lua> {
187254
#[inline]
188255
fn as_lua(&self) -> LuaContext {
189256
self.lua
190257
}
191258
}
192259

193-
unsafe impl<'a, 'lua> AsMutLua<'lua> for &'a mut InsideCallback {
260+
unsafe impl<'a, 'lua> AsMutLua<'lua> for &'a mut InsideCallback<'lua> {
194261
#[inline]
195262
fn as_mut_lua(&mut self) -> LuaContext {
196263
self.lua
197264
}
198265
}
199266

200-
impl<'a, T, E, P> Push<&'a mut InsideCallback> for Result<T, E>
201-
where T: Push<&'a mut InsideCallback, Err = P> + for<'b> Push<&'b mut &'a mut InsideCallback, Err = P>,
267+
pub struct InsideCallbackLockGuard<'a> {
268+
lua: LuaContext,
269+
guard: MutexGuard<'a, ()>,
270+
}
271+
272+
unsafe impl<'a, 'lua> AsLua<'lua> for InsideCallbackLockGuard<'a> {
273+
#[inline]
274+
fn as_lua(&self) -> LuaContext {
275+
self.lua
276+
}
277+
}
278+
279+
unsafe impl<'a, 'lua> AsMutLua<'lua> for InsideCallbackLockGuard<'a> {
280+
#[inline]
281+
fn as_mut_lua(&mut self) -> LuaContext {
282+
self.lua
283+
}
284+
}
285+
286+
impl<'a, 'lua, T, E, P> Push<&'a mut InsideCallback<'lua>> for Result<T, E>
287+
where T: Push<&'a mut InsideCallback<'lua>, Err = P> + for<'b> Push<&'b mut &'a mut InsideCallback<'lua>, Err = P>,
202288
E: Debug
203289
{
204290
type Err = P;
205291

206292
#[inline]
207-
fn push_to_lua(self, mut lua: &'a mut InsideCallback) -> Result<PushGuard<&'a mut InsideCallback>, (P, &'a mut InsideCallback)> {
293+
fn push_to_lua(self, mut lua: &'a mut InsideCallback<'lua>) -> Result<PushGuard<&'a mut InsideCallback<'lua>>, (P, &'a mut InsideCallback<'lua>)> {
208294
unsafe {
209295
match self {
210296
Ok(val) => val.push_to_lua(lua),
@@ -222,29 +308,33 @@ impl<'a, T, E, P> Push<&'a mut InsideCallback> for Result<T, E>
222308
}
223309
}
224310

225-
impl<'a, T, E, P> PushOne<&'a mut InsideCallback> for Result<T, E>
226-
where T: PushOne<&'a mut InsideCallback, Err = P> + for<'b> PushOne<&'b mut &'a mut InsideCallback, Err = P>,
311+
impl<'a, 'lua, T, E, P> PushOne<&'a mut InsideCallback<'lua>> for Result<T, E>
312+
where T: PushOne<&'a mut InsideCallback<'lua>, Err = P> + for<'b> PushOne<&'b mut &'a mut InsideCallback<'lua>, Err = P>,
227313
E: Debug
228314
{
229315
}
230316

231317
// this function is called when Lua wants to call one of our functions
232318
#[inline]
233-
extern "C" fn wrapper<T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
319+
extern "C" fn wrapper<'lua, T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
234320
where T: FunctionExt<P, Output = R>,
235-
P: for<'p> LuaRead<&'p mut InsideCallback> + 'static,
236-
R: for<'p> Push<&'p mut InsideCallback>
321+
P: for<'p> LuaRead<&'p InsideCallback<'lua>>,
322+
R: for<'p> Push<&'p mut InsideCallback<'lua>>
237323
{
238324
// loading the object that we want to call from the Lua context
239325
let data_raw = unsafe { ffi::lua_touserdata(lua, ffi::lua_upvalueindex(1)) };
240326
let data: &mut T = unsafe { mem::transmute(data_raw) };
241327

242328
// creating a temporary Lua context in order to pass it to push & read functions
243-
let mut tmp_lua = InsideCallback { lua: LuaContext(lua) };
329+
let mut tmp_lua = InsideCallback {
330+
lua: LuaContext(lua),
331+
mutex: Mutex::new(()),
332+
marker: PhantomData,
333+
};
244334

245335
// trying to read the arguments
246336
let arguments_count = unsafe { ffi::lua_gettop(lua) } as i32;
247-
let args = match LuaRead::lua_read_at_position(&mut tmp_lua, -arguments_count as libc::c_int) { // TODO: what if the user has the wrong params?
337+
let args = match LuaRead::lua_read_at_position(&tmp_lua, -arguments_count as libc::c_int) { // TODO: what if the user has the wrong params?
248338
Err(_) => {
249339
let err_msg = format!("wrong parameter types for callback function");
250340
match err_msg.push_to_lua(&mut tmp_lua) {
@@ -273,6 +363,8 @@ extern "C" fn wrapper<T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
273363
mod tests {
274364
use Lua;
275365
use LuaError;
366+
use LuaFunction;
367+
use LuaMutex;
276368
use function0;
277369
use function1;
278370
use function2;
@@ -392,4 +484,37 @@ mod tests {
392484
assert_eq!(a, 20)
393485
}
394486

487+
#[test]
488+
fn lua_mutex_basic() {
489+
let mut lua = Lua::new();
490+
491+
lua.set("foo", function1(|a: LuaMutex<LuaFunction<_>>| {
492+
let a = a.lock().unwrap();
493+
assert_eq!(a.call::<i32>().unwrap(), 5);
494+
}));
495+
496+
lua.execute::<()>("function bar() return 5 end").unwrap();
497+
lua.execute::<()>("foo(bar)").unwrap();
498+
}
499+
500+
/* TODO: make compile
501+
#[test]
502+
fn lua_mutex_two() {
503+
let mut lua = Lua::new();
504+
505+
lua.set("foo", function2(|a: LuaMutex<LuaFunction<_>>, b: LuaMutex<LuaFunction<_>>| {
506+
{
507+
let a = a.lock().unwrap();
508+
assert_eq!(a.call::<i32>().unwrap(), 5);
509+
}
510+
511+
{
512+
let b = b.lock().unwrap();
513+
assert_eq!(b.call::<i32>().unwrap(), 5);
514+
}
515+
}));
516+
517+
lua.execute::<()>("function bar() return 5 end").unwrap();
518+
lua.execute::<()>("foo(bar)").unwrap();
519+
}*/
395520
}

hlua/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub use any::AnyLuaValue;
1111
pub use functions_write::{Function, InsideCallback};
1212
pub use functions_write::{function0, function1, function2, function3, function4, function5};
1313
pub use functions_write::{function6, function7, function8, function9, function10};
14+
pub use functions_write::LuaMutex;
1415
pub use lua_functions::LuaFunction;
1516
pub use lua_functions::LuaFunctionCallError;
1617
pub use lua_functions::{LuaCode, LuaCodeFromReader};

hlua/src/tuples.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use AsMutLua;
2-
use AsLua;
32

43
use Push;
54
use PushOne;
@@ -9,7 +8,7 @@ use Void;
98

109
macro_rules! tuple_impl {
1110
($ty:ident) => (
12-
impl<'lua, LU, $ty> Push<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: Push<LU> {
11+
impl<LU, $ty> Push<LU> for ($ty,) where $ty: Push<LU> {
1312
type Err = <$ty as Push<LU>>::Err;
1413

1514
#[inline]
@@ -18,10 +17,10 @@ macro_rules! tuple_impl {
1817
}
1918
}
2019

21-
impl<'lua, LU, $ty> PushOne<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: PushOne<LU> {
20+
impl<LU, $ty> PushOne<LU> for ($ty,) where $ty: PushOne<LU> {
2221
}
2322

24-
impl<'lua, LU, $ty> LuaRead<LU> for ($ty,) where LU: AsMutLua<'lua>, $ty: LuaRead<LU> {
23+
impl<LU, $ty> LuaRead<LU> for ($ty,) where $ty: LuaRead<LU> {
2524
#[inline]
2625
fn lua_read_at_position(lua: LU, index: i32) -> Result<($ty,), LU> {
2726
LuaRead::lua_read_at_position(lua, index).map(|v| (v,))
@@ -74,7 +73,7 @@ macro_rules! tuple_impl {
7473
#[allow(unused_assignments)]
7574
#[allow(non_snake_case)]
7675
impl<'lua, LU, $first: for<'a> LuaRead<&'a mut LU>, $($other: for<'a> LuaRead<&'a mut LU>),+>
77-
LuaRead<LU> for ($first, $($other),+) where LU: AsLua<'lua>
76+
LuaRead<LU> for ($first, $($other),+)
7877
{
7978
#[inline]
8079
fn lua_read_at_position(mut lua: LU, index: i32) -> Result<($first, $($other),+), LU> {

hlua/src/userdata.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,8 @@ pub fn push_userdata<'lua, L, T, F>(data: T, mut lua: L, mut metatable: F) -> Pu
120120

121121
///
122122
#[inline]
123-
pub fn read_userdata<'t, 'c, T>(mut lua: &'c mut InsideCallback,
124-
index: i32)
125-
-> Result<&'t mut T, &'c mut InsideCallback>
123+
pub fn read_userdata<'t, 'c, 'lua, T>(mut lua: &'c mut InsideCallback<'lua>, index: i32)
124+
-> Result<&'t mut T, &'c mut InsideCallback<'lua>>
126125
where T: 'static + Any
127126
{
128127
unsafe {

0 commit comments

Comments
 (0)