hlua_badtouch/
lua_functions.rs

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/// Wrapper around a `&str`. When pushed, the content will be parsed as Lua code and turned into a
24/// function.
25///
26/// Since pushing this value can fail in case of a parsing error, you must use the `checked_set`
27/// method instead of `set`.
28///
29/// > **Note**: This struct is a wrapper around `LuaCodeFromReader`. There's no advantage in using
30/// > it except that it is more convenient. More advanced usages (such as returning a Lua function
31/// > from a Rust function) can be done with `LuaCodeFromReader`.
32///
33/// # Example
34///
35/// ```
36/// let mut lua = hlua::Lua::new();
37/// lua.checked_set("hello", hlua::LuaCode("return 5")).unwrap();
38///
39/// let r: i32 = lua.execute("return hello();").unwrap();
40/// assert_eq!(r, 5);
41/// ```
42#[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/// Wrapper around a `Read` object. When pushed, the content will be parsed as Lua code and turned
59/// into a function.
60///
61/// Since pushing this value can fail in case of a reading error or a parsing error, you must use
62/// the `checked_set` method instead of `set`.
63///
64/// # Example: returning a Lua function from a Rust function
65///
66/// ```
67/// use std::io::Cursor;
68///
69/// let mut lua = hlua::Lua::new();
70///
71/// lua.set("call_rust", hlua::function0(|| -> hlua::LuaCodeFromReader<Cursor<String>> {
72///     let lua_code = "return 18;";
73///     return hlua::LuaCodeFromReader(Cursor::new(lua_code.to_owned()));
74/// }));
75///
76/// let r: i32 = lua.execute("local lua_func = call_rust(); return lua_func();").unwrap();
77/// assert_eq!(r, 18);
78/// ```
79#[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/// Handle to a function in the Lua context.
178///
179/// Just like you can read variables as integers and strings, you can also read Lua functions by
180/// requesting a `LuaFunction` object. Once you have a `LuaFunction` you can call it with `call()`.
181///
182/// > **Note**: Passing parameters when calling the function is not yet implemented.
183///
184/// # Example
185///
186/// ```
187/// let mut lua = hlua::Lua::new();
188/// lua.execute::<()>("function foo() return 12 end").unwrap();
189///
190/// let mut foo: hlua::LuaFunction<_> = lua.get("foo").unwrap();
191/// let result: i32 = foo.call().unwrap();
192/// assert_eq!(result, 12);
193/// ```
194// TODO: example for how to get a LuaFunction as a parameter of a Rust function
195#[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    /// Calls the function. Doesn't allow passing parameters.
222    ///
223    /// TODO: will eventually disappear and get replaced with `call_with_args`
224    ///
225    /// Returns an error if there is an error while executing the Lua code (eg. a function call
226    /// returns an error), or if the requested return type doesn't match the actual return type.
227    ///
228    /// > **Note**: In order to pass parameters, see `call_with_args` instead.
229    #[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    /// Calls the function with parameters.
241    ///
242    /// TODO: should be eventually be renamed to `call`
243    ///
244    /// You can either pass a single value by passing a single value, or multiple parameters by
245    /// passing a tuple.
246    /// If you pass a tuple, the first element of the tuple will be the first argument, the second
247    /// element of the tuple the second argument, and so on.
248    ///
249    /// Returns an error if there is an error while executing the Lua code (eg. a function call
250    /// returns an error), if the requested return type doesn't match the actual return type, or
251    /// if we failed to push an argument.
252    ///
253    /// # Example
254    ///
255    /// ```
256    /// let mut lua = hlua::Lua::new();
257    /// lua.execute::<()>("function sub(a, b) return a - b end").unwrap();
258    ///
259    /// let mut foo: hlua::LuaFunction<_> = lua.get("sub").unwrap();
260    /// let result: i32 = foo.call_with_args((18, 4)).unwrap();
261    /// assert_eq!(result, 14);
262    /// ```
263    #[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        // calling pcall pops the parameters and pushes output
269        let (pcall_return_value, pushed_value) = unsafe {
270            // lua_pcall pops the function, so we have to make a copy of it
271            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);     // TODO: num ret values
277
278            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    /// Builds a new `LuaFunction` from the code of a reader.
305    ///
306    /// Returns an error if reading from the `Read` object fails or if there is a syntax error in
307    /// the code.
308    ///
309    /// # Example
310    ///
311    /// ```
312    /// use std::io::Cursor;
313    ///
314    /// let mut lua = hlua::Lua::new();
315    ///
316    /// let mut f = hlua::LuaFunction::load_from_reader(&mut lua, Cursor::new("return 8")).unwrap();
317    /// let ret: i32 = f.call().unwrap();
318    /// assert_eq!(ret, 8);
319    /// ```
320    #[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    /// Builds a new `LuaFunction` from a raw string.
331    ///
332    /// > **Note**: This is just a wrapper around `load_from_reader`. There is no advantage in
333    /// > using `load` except that it is more convenient.
334    // TODO: remove this function? it's only a thin wrapper and it's for a very niche situation
335    #[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/// Error that can happen when calling a `LuaFunction`.
343// TODO: implement Error on this
344#[derive(Debug)]
345pub enum LuaFunctionCallError<E> {
346    /// Error while executing the function.
347    LuaError(LuaError),
348    /// Error while pushing one of the parameters.
349    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
416// TODO: return Result<Ret, ExecutionError> instead
417// impl<'a, 'lua, Ret: CopyRead> ::std::ops::FnMut<(), Ret> for LuaFunction<'a,'lua> {
418// fn call_mut(&mut self, _: ()) -> Ret {
419// self.call().unwrap()
420// }
421// }
422
423impl<'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);   // FIXME:
429        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        // Compile-time trait checks.
543        fn _assert<T: Error>(_: T) {}
544
545        _assert(LuaFunctionCallError::LuaError::<Void>(LuaError::WrongType));
546        _assert(LuaFunctionCallError::PushError(IoError::new(IoErrorKind::Other, "Test")));
547    }
548}