tlua/
lua_functions.rs

1use std::ffi::CString;
2use std::io::Cursor;
3use std::io::Error as IoError;
4use std::io::Read;
5use std::num::NonZeroI32;
6use std::panic::Location;
7
8use crate::{
9    ffi, impl_object, nzi32,
10    object::{Call, CallError, FromObject, Object},
11    AsLua, LuaError, LuaRead, LuaState, Push, PushGuard, PushInto, PushOne, PushOneInto,
12};
13
14/// Wrapper around a `&str`. When pushed, the content will be parsed as Lua code and turned into a
15/// function.
16///
17/// Since pushing this value can fail in case of a parsing error, you must use the `checked_set`
18/// method instead of `set`.
19///
20/// > **Note**: This struct is a wrapper around `LuaCodeFromReader`. There's no advantage in using
21/// > it except that it is more convenient. More advanced usages (such as returning a Lua function
22/// > from a Rust function) can be done with `LuaCodeFromReader`.
23///
24/// # Example
25///
26/// ```no_run
27/// let lua = tlua::Lua::new();
28/// lua.checked_set("hello", &tlua::LuaCode("return 5")).unwrap();
29///
30/// let r: i32 = lua.eval("return hello();").unwrap();
31/// assert_eq!(r, 5);
32/// ```
33#[derive(Debug)]
34pub struct LuaCode<'a>(pub &'a str);
35
36impl<L> Push<L> for LuaCode<'_>
37where
38    L: AsLua,
39{
40    type Err = LuaError;
41
42    #[track_caller]
43    #[inline]
44    fn push_to_lua(&self, lua: L) -> Result<PushGuard<L>, (LuaError, L)> {
45        let reader = Cursor::new(self.0.as_bytes());
46        LuaCodeFromReader::new(reader).push_into_lua(lua)
47    }
48}
49
50impl<L> PushOne<L> for LuaCode<'_> where L: AsLua {}
51
52/// Wrapper around a `Read` object. When pushed, the content will be parsed as Lua code and turned
53/// into a function.
54///
55/// Since pushing this value can fail in case of a reading error or a parsing error, you must use
56/// the `checked_set` method instead of `set`.
57///
58/// # Example: returning a Lua function from a Rust function
59///
60/// ```no_run
61/// use std::io::Cursor;
62///
63/// let lua = tlua::Lua::new();
64///
65/// lua.set("call_rust", tlua::function0(|| -> tlua::LuaCodeFromReader<Cursor<String>> {
66///     let lua_code = "return 18;";
67///     return tlua::LuaCodeFromReader::new(Cursor::new(lua_code.to_owned()));
68/// }));
69///
70/// let r: i32 = lua.eval("local lua_func = call_rust(); return lua_func();").unwrap();
71/// assert_eq!(r, 18);
72/// ```
73#[derive(Debug)]
74pub struct LuaCodeFromReader<R> {
75    reader: R,
76    location: &'static Location<'static>,
77}
78
79impl<R> LuaCodeFromReader<R> {
80    #[track_caller]
81    pub fn new(reader: R) -> Self {
82        Self {
83            reader,
84            location: Location::caller(),
85        }
86    }
87}
88
89impl<L, R> PushInto<L> for LuaCodeFromReader<R>
90where
91    L: AsLua,
92    R: Read,
93{
94    type Err = LuaError;
95
96    #[inline]
97    fn push_into_lua(self, lua: L) -> Result<PushGuard<L>, (LuaError, L)> {
98        unsafe {
99            struct ReadData<R> {
100                reader: R,
101                buffer: [u8; 128],
102                triggered_error: Option<IoError>,
103            }
104
105            let mut read_data = ReadData {
106                reader: self.reader,
107                buffer: [0; 128],
108                triggered_error: None,
109            };
110
111            extern "C" fn reader<R>(
112                _: LuaState,
113                data: *mut libc::c_void,
114                size: *mut libc::size_t,
115            ) -> *const libc::c_char
116            where
117                R: Read,
118            {
119                unsafe {
120                    let data: *mut ReadData<R> = data as *mut _;
121                    let data: &mut ReadData<R> = &mut *data;
122
123                    if data.triggered_error.is_some() {
124                        (*size) = 0;
125                        return data.buffer.as_ptr() as *const libc::c_char;
126                    }
127
128                    match data.reader.read(&mut data.buffer) {
129                        Ok(len) => (*size) = len as libc::size_t,
130                        Err(e) => {
131                            (*size) = 0;
132                            data.triggered_error = Some(e);
133                        }
134                    };
135
136                    data.buffer.as_ptr() as *const libc::c_char
137                }
138            }
139
140            let (load_return_value, pushed_value) = {
141                let location = format!("=[{}:{}]\0", self.location.file(), self.location.line());
142                let location = CString::from_vec_with_nul_unchecked(location.into());
143                let code = ffi::lua_load(
144                    lua.as_lua(),
145                    reader::<R>,
146                    &mut read_data as *mut ReadData<_> as *mut _,
147                    location.as_ptr(),
148                );
149                (code, PushGuard::new(lua, 1))
150            };
151
152            if read_data.triggered_error.is_some() {
153                let error = read_data.triggered_error.unwrap();
154                return Err((LuaError::ReadError(error), pushed_value.into_inner()));
155            }
156
157            if load_return_value == 0 {
158                return Ok(pushed_value);
159            }
160
161            let error_msg: String = LuaRead::lua_read(pushed_value.as_lua())
162                .expect("can't find error message at the top of the Lua stack");
163
164            if load_return_value == ffi::LUA_ERRMEM {
165                panic!("LUA_ERRMEM");
166            }
167
168            if load_return_value == ffi::LUA_ERRSYNTAX {
169                return Err((LuaError::SyntaxError(error_msg), pushed_value.into_inner()));
170            }
171
172            panic!("Unknown error while calling lua_load");
173        }
174    }
175}
176
177impl<L, R> PushOneInto<L> for LuaCodeFromReader<R>
178where
179    L: AsLua,
180    R: Read,
181{
182}
183
184/// Handle to a function in the Lua context.
185///
186/// Just like you can read variables as integers and strings, you can also read Lua functions by
187/// requesting a `LuaFunction` object. Once you have a `LuaFunction` you can call it with `call()`.
188///
189/// > **Note**: Passing parameters when calling the function is not yet implemented.
190///
191/// # Example
192///
193/// ```no_run
194/// let lua = tlua::Lua::new();
195/// lua.exec("function foo() return 12 end").unwrap();
196///
197/// let foo: tlua::LuaFunction<_> = lua.get("foo").unwrap();
198/// let result: i32 = foo.call().unwrap();
199/// assert_eq!(result, 12);
200/// ```
201// TODO: example for how to get a LuaFunction as a parameter of a Rust function
202#[derive(Debug)]
203pub struct LuaFunction<L> {
204    inner: Object<L>,
205}
206
207impl<L> LuaFunction<L>
208where
209    L: AsLua,
210{
211    unsafe fn new(lua: L, index: NonZeroI32) -> Self {
212        Self::from_obj(Object::new(lua, index))
213    }
214
215    pub fn into_inner(self) -> L {
216        self.inner.into_guard()
217    }
218}
219
220impl_object! { LuaFunction,
221    check(lua, index) {
222        ffi::lua_isfunction(lua.as_lua(), index.into())
223    }
224    impl Call,
225}
226
227impl<'lua, L> LuaFunction<L>
228where
229    L: 'lua,
230    L: AsLua,
231{
232    /// Calls the function. Doesn't allow passing parameters.
233    ///
234    /// TODO: will eventually disappear and get replaced with `call_with_args`
235    ///
236    /// Returns an error if there is an error while executing the Lua code (eg. a function call
237    /// returns an error), or if the requested return type doesn't match the actual return type.
238    ///
239    /// > **Note**: In order to pass parameters, see `call_with_args` instead.
240    #[track_caller]
241    #[inline]
242    pub fn call<V>(&'lua self) -> Result<V, LuaError>
243    where
244        V: LuaRead<PushGuard<&'lua L>>,
245    {
246        Call::call(self)
247    }
248
249    /// Calls the function taking ownership of the underlying push guard.
250    /// Doesn't allow passing parameters.
251    ///
252    /// TODO: will eventually disappear and get replaced with `call_with_args`
253    ///
254    /// Returns an error if there is an error while executing the Lua code (eg. a function call
255    /// returns an error), or if the requested return type doesn't match the actual return type.
256    ///
257    /// > **Note**: In order to pass parameters, see `into_call_with_args` instead.
258    #[track_caller]
259    #[inline]
260    pub fn into_call<V>(self) -> Result<V, LuaError>
261    where
262        V: LuaRead<PushGuard<Self>>,
263    {
264        Call::into_call(self)
265    }
266
267    /// Calls the function with parameters.
268    ///
269    /// TODO: should be eventually be renamed to `call`
270    ///
271    /// **Note:** this function can return multiple values if `V` is a tuple.
272    /// * If the expected number of values is less than the actual, only the
273    ///   first few values will be returned.
274    /// * If the expected number of values is greater than the actual, the
275    ///   function will return an error, unless the excess elements are
276    ///   `Option<T>`.
277    ///
278    /// You can either pass a single value by passing a single value, or multiple parameters by
279    /// passing a tuple.
280    /// If you pass a tuple, the first element of the tuple will be the first argument, the second
281    /// element of the tuple the second argument, and so on.
282    ///
283    /// Returns an error if there is an error while executing the Lua code (eg. a function call
284    /// returns an error), if the requested return type doesn't match the actual return type, or
285    /// if we failed to push an argument.
286    ///
287    /// # Example
288    ///
289    /// ```no_run
290    /// let lua = tlua::Lua::new();
291    /// lua.exec("function sub(a, b) return a - b end").unwrap();
292    ///
293    /// let foo: tlua::LuaFunction<_> = lua.get("sub").unwrap();
294    /// let result: i32 = foo.call_with_args((18, 4)).unwrap();
295    /// assert_eq!(result, 14);
296    /// ```
297    ///
298    /// # Multiple return values
299    ///
300    /// ```no_run
301    /// let lua = tlua::Lua::new();
302    /// lua.exec("function divmod(a, b) return math.floor(a / b), a % b end").unwrap();
303    ///
304    /// let foo: tlua::LuaFunction<_> = lua.get("divmod").unwrap();
305    ///
306    /// let first_result: i32 = foo.call_with_args((18, 4)).unwrap();
307    /// assert_eq!(first_result, 4);
308    ///
309    /// let all_result: (i32, i32) = foo.call_with_args((18, 4)).unwrap();
310    /// assert_eq!(all_result, (4, 2));
311    ///
312    /// let excess_results: (i32, i32, Option<i32>) = foo.call_with_args((18, 4)).unwrap();
313    /// assert_eq!(excess_results, (4, 2, None));
314    /// ```
315    #[track_caller]
316    #[inline]
317    pub fn call_with_args<V, A>(&'lua self, args: A) -> Result<V, CallError<A::Err>>
318    where
319        A: PushInto<LuaState>,
320        V: LuaRead<PushGuard<&'lua L>>,
321    {
322        Call::call_with(self, args)
323    }
324
325    /// Calls the function with parameters taking ownership of the underlying
326    /// push guard.
327    ///
328    /// TODO: should be eventually be renamed to `call`
329    ///
330    /// **Note:** this function can return multiple values if `V` is a tuple.
331    /// * If the expected number of values is less than the actual, only the
332    ///   first few values will be returned.
333    /// * If the expected number of values is greater than the actual, the
334    ///   function will return an error, unless the excess elements are
335    ///   `Option<T>`.
336    ///
337    /// You can either pass a single value by passing a single value, or multiple parameters by
338    /// passing a tuple.
339    /// If you pass a tuple, the first element of the tuple will be the first argument, the second
340    /// element of the tuple the second argument, and so on.
341    ///
342    /// Returns an error if there is an error while executing the Lua code (eg. a function call
343    /// returns an error), if the requested return type doesn't match the actual return type, or
344    /// if we failed to push an argument.
345    ///
346    /// # Example
347    ///
348    /// ```no_run
349    /// let lua = tlua::Lua::new();
350    /// lua.exec("function sub(a, b) return a - b end").unwrap();
351    ///
352    /// let foo: tlua::LuaFunction<_> = lua.get("sub").unwrap();
353    /// let result: i32 = foo.into_call_with_args((18, 4)).unwrap();
354    /// assert_eq!(result, 14);
355    /// ```
356    ///
357    /// # Multiple return values
358    ///
359    /// ```no_run
360    /// let lua = tlua::Lua::new();
361    /// lua.exec("function divmod(a, b) return math.floor(a / b), a % b end").unwrap();
362    ///
363    /// let foo: tlua::LuaFunction<_> = lua.get("divmod").unwrap();
364    ///
365    /// let all_result: (i32, i32) = foo.into_call_with_args((18, 4)).unwrap();
366    /// assert_eq!(all_result, (4, 2));
367    /// ```
368    #[track_caller]
369    #[inline]
370    pub fn into_call_with_args<V, A>(self, args: A) -> Result<V, CallError<A::Err>>
371    where
372        A: PushInto<LuaState>,
373        V: LuaRead<PushGuard<Self>>,
374    {
375        Call::into_call_with(self, args)
376    }
377}
378
379impl<L> LuaFunction<PushGuard<L>>
380where
381    L: AsLua,
382{
383    /// Builds a new `LuaFunction` from the code of a reader.
384    ///
385    /// Returns an error if reading from the `Read` object fails or if there is a syntax error in
386    /// the code.
387    ///
388    /// # Example
389    ///
390    /// ```no_run
391    /// use std::io::Cursor;
392    ///
393    /// let lua = tlua::Lua::new();
394    ///
395    /// let f = tlua::LuaFunction::load_from_reader(&lua, Cursor::new("return 8")).unwrap();
396    /// let ret: i32 = f.call().unwrap();
397    /// assert_eq!(ret, 8);
398    /// ```
399    #[track_caller]
400    #[inline]
401    pub fn load_from_reader(lua: L, code: impl Read) -> Result<Self, LuaError> {
402        match LuaCodeFromReader::new(code).push_into_lua(lua) {
403            Ok(pushed) => unsafe { Ok(Self::new(pushed, nzi32!(-1))) },
404            Err((err, _)) => Err(err),
405        }
406    }
407
408    /// Builds a new `LuaFunction` from a raw string.
409    ///
410    /// > **Note**: This is just a wrapper around `load_from_reader`. There is no advantage in
411    /// > using `load` except that it is more convenient.
412    // TODO: remove this function? it's only a thin wrapper and it's for a very niche situation
413    #[track_caller]
414    #[inline(always)]
415    pub fn load(lua: L, code: &str) -> Result<Self, LuaError> {
416        let reader = Cursor::new(code.as_bytes());
417        Self::load_from_reader(lua, reader)
418    }
419}