1use ffi;
2use libc;
3
4use std::error::Error;
5use std::fmt;
6use std::io::Cursor;
7use std::io::Read;
8use std::io::Error as IoError;
9use std::mem;
10use std::ptr;
11
12use AsLua;
13use AsMutLua;
14
15use LuaContext;
16use LuaRead;
17use LuaError;
18use Push;
19use PushGuard;
20use PushOne;
21use Void;
22
23#[derive(Debug)]
43pub struct LuaCode<'a>(pub &'a str);
44
45impl<'lua, 'c, L> Push<L> for LuaCode<'c>
46 where L: AsMutLua<'lua>
47{
48 type Err = LuaError;
49
50 #[inline]
51 fn push_to_lua(self, lua: L) -> Result<PushGuard<L>, (LuaError, L)> {
52 LuaCodeFromReader(Cursor::new(self.0.as_bytes())).push_to_lua(lua)
53 }
54}
55
56impl<'lua, 'c, L> PushOne<L> for LuaCode<'c> where L: AsMutLua<'lua> {}
57
58#[derive(Debug)]
80pub struct LuaCodeFromReader<R>(pub R);
81
82impl<'lua, L, R> Push<L> for LuaCodeFromReader<R>
83 where L: AsMutLua<'lua>,
84 R: Read
85{
86 type Err = LuaError;
87
88 #[inline]
89 fn push_to_lua(self, mut lua: L) -> Result<PushGuard<L>, (LuaError, L)> {
90 unsafe {
91 struct ReadData<R> {
92 reader: R,
93 buffer: [u8; 128],
94 triggered_error: Option<IoError>,
95 }
96
97 let mut read_data = ReadData {
98 reader: self.0,
99 buffer: mem::uninitialized(),
100 triggered_error: None,
101 };
102
103 extern "C" fn reader<R>(_: *mut ffi::lua_State,
104 data: *mut libc::c_void,
105 size: *mut libc::size_t)
106 -> *const libc::c_char
107 where R: Read
108 {
109 unsafe {
110 let data: *mut ReadData<R> = data as *mut _;
111 let data: &mut ReadData<R> = &mut *data;
112
113 if data.triggered_error.is_some() {
114 (*size) = 0;
115 return data.buffer.as_ptr() as *const libc::c_char;
116 }
117
118 match data.reader.read(&mut data.buffer) {
119 Ok(len) => (*size) = len as libc::size_t,
120 Err(e) => {
121 (*size) = 0;
122 data.triggered_error = Some(e);
123 }
124 };
125
126 data.buffer.as_ptr() as *const libc::c_char
127 }
128 }
129
130 let (load_return_value, pushed_value) = {
131 let code = ffi::lua_load(lua.as_mut_lua().0,
132 reader::<R>,
133 &mut read_data as *mut ReadData<_> as *mut libc::c_void,
134 b"chunk\0".as_ptr() as *const _,
135 ptr::null());
136 let raw_lua = lua.as_lua();
137 (code,
138 PushGuard {
139 lua: lua,
140 size: 1,
141 raw_lua: raw_lua,
142 })
143 };
144
145 if read_data.triggered_error.is_some() {
146 let error = read_data.triggered_error.unwrap();
147 return Err((LuaError::ReadError(error), pushed_value.into_inner()));
148 }
149
150 if load_return_value == 0 {
151 return Ok(pushed_value);
152 }
153
154 let error_msg: String = LuaRead::lua_read(&pushed_value)
155 .ok()
156 .expect("can't find error message at the top of the Lua stack");
157
158 if load_return_value == ffi::LUA_ERRMEM {
159 panic!("LUA_ERRMEM");
160 }
161
162 if load_return_value == ffi::LUA_ERRSYNTAX {
163 return Err((LuaError::SyntaxError(error_msg), pushed_value.into_inner()));
164 }
165
166 panic!("Unknown error while calling lua_load");
167 }
168 }
169}
170
171impl<'lua, L, R> PushOne<L> for LuaCodeFromReader<R>
172 where L: AsMutLua<'lua>,
173 R: Read
174{
175}
176
177#[derive(Debug)]
196pub struct LuaFunction<L> {
197 variable: L,
198}
199
200unsafe impl<'lua, L> AsLua<'lua> for LuaFunction<L>
201 where L: AsLua<'lua>
202{
203 #[inline]
204 fn as_lua(&self) -> LuaContext {
205 self.variable.as_lua()
206 }
207}
208
209unsafe impl<'lua, L> AsMutLua<'lua> for LuaFunction<L>
210 where L: AsMutLua<'lua>
211{
212 #[inline]
213 fn as_mut_lua(&mut self) -> LuaContext {
214 self.variable.as_mut_lua()
215 }
216}
217
218impl<'lua, L> LuaFunction<L>
219 where L: AsMutLua<'lua>
220{
221 #[inline]
230 pub fn call<'a, V>(&'a mut self) -> Result<V, LuaError>
231 where V: LuaRead<PushGuard<&'a mut L>>
232 {
233 match self.call_with_args(()) {
234 Ok(v) => Ok(v),
235 Err(LuaFunctionCallError::LuaError(err)) => Err(err),
236 Err(LuaFunctionCallError::PushError(_)) => unreachable!(),
237 }
238 }
239
240 #[inline]
264 pub fn call_with_args<'a, V, A, E>(&'a mut self, args: A) -> Result<V, LuaFunctionCallError<E>>
265 where A: for<'r> Push<&'r mut LuaFunction<L>, Err = E>,
266 V: LuaRead<PushGuard<&'a mut L>>
267 {
268 let (pcall_return_value, pushed_value) = unsafe {
270 ffi::lua_pushvalue(self.variable.as_mut_lua().0, -1);
272 let num_pushed = match args.push_to_lua(self) {
273 Ok(g) => g.forget_internal(),
274 Err((err, _)) => return Err(LuaFunctionCallError::PushError(err)),
275 };
276 let pcall_return_value = ffi::lua_pcall(self.variable.as_mut_lua().0, num_pushed, 1, 0); let raw_lua = self.variable.as_lua();
279 let guard = PushGuard {
280 lua: &mut self.variable,
281 size: 1,
282 raw_lua: raw_lua,
283 };
284
285 (pcall_return_value, guard)
286 };
287
288 match pcall_return_value {
289 0 => match LuaRead::lua_read(pushed_value) {
290 Err(_) => Err(LuaFunctionCallError::LuaError(LuaError::WrongType)),
291 Ok(x) => Ok(x),
292 },
293 ffi::LUA_ERRMEM => panic!("lua_pcall returned LUA_ERRMEM"),
294 ffi::LUA_ERRRUN => {
295 let error_msg: String = LuaRead::lua_read(pushed_value)
296 .ok()
297 .expect("can't find error message at the top of the Lua stack");
298 Err(LuaFunctionCallError::LuaError(LuaError::ExecutionError(error_msg)))
299 }
300 _ => panic!("Unknown error code returned by lua_pcall: {}", pcall_return_value),
301 }
302 }
303
304 #[inline]
321 pub fn load_from_reader<R>(lua: L, code: R) -> Result<LuaFunction<PushGuard<L>>, LuaError>
322 where R: Read
323 {
324 match LuaCodeFromReader(code).push_to_lua(lua) {
325 Ok(pushed) => Ok(LuaFunction { variable: pushed }),
326 Err((err, _)) => Err(err),
327 }
328 }
329
330 #[inline]
336 pub fn load(lua: L, code: &str) -> Result<LuaFunction<PushGuard<L>>, LuaError> {
337 let reader = Cursor::new(code.as_bytes());
338 LuaFunction::load_from_reader(lua, reader)
339 }
340}
341
342#[derive(Debug)]
345pub enum LuaFunctionCallError<E> {
346 LuaError(LuaError),
348 PushError(E),
350}
351
352impl<E> fmt::Display for LuaFunctionCallError<E>
353 where E: fmt::Display
354{
355 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
356 match *self {
357 LuaFunctionCallError::LuaError(ref lua_error) => write!(f, "Lua error: {}", lua_error),
358 LuaFunctionCallError::PushError(ref err) => {
359 write!(f, "Error while pushing arguments: {}", err)
360 }
361 }
362 }
363}
364
365impl<E> From<LuaError> for LuaFunctionCallError<E> {
366 #[inline]
367 fn from(err: LuaError) -> LuaFunctionCallError<E> {
368 LuaFunctionCallError::LuaError(err)
369 }
370}
371
372impl From<LuaFunctionCallError<Void>> for LuaError {
373 #[inline]
374 fn from(err: LuaFunctionCallError<Void>) -> LuaError {
375 match err {
376 LuaFunctionCallError::LuaError(lua_error) => lua_error,
377 LuaFunctionCallError::PushError(_) => unreachable!("Void cannot be instantiated"),
378 }
379 }
380}
381
382impl<E> Error for LuaFunctionCallError<E>
383 where E: Error
384{
385 fn description(&self) -> &str {
386 match *self {
387 LuaFunctionCallError::LuaError(_) => "Lua error",
388 LuaFunctionCallError::PushError(_) => "error while pushing arguments",
389 }
390 }
391
392 fn cause(&self) -> Option<&Error> {
393 match *self {
394 LuaFunctionCallError::LuaError(ref lua_error) => Some(lua_error),
395 LuaFunctionCallError::PushError(ref err) => Some(err),
396 }
397 }
398}
399
400impl Error for LuaFunctionCallError<Void> {
401 fn description(&self) -> &str {
402 match *self {
403 LuaFunctionCallError::LuaError(_) => "Lua error",
404 _ => unreachable!("Void cannot be instantiated"),
405 }
406 }
407
408 fn cause(&self) -> Option<&Error> {
409 match *self {
410 LuaFunctionCallError::LuaError(ref lua_error) => Some(lua_error),
411 _ => unreachable!("Void cannot be instantiated"),
412 }
413 }
414}
415
416impl<'lua, L> LuaRead<L> for LuaFunction<L>
424 where L: AsMutLua<'lua>
425{
426 #[inline]
427 fn lua_read_at_position(mut lua: L, index: i32) -> Result<LuaFunction<L>, L> {
428 assert!(index == -1); if unsafe { ffi::lua_isfunction(lua.as_mut_lua().0, -1) } {
430 Ok(LuaFunction { variable: lua })
431 } else {
432 Err(lua)
433 }
434 }
435}
436
437#[cfg(test)]
438mod tests {
439 use Lua;
440 use LuaError;
441 use LuaFunction;
442 use LuaFunctionCallError;
443 use LuaTable;
444 use Void;
445
446 use std::io::{Error as IoError, ErrorKind as IoErrorKind, Read};
447 use std::error::Error;
448
449 #[test]
450 fn basic() {
451 let mut lua = Lua::new();
452 let mut f = LuaFunction::load(&mut lua, "return 5;").unwrap();
453 let val: i32 = f.call().unwrap();
454 assert_eq!(val, 5);
455 }
456
457 #[test]
458 fn args() {
459 let mut lua = Lua::new();
460 lua.execute::<()>("function foo(a) return a * 5 end").unwrap();
461 let val: i32 = lua.get::<LuaFunction<_>, _>("foo").unwrap().call_with_args((3)).unwrap();
462 assert_eq!(val, 15);
463 }
464
465 #[test]
466 fn args_in_order() {
467 let mut lua = Lua::new();
468 lua.execute::<()>("function foo(a, b) return a - b end").unwrap();
469 let val: i32 = lua.get::<LuaFunction<_>, _>("foo").unwrap().call_with_args((5, 3)).unwrap();
470 assert_eq!(val, 2);
471 }
472
473 #[test]
474 fn syntax_error() {
475 let mut lua = Lua::new();
476 match LuaFunction::load(&mut lua, "azerazer") {
477 Err(LuaError::SyntaxError(_)) => (),
478 _ => panic!(),
479 };
480 }
481
482 #[test]
483 fn execution_error() {
484 let mut lua = Lua::new();
485 let mut f = LuaFunction::load(&mut lua, "return a:hello()").unwrap();
486 match f.call::<()>() {
487 Err(LuaError::ExecutionError(_)) => (),
488 _ => panic!(),
489 };
490 }
491
492 #[test]
493 fn wrong_type() {
494 let mut lua = Lua::new();
495 let mut f = LuaFunction::load(&mut lua, "return 12").unwrap();
496 match f.call::<LuaFunction<_>>() {
497 Err(LuaError::WrongType) => (),
498 _ => panic!(),
499 };
500 }
501
502 #[test]
503 fn call_and_read_table() {
504 let mut lua = Lua::new();
505 let mut f = LuaFunction::load(&mut lua, "return {1, 2, 3};").unwrap();
506 let mut val: LuaTable<_> = f.call().unwrap();
507 assert_eq!(val.get::<u8, _, _>(2).unwrap(), 2);
508 }
509
510 #[test]
511 fn lua_function_returns_function() {
512 let mut lua = Lua::new();
513 lua.execute::<()>("function foo() return 5 end").unwrap();
514 let mut bar = LuaFunction::load(&mut lua, "return foo;").unwrap();
515 let mut foo: LuaFunction<_> = bar.call().unwrap();
516 let val: i32 = foo.call().unwrap();
517 assert_eq!(val, 5);
518 }
519
520 #[test]
521 fn execute_from_reader_errors_if_cant_read() {
522 struct Reader { };
523
524 impl Read for Reader {
525 fn read(&mut self, _: &mut [u8]) -> ::std::io::Result<usize> {
526 use std::io::{Error, ErrorKind};
527 Err(Error::new(ErrorKind::Other, "oh no!"))
528 }
529 }
530
531 let mut lua = Lua::new();
532 let reader = Reader { };
533 let res: Result<(), _> = lua.execute_from_reader(reader);
534 match res {
535 Ok(_) => panic!("Reading succeded"),
536 Err(LuaError::ReadError(e)) => { assert_eq!("oh no!", e.description()) },
537 Err(_) => panic!("Unexpected error happened"),
538 }
539 }
540
541 fn _assert_error() {
542 fn _assert<T: Error>(_: T) {}
544
545 _assert(LuaFunctionCallError::LuaError::<Void>(LuaError::WrongType));
546 _assert(LuaFunctionCallError::PushError(IoError::new(IoErrorKind::Other, "Test")));
547 }
548}