@@ -14,6 +14,8 @@ use std::marker::PhantomData;
14
14
use std:: fmt:: Debug ;
15
15
use std:: mem;
16
16
use std:: ptr;
17
+ use std:: sync:: Mutex ;
18
+ use std:: sync:: MutexGuard ;
17
19
18
20
macro_rules! impl_function {
19
21
( $name: ident, $( $p: ident) ,* ) => (
@@ -63,6 +65,9 @@ pub trait FunctionExt<P> {
63
65
fn call_mut ( & mut self , params : P ) -> Self :: Output ;
64
66
}
65
67
68
+ // TODO: with one argument we should require LuaRead<&'a mut InsideCallback<'lua>> and
69
+ // not LuaRead<&'a InsideCallback<'lua>>
70
+
66
71
macro_rules! impl_function_ext {
67
72
( ) => (
68
73
impl <Z , R > FunctionExt <( ) > for Function <Z , ( ) , R > where Z : FnMut ( ) -> R {
@@ -78,7 +83,7 @@ macro_rules! impl_function_ext {
78
83
impl <' lua, L , Z , R > Push <L > for Function <Z , ( ) , R >
79
84
where L : AsMutLua <' lua>,
80
85
Z : ' lua + FnMut ( ) -> R ,
81
- R : for <' a> Push <& ' a mut InsideCallback > + ' static
86
+ R : for <' a> Push <& ' a mut InsideCallback < ' lua> > + ' static
82
87
{
83
88
type Err = Void ; // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
84
89
@@ -103,7 +108,7 @@ macro_rules! impl_function_ext {
103
108
impl <' lua, L , Z , R > PushOne <L > for Function <Z , ( ) , R >
104
109
where L : AsMutLua <' lua>,
105
110
Z : ' lua + FnMut ( ) -> R ,
106
- R : for <' a> Push <& ' a mut InsideCallback > + ' static
111
+ R : for <' a> Push <& ' a mut InsideCallback < ' lua> > + ' static
107
112
{
108
113
}
109
114
) ;
@@ -123,8 +128,8 @@ macro_rules! impl_function_ext {
123
128
impl <' lua, L , Z , R $( , $p: ' static ) +> Push <L > for Function <Z , ( $( $p, ) * ) , R >
124
129
where L : AsMutLua <' lua>,
125
130
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
128
133
{
129
134
type Err = Void ; // TODO: use `!` instead (https://github.com/rust-lang/rust/issues/35121)
130
135
@@ -149,8 +154,8 @@ macro_rules! impl_function_ext {
149
154
impl <' lua, L , Z , R $( , $p: ' static ) +> PushOne <L > for Function <Z , ( $( $p, ) * ) , R >
150
155
where L : AsMutLua <' lua>,
151
156
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
154
159
{
155
160
}
156
161
)
@@ -168,43 +173,124 @@ impl_function_ext!(A, B, C, D, E, F, G, H);
168
173
impl_function_ext ! ( A , B , C , D , E , F , G , H , I ) ;
169
174
impl_function_ext ! ( A , B , C , D , E , F , G , H , I , J ) ;
170
175
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
+
171
227
/// Opaque type that represents the Lua context when inside a callback.
172
228
///
173
229
/// Some types (like `Result`) can only be returned from a callback and not written inside a
174
230
/// Lua variable. This type is here to enforce this restriction.
175
- pub struct InsideCallback {
231
+ pub struct InsideCallback < ' lua > {
176
232
lua : LuaContext ,
233
+ mutex : Mutex < ( ) > ,
234
+ marker : PhantomData < & ' lua ( ) > ,
177
235
}
178
236
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 > {
180
247
#[ inline]
181
248
fn as_lua ( & self ) -> LuaContext {
182
249
self . lua
183
250
}
184
251
}
185
252
186
- unsafe impl < ' a , ' lua > AsLua < ' lua > for & ' a mut InsideCallback {
253
+ unsafe impl < ' a , ' lua > AsLua < ' lua > for & ' a mut InsideCallback < ' lua > {
187
254
#[ inline]
188
255
fn as_lua ( & self ) -> LuaContext {
189
256
self . lua
190
257
}
191
258
}
192
259
193
- unsafe impl < ' a , ' lua > AsMutLua < ' lua > for & ' a mut InsideCallback {
260
+ unsafe impl < ' a , ' lua > AsMutLua < ' lua > for & ' a mut InsideCallback < ' lua > {
194
261
#[ inline]
195
262
fn as_mut_lua ( & mut self ) -> LuaContext {
196
263
self . lua
197
264
}
198
265
}
199
266
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 > ,
202
288
E : Debug
203
289
{
204
290
type Err = P ;
205
291
206
292
#[ 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 > ) > {
208
294
unsafe {
209
295
match self {
210
296
Ok ( val) => val. push_to_lua ( lua) ,
@@ -222,29 +308,33 @@ impl<'a, T, E, P> Push<&'a mut InsideCallback> for Result<T, E>
222
308
}
223
309
}
224
310
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 > ,
227
313
E : Debug
228
314
{
229
315
}
230
316
231
317
// this function is called when Lua wants to call one of our functions
232
318
#[ 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
234
320
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 > >
237
323
{
238
324
// loading the object that we want to call from the Lua context
239
325
let data_raw = unsafe { ffi:: lua_touserdata ( lua, ffi:: lua_upvalueindex ( 1 ) ) } ;
240
326
let data: & mut T = unsafe { mem:: transmute ( data_raw) } ;
241
327
242
328
// 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
+ } ;
244
334
245
335
// trying to read the arguments
246
336
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?
248
338
Err ( _) => {
249
339
let err_msg = format ! ( "wrong parameter types for callback function" ) ;
250
340
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
273
363
mod tests {
274
364
use Lua ;
275
365
use LuaError ;
366
+ use LuaFunction ;
367
+ use LuaMutex ;
276
368
use function0;
277
369
use function1;
278
370
use function2;
@@ -392,4 +484,37 @@ mod tests {
392
484
assert_eq ! ( a, 20 )
393
485
}
394
486
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
+ }*/
395
520
}
0 commit comments