1use ffi;
2use libc;
3
4use AnyLuaValue;
5use AsLua;
6use AsMutLua;
7use LuaContext;
8use LuaRead;
9use Push;
10use PushGuard;
11use PushOne;
12use Void;
13
14use std::marker::PhantomData;
15use std::fmt::Display;
16use std::mem;
17use std::ptr;
18
19macro_rules! impl_function {
20 ($name:ident, $($p:ident),*) => (
21 #[inline]
29 pub fn $name<Z, R $(, $p)*>(f: Z) -> Function<Z, ($($p,)*), R>
30 where Z: FnMut($($p),*) -> R
31 {
32 Function {
33 function: f,
34 marker: PhantomData,
35 }
36 }
37 )
38}
39
40impl_function!(function0,);
41impl_function!(function1, A);
42impl_function!(function2, A, B);
43impl_function!(function3, A, B, C);
44impl_function!(function4, A, B, C, D);
45impl_function!(function5, A, B, C, D, E);
46impl_function!(function6, A, B, C, D, E, F);
47impl_function!(function7, A, B, C, D, E, F, G);
48impl_function!(function8, A, B, C, D, E, F, G, H);
49impl_function!(function9, A, B, C, D, E, F, G, H, I);
50impl_function!(function10, A, B, C, D, E, F, G, H, I, J);
51
52#[derive(Debug)]
160pub struct Function<F, P, R> {
161 function: F,
162 marker: PhantomData<(P, R)>,
163}
164
165pub trait FunctionExt<P> {
169 type Output;
170
171 fn call_mut(&mut self, params: P) -> Self::Output;
172}
173
174#[inline]
176extern "C" fn closure_destructor_wrapper<T>(lua: *mut ffi::lua_State) -> libc::c_int {
177 unsafe {
178 let obj = ffi::lua_touserdata(lua, -1);
179 ptr::drop_in_place((obj as *mut u8) as *mut T);
180 0
181 }
182}
183
184macro_rules! impl_function_ext {
185 () => (
186 impl<Z, R> FunctionExt<()> for Function<Z, (), R> where Z: FnMut() -> R {
187 type Output = R;
188
189 #[allow(non_snake_case)]
190 #[inline]
191 fn call_mut(&mut self, _: ()) -> Self::Output {
192 (self.function)()
193 }
194 }
195
196 impl<'lua, L, Z, R> Push<L> for Function<Z, (), R>
197 where L: AsMutLua<'lua>,
198 Z: 'lua + FnMut() -> R,
199 R: for<'a> Push<&'a mut InsideCallback> + 'static
200 {
201 type Err = Void; #[inline]
204 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
205 unsafe {
206 let lua_data = ffi::lua_newuserdata(lua.as_mut_lua().0,
208 mem::size_of::<Z>() as libc::size_t);
209 let lua_data: *mut Z = mem::transmute(lua_data);
210 ptr::write(lua_data, self.function);
211
212 let lua_raw = lua.as_mut_lua();
213
214 ffi::lua_newtable(lua.as_mut_lua().0);
216
217 {
223 match "__gc".push_to_lua(&mut lua) {
224 Ok(p) => p.forget(),
225 Err(_) => unreachable!(),
226 };
227
228 ffi::lua_pushcfunction(lua.as_mut_lua().0, closure_destructor_wrapper::<Z>);
229 ffi::lua_settable(lua.as_mut_lua().0, -3);
230 }
231 ffi::lua_setmetatable(lua_raw.0, -2);
232
233 let wrapper: extern fn(*mut ffi::lua_State) -> libc::c_int = wrapper::<Self, _, R>;
235 ffi::lua_pushcclosure(lua.as_mut_lua().0, wrapper, 1);
236 let raw_lua = lua.as_lua();
237 Ok(PushGuard { lua: lua, size: 1, raw_lua: raw_lua })
238 }
239 }
240 }
241
242 impl<'lua, L, Z, R> PushOne<L> for Function<Z, (), R>
243 where L: AsMutLua<'lua>,
244 Z: 'lua + FnMut() -> R,
245 R: for<'a> Push<&'a mut InsideCallback> + 'static
246 {
247 }
248 );
249
250 ($($p:ident),+) => (
251 impl<Z, R $(,$p)*> FunctionExt<($($p,)*)> for Function<Z, ($($p,)*), R> where Z: FnMut($($p),*) -> R {
252 type Output = R;
253
254 #[allow(non_snake_case)]
255 #[inline]
256 fn call_mut(&mut self, params: ($($p,)*)) -> Self::Output {
257 let ($($p,)*) = params;
258 (self.function)($($p),*)
259 }
260 }
261
262 impl<'lua, L, Z, R $(,$p: 'static)+> Push<L> for Function<Z, ($($p,)*), R>
263 where L: AsMutLua<'lua>,
264 Z: 'lua + FnMut($($p),*) -> R,
265 ($($p,)*): for<'p> LuaRead<&'p mut InsideCallback>,
266 R: for<'a> Push<&'a mut InsideCallback> + 'static
267 {
268 type Err = Void; #[inline]
271 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (Void, L)> {
272 unsafe {
273 let lua_data = ffi::lua_newuserdata(lua.as_mut_lua().0,
275 mem::size_of::<Z>() as libc::size_t);
276 let lua_data: *mut Z = mem::transmute(lua_data);
277 ptr::write(lua_data, self.function);
278
279 let lua_raw = lua.as_mut_lua();
280
281 ffi::lua_newtable(lua.as_mut_lua().0);
283
284 {
290 match "__gc".push_to_lua(&mut lua) {
291 Ok(p) => p.forget_internal(),
292 Err(_) => unreachable!(),
293 };
294
295 ffi::lua_pushcfunction(lua.as_mut_lua().0, closure_destructor_wrapper::<Z>);
296 ffi::lua_settable(lua.as_mut_lua().0, -3);
297 }
298 ffi::lua_setmetatable(lua_raw.0, -2);
299
300 let wrapper: extern fn(*mut ffi::lua_State) -> libc::c_int = wrapper::<Self, _, R>;
302 ffi::lua_pushcclosure(lua.as_mut_lua().0, wrapper, 1);
303 let raw_lua = lua.as_lua();
304 Ok(PushGuard { lua: lua, size: 1, raw_lua: raw_lua })
305 }
306 }
307 }
308
309 impl<'lua, L, Z, R $(,$p: 'static)+> PushOne<L> for Function<Z, ($($p,)*), R>
310 where L: AsMutLua<'lua>,
311 Z: 'lua + FnMut($($p),*) -> R,
312 ($($p,)*): for<'p> LuaRead<&'p mut InsideCallback>,
313 R: for<'a> Push<&'a mut InsideCallback> + 'static
314 {
315 }
316 )
317}
318
319impl_function_ext!();
320impl_function_ext!(A);
321impl_function_ext!(A, B);
322impl_function_ext!(A, B, C);
323impl_function_ext!(A, B, C, D);
324impl_function_ext!(A, B, C, D, E);
325impl_function_ext!(A, B, C, D, E, F);
326impl_function_ext!(A, B, C, D, E, F, G);
327impl_function_ext!(A, B, C, D, E, F, G, H);
328impl_function_ext!(A, B, C, D, E, F, G, H, I);
329impl_function_ext!(A, B, C, D, E, F, G, H, I, J);
330
331#[derive(Debug)]
336pub struct InsideCallback {
337 lua: LuaContext,
338}
339
340unsafe impl<'a, 'lua> AsLua<'lua> for &'a InsideCallback {
341 #[inline]
342 fn as_lua(&self) -> LuaContext {
343 self.lua
344 }
345}
346
347unsafe impl<'a, 'lua> AsLua<'lua> for &'a mut InsideCallback {
348 #[inline]
349 fn as_lua(&self) -> LuaContext {
350 self.lua
351 }
352}
353
354unsafe impl<'a, 'lua> AsMutLua<'lua> for &'a mut InsideCallback {
355 #[inline]
356 fn as_mut_lua(&mut self) -> LuaContext {
357 self.lua
358 }
359}
360
361impl<'a, T, E, P> Push<&'a mut InsideCallback> for Result<T, E>
362 where T: Push<&'a mut InsideCallback, Err = P> + for<'b> Push<&'b mut &'a mut InsideCallback, Err = P>,
363 E: Display
364{
365 type Err = P;
366
367 #[inline]
368 fn push_to_lua(self, lua: &'a mut InsideCallback) -> Result<PushGuard<&'a mut InsideCallback>, (P, &'a mut InsideCallback)> {
369 match self {
370 Ok(val) => val.push_to_lua(lua),
371 Err(val) => {
372 Ok((AnyLuaValue::LuaNil, format!("{}", val)).push_no_err(lua))
373 }
374 }
375 }
376}
377
378impl<'a, T, E, P> PushOne<&'a mut InsideCallback> for Result<T, E>
379 where T: PushOne<&'a mut InsideCallback, Err = P> + for<'b> PushOne<&'b mut &'a mut InsideCallback, Err = P>,
380 E: Display
381{
382}
383
384#[inline]
386extern "C" fn wrapper<T, P, R>(lua: *mut ffi::lua_State) -> libc::c_int
387 where T: FunctionExt<P, Output = R>,
388 P: for<'p> LuaRead<&'p mut InsideCallback> + 'static,
389 R: for<'p> Push<&'p mut InsideCallback>
390{
391 let data_raw = unsafe { ffi::lua_touserdata(lua, ffi::lua_upvalueindex(1)) };
393 let data: &mut T = unsafe { mem::transmute(data_raw) };
394
395 let mut tmp_lua = InsideCallback { lua: LuaContext(lua) };
397
398 let arguments_count = unsafe { ffi::lua_gettop(lua) } as i32;
400 let args = match LuaRead::lua_read_at_position(&mut tmp_lua, -arguments_count as libc::c_int) { Err(_) => {
402 let err_msg = format!("wrong parameter types for callback function");
403 match err_msg.push_to_lua(&mut tmp_lua) {
404 Ok(p) => p.forget_internal(),
405 Err(_) => unreachable!(),
406 };
407 unsafe {
408 ffi::lua_error(lua);
409 }
410 unreachable!()
411 }
412 Ok(a) => a,
413 };
414
415 let ret_value = data.call_mut(args);
416
417 let nb = match ret_value.push_to_lua(&mut tmp_lua) {
419 Ok(p) => p.forget_internal(),
420 Err(_) => panic!(), };
422 nb as libc::c_int
423}
424
425#[cfg(test)]
426mod tests {
427 use Lua;
428 use LuaError;
429 use function0;
430 use function1;
431 use function2;
432
433 use std::sync::Arc;
434
435 #[test]
436 fn simple_function() {
437 let mut lua = Lua::new();
438
439 fn ret5() -> i32 {
440 5
441 };
442 lua.set("ret5", function0(ret5));
443
444 let val: i32 = lua.execute("return ret5()").unwrap();
445 assert_eq!(val, 5);
446 }
447
448 #[test]
449 fn one_argument() {
450 let mut lua = Lua::new();
451
452 fn plus_one(val: i32) -> i32 {
453 val + 1
454 };
455 lua.set("plus_one", function1(plus_one));
456
457 let val: i32 = lua.execute("return plus_one(3)").unwrap();
458 assert_eq!(val, 4);
459 }
460
461 #[test]
462 fn two_arguments() {
463 let mut lua = Lua::new();
464
465 fn add(val1: i32, val2: i32) -> i32 {
466 val1 + val2
467 };
468 lua.set("add", function2(add));
469
470 let val: i32 = lua.execute("return add(3, 7)").unwrap();
471 assert_eq!(val, 10);
472 }
473
474 #[test]
475 fn wrong_arguments_types() {
476 let mut lua = Lua::new();
477
478 fn add(val1: i32, val2: i32) -> i32 {
479 val1 + val2
480 };
481 lua.set("add", function2(add));
482
483 match lua.execute::<i32>("return add(3, \"hello\")") {
484 Err(LuaError::ExecutionError(_)) => (),
485 _ => panic!(),
486 }
487 }
488
489 #[test]
490 fn return_result() {
491 let mut lua = Lua::new();
492 lua.openlibs();
493
494 fn always_fails() -> Result<i32, &'static str> {
495 Err("oops, problem")
496 };
497 lua.set("always_fails", function0(always_fails));
498
499 match lua.execute::<()>(r#"
500 local res, err = always_fails();
501 assert(res == nil);
502 assert(err == "oops, problem");
503 "#) {
504 Ok(()) => {}
505 Err(e) => panic!("{:?}", e),
506 }
507 }
508
509 #[test]
510 fn closures() {
511 let mut lua = Lua::new();
512
513 lua.set("add", function2(|a: i32, b: i32| a + b));
514 lua.set("sub", function2(|a: i32, b: i32| a - b));
515
516 let val1: i32 = lua.execute("return add(3, 7)").unwrap();
517 assert_eq!(val1, 10);
518
519 let val2: i32 = lua.execute("return sub(5, 2)").unwrap();
520 assert_eq!(val2, 3);
521 }
522
523 #[test]
524 fn closures_lifetime() {
525 fn t<F>(f: F)
526 where F: Fn(i32, i32) -> i32
527 {
528 let mut lua = Lua::new();
529
530 lua.set("add", function2(f));
531
532 let val1: i32 = lua.execute("return add(3, 7)").unwrap();
533 assert_eq!(val1, 10);
534 }
535
536 t(|a, b| a + b);
537 }
538
539 #[test]
540 fn closures_extern_access() {
541 let mut a = 5;
542
543 {
544 let mut lua = Lua::new();
545
546 lua.set("inc", function0(|| a += 1));
547 for _ in 0..15 {
548 lua.execute::<()>("inc()").unwrap();
549 }
550 }
551
552 assert_eq!(a, 20)
553 }
554
555 #[test]
556 fn closures_drop_env() {
557 static mut DID_DESTRUCTOR_RUN: bool = false;
558
559 #[derive(Debug)]
560 struct Foo { };
561 impl Drop for Foo {
562 fn drop(&mut self) {
563 unsafe {
564 DID_DESTRUCTOR_RUN = true;
565 }
566 }
567 }
568 {
569 let foo = Arc::new(Foo { });
570
571 {
572 let mut lua = Lua::new();
573
574 lua.set("print_foo", function0(move || println!("{:?}", foo)));
575 }
576 }
577 assert_eq!(unsafe { DID_DESTRUCTOR_RUN }, true);
578 }
579}