Skip to main content

mlua/
function.rs

1//! Lua function handling.
2//!
3//! This module provides types for working with Lua functions from Rust, including
4//! both Lua-defined functions and native Rust callbacks.
5//!
6//! # Calling Functions
7//!
8//! Use [`Function::call`] to invoke a Lua function synchronously:
9//!
10//! ```
11//! # use mlua::{Function, Lua, Result};
12//! # fn main() -> Result<()> {
13//! let lua = Lua::new();
14//!
15//! // Get a built-in function
16//! let print: Function = lua.globals().get("print")?;
17//! print.call::<()>("Hello from Rust!")?;
18//!
19//! // Call a function that returns values
20//! let tonumber: Function = lua.globals().get("tonumber")?;
21//! let n: i32 = tonumber.call("42")?;
22//! assert_eq!(n, 42);
23//! # Ok(())
24//! # }
25//! ```
26//!
27//! For asynchronous execution, use `Function::call_async` (requires `async` feature):
28//!
29//! ```ignore
30//! let result: String = my_async_func.call_async(args).await?;
31//! ```
32//!
33//! # Creating Functions
34//!
35//! Functions can be created from Rust closures using [`Lua::create_function`]:
36//!
37//! ```
38//! # use mlua::{Lua, Result};
39//! # fn main() -> Result<()> {
40//! let lua = Lua::new();
41//!
42//! let greet = lua.create_function(|_, name: String| {
43//!     Ok(format!("Hello, {}!", name))
44//! })?;
45//!
46//! lua.globals().set("greet", greet)?;
47//! let result: String = lua.load(r#"greet("World")"#).eval()?;
48//! assert_eq!(result, "Hello, World!");
49//! # Ok(())
50//! # }
51//! ```
52//!
53//! For simpler cases, use [`Function::wrap`] or [`Function::wrap_raw`] to convert a Rust function
54//! directly:
55//!
56//! ```
57//! # use mlua::{Function, Lua, Result};
58//! # fn main() -> Result<()> {
59//! let lua = Lua::new();
60//!
61//! fn add(a: i32, b: i32) -> i32 { a + b }
62//!
63//! lua.globals().set("add", Function::wrap_raw(add))?;
64//! let sum: i32 = lua.load("add(2, 3)").eval()?;
65//! assert_eq!(sum, 5);
66//! # Ok(())
67//! # }
68//! ```
69//!
70//! # Function Environments
71//!
72//! Lua functions have an associated environment table that determines how global
73//! variables are resolved. Use [`Function::environment`] and [`Function::set_environment`]
74//! to inspect or modify this environment.
75
76use std::cell::RefCell;
77use std::os::raw::{c_int, c_void};
78use std::result::Result as StdResult;
79use std::{mem, ptr, slice};
80
81use crate::error::{Error, ExternalError, ExternalResult, Result};
82use crate::state::Lua;
83use crate::table::Table;
84use crate::traits::{FromLuaMulti, IntoLua, IntoLuaMulti};
85use crate::types::{Callback, LuaType, MaybeSend, ValueRef};
86use crate::util::{
87    StackGuard, assert_stack, check_stack, linenumber_to_usize, pop_error, ptr_to_lossy_str, ptr_to_str,
88};
89use crate::value::Value;
90
91#[cfg(feature = "async")]
92use {
93    crate::thread::AsyncThread,
94    crate::types::AsyncCallback,
95    std::future::{self, Future},
96    std::pin::{Pin, pin},
97    std::task::{Context, Poll},
98};
99
100/// Handle to an internal Lua function.
101#[derive(Clone, Debug, PartialEq)]
102pub struct Function(pub(crate) ValueRef);
103
104/// Contains information about a function.
105///
106/// Please refer to the [`Lua Debug Interface`] for more information.
107///
108/// [`Lua Debug Interface`]: https://www.lua.org/manual/5.4/manual.html#4.7
109#[derive(Clone, Debug)]
110#[non_exhaustive]
111pub struct FunctionInfo {
112    /// A (reasonable) name of the function (`None` if the name cannot be found).
113    pub name: Option<String>,
114    /// Explains the `name` field (can be `global`/`local`/`method`/`field`/`upvalue`/etc).
115    ///
116    /// Always `None` for Luau.
117    pub name_what: Option<&'static str>,
118    /// A string `Lua` if the function is a Lua function, `C` if it is a C function, `main` if it is
119    /// the main part of a chunk.
120    pub what: &'static str,
121    /// Source of the chunk that created the function.
122    pub source: Option<String>,
123    /// A "printable" version of `source`, to be used in error messages.
124    pub short_src: Option<String>,
125    /// The line number where the definition of the function starts.
126    pub line_defined: Option<usize>,
127    /// The line number where the definition of the function ends (not set by Luau).
128    pub last_line_defined: Option<usize>,
129    /// The number of upvalues of the function.
130    pub num_upvalues: u8,
131    /// The number of parameters of the function (always 0 for C).
132    #[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
133    #[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
134    pub num_params: u8,
135    /// Whether the function is a variadic function (always true for C).
136    #[cfg(any(not(any(feature = "lua51", feature = "luajit")), doc))]
137    #[cfg_attr(docsrs, doc(cfg(not(any(feature = "lua51", feature = "luajit")))))]
138    pub is_vararg: bool,
139}
140
141/// Luau function coverage snapshot.
142#[cfg(any(feature = "luau", doc))]
143#[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
144#[derive(Clone, Debug, PartialEq, Eq)]
145pub struct CoverageInfo {
146    pub function: Option<String>,
147    pub line_defined: i32,
148    pub depth: i32,
149    pub hits: Vec<i32>,
150}
151
152impl Function {
153    /// Calls the function, passing `args` as function arguments.
154    ///
155    /// The function's return values are converted to the generic type `R`.
156    ///
157    /// # Examples
158    ///
159    /// Call Lua's built-in `tostring` function:
160    ///
161    /// ```
162    /// # use mlua::{Function, Lua, Result};
163    /// # fn main() -> Result<()> {
164    /// # let lua = Lua::new();
165    /// let globals = lua.globals();
166    ///
167    /// let tostring: Function = globals.get("tostring")?;
168    ///
169    /// assert_eq!(tostring.call::<String>(123)?, "123");
170    ///
171    /// # Ok(())
172    /// # }
173    /// ```
174    ///
175    /// Call a function with multiple arguments:
176    ///
177    /// ```
178    /// # use mlua::{Function, Lua, Result};
179    /// # fn main() -> Result<()> {
180    /// # let lua = Lua::new();
181    /// let sum: Function = lua.load(
182    ///     r#"
183    ///         function(a, b)
184    ///             return a + b
185    ///         end
186    /// "#).eval()?;
187    ///
188    /// assert_eq!(sum.call::<u32>((3, 4))?, 3 + 4);
189    ///
190    /// # Ok(())
191    /// # }
192    /// ```
193    pub fn call<R: FromLuaMulti>(&self, args: impl IntoLuaMulti) -> Result<R> {
194        let lua = self.0.lua.lock();
195        let state = lua.state();
196        unsafe {
197            let _sg = StackGuard::new(state);
198            check_stack(state, 2)?;
199
200            // Push error handler
201            lua.push_error_traceback();
202            let stack_start = ffi::lua_gettop(state);
203            // Push function and the arguments
204            lua.push_ref(&self.0);
205            let nargs = args.push_into_stack_multi(&lua)?;
206            // Call the function
207            let ret = ffi::lua_pcall(state, nargs, ffi::LUA_MULTRET, stack_start);
208            if ret != ffi::LUA_OK {
209                return Err(pop_error(state, ret));
210            }
211            // Get the results
212            let nresults = ffi::lua_gettop(state) - stack_start;
213            R::from_stack_multi(nresults, &lua)
214        }
215    }
216
217    /// Returns a future that, when polled, calls `self`, passing `args` as function arguments,
218    /// and drives the execution.
219    ///
220    /// Internally it wraps the function to an [`AsyncThread`]. The returned type implements
221    /// `Future<Output = Result<R>>` and can be awaited.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use std::time::Duration;
227    /// # use mlua::{Lua, Result};
228    /// # #[tokio::main]
229    /// # async fn main() -> Result<()> {
230    /// # let lua = Lua::new();
231    ///
232    /// let sleep = lua.create_async_function(move |_lua, n: u64| async move {
233    ///     tokio::time::sleep(Duration::from_millis(n)).await;
234    ///     Ok(())
235    /// })?;
236    ///
237    /// sleep.call_async::<()>(10).await?;
238    ///
239    /// # Ok(())
240    /// # }
241    /// ```
242    ///
243    /// [`AsyncThread`]: crate::thread::AsyncThread
244    #[cfg(feature = "async")]
245    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
246    pub fn call_async<R>(&self, args: impl IntoLuaMulti) -> AsyncCallFuture<R>
247    where
248        R: FromLuaMulti,
249    {
250        let lua = self.0.lua.lock();
251        AsyncCallFuture(unsafe {
252            lua.create_recycled_thread(self).and_then(|th| {
253                let mut th = th.into_async(args)?;
254                th.set_recyclable(true);
255                Ok(th)
256            })
257        })
258    }
259
260    /// Returns a function that, when called, calls `self`, passing `args` as the first set of
261    /// arguments.
262    ///
263    /// If any arguments are passed to the returned function, they will be passed after `args`.
264    ///
265    /// # Examples
266    ///
267    /// ```
268    /// # use mlua::{Function, Lua, Result};
269    /// # fn main() -> Result<()> {
270    /// # let lua = Lua::new();
271    /// let sum: Function = lua.load(
272    ///     r#"
273    ///         function(a, b)
274    ///             return a + b
275    ///         end
276    /// "#).eval()?;
277    ///
278    /// let bound_a = sum.bind(1)?;
279    /// assert_eq!(bound_a.call::<u32>(2)?, 1 + 2);
280    ///
281    /// let bound_a_and_b = sum.bind(13)?.bind(57)?;
282    /// assert_eq!(bound_a_and_b.call::<u32>(())?, 13 + 57);
283    ///
284    /// # Ok(())
285    /// # }
286    /// ```
287    pub fn bind(&self, args: impl IntoLuaMulti) -> Result<Function> {
288        unsafe extern "C-unwind" fn args_wrapper_impl(state: *mut ffi::lua_State) -> c_int {
289            let nargs = ffi::lua_gettop(state);
290            let nbinds = ffi::lua_tointeger(state, ffi::lua_upvalueindex(1)) as c_int;
291            ffi::luaL_checkstack(state, nbinds, ptr::null());
292
293            for i in 0..nbinds {
294                ffi::lua_pushvalue(state, ffi::lua_upvalueindex(i + 2));
295            }
296            if nargs > 0 {
297                ffi::lua_rotate(state, 1, nbinds);
298            }
299
300            nargs + nbinds
301        }
302
303        let lua = self.0.lua.lock();
304        let state = lua.state();
305
306        let args = args.into_lua_multi(lua.lua())?;
307        let nargs = args.len() as c_int;
308
309        if nargs == 0 {
310            return Ok(self.clone());
311        }
312
313        if nargs + 1 > ffi::LUA_MAX_UPVALUES {
314            return Err(Error::BindError);
315        }
316
317        let args_wrapper = unsafe {
318            let _sg = StackGuard::new(state);
319            check_stack(state, nargs + 3)?;
320
321            ffi::lua_pushinteger(state, nargs as ffi::lua_Integer);
322            for arg in &args {
323                lua.push_value(arg)?;
324            }
325            protect_lua!(state, nargs + 1, 1, fn(state) {
326                ffi::lua_pushcclosure(state, args_wrapper_impl, ffi::lua_gettop(state));
327            })?;
328
329            Function(lua.pop_ref())
330        };
331
332        let lua = lua.lua();
333        lua.load(
334            r#"
335            local func, args_wrapper = ...
336            return function(...)
337                return func(args_wrapper(...))
338            end
339            "#,
340        )
341        .try_cache()
342        .set_name("=__mlua_bind")
343        .call((self, args_wrapper))
344    }
345
346    /// Returns the environment of the Lua function.
347    ///
348    /// By default Lua functions shares a global environment.
349    ///
350    /// This function always returns `None` for Rust/C functions.
351    pub fn environment(&self) -> Option<Table> {
352        let lua = self.0.lua.lock();
353        let state = lua.state();
354        unsafe {
355            let _sg = StackGuard::new(state);
356            assert_stack(state, 1);
357
358            lua.push_ref(&self.0);
359            if ffi::lua_iscfunction(state, -1) != 0 {
360                return None;
361            }
362
363            #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
364            ffi::lua_getfenv(state, -1);
365            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
366            for i in 1..=255 {
367                // Traverse upvalues until we find the _ENV one
368                match ffi::lua_getupvalue(state, -1, i) {
369                    s if s.is_null() => break,
370                    s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => break,
371                    _ => ffi::lua_pop(state, 1),
372                }
373            }
374
375            if ffi::lua_type(state, -1) != ffi::LUA_TTABLE {
376                return None;
377            }
378            Some(Table(lua.pop_ref()))
379        }
380    }
381
382    /// Sets the environment of the Lua function.
383    ///
384    /// The environment is a table that is used as the global environment for the function.
385    /// Returns `true` if environment successfully changed, `false` otherwise.
386    ///
387    /// This function does nothing for Rust/C functions.
388    pub fn set_environment(&self, env: Table) -> Result<bool> {
389        let lua = self.0.lua.lock();
390        let state = lua.state();
391        unsafe {
392            let _sg = StackGuard::new(state);
393            check_stack(state, 2)?;
394
395            lua.push_ref(&self.0);
396            if ffi::lua_iscfunction(state, -1) != 0 {
397                return Ok(false);
398            }
399
400            #[cfg(any(feature = "lua51", feature = "luajit", feature = "luau"))]
401            {
402                lua.push_ref(&env.0);
403                ffi::lua_setfenv(state, -2);
404            }
405            #[cfg(any(feature = "lua55", feature = "lua54", feature = "lua53", feature = "lua52"))]
406            for i in 1..=255 {
407                match ffi::lua_getupvalue(state, -1, i) {
408                    s if s.is_null() => return Ok(false),
409                    s if std::ffi::CStr::from_ptr(s as _) == c"_ENV" => {
410                        ffi::lua_pop(state, 1);
411                        // Create an anonymous function with the new environment
412                        let f_with_env = lua
413                            .lua()
414                            .load("return _ENV")
415                            .set_environment(env)
416                            .try_cache()
417                            .into_function()?;
418                        lua.push_ref(&f_with_env.0);
419                        ffi::lua_upvaluejoin(state, -2, i, -1, 1);
420                        break;
421                    }
422                    _ => ffi::lua_pop(state, 1),
423                }
424            }
425
426            Ok(true)
427        }
428    }
429
430    /// Returns information about the function.
431    ///
432    /// Corresponds to the `>Snu` (`>Sn` for Luau) what mask for
433    /// [`lua_getinfo`] when applied to the function.
434    ///
435    /// [`lua_getinfo`]: https://www.lua.org/manual/5.4/manual.html#lua_getinfo
436    pub fn info(&self) -> FunctionInfo {
437        let lua = self.0.lua.lock();
438        let state = lua.state();
439        unsafe {
440            let _sg = StackGuard::new(state);
441            assert_stack(state, 1);
442
443            let mut ar: ffi::lua_Debug = mem::zeroed();
444            lua.push_ref(&self.0);
445
446            #[cfg(not(feature = "luau"))]
447            let res = ffi::lua_getinfo(state, cstr!(">Snu"), &mut ar);
448            #[cfg(not(feature = "luau"))]
449            mlua_assert!(res != 0, "lua_getinfo failed with `>Snu`");
450
451            #[cfg(feature = "luau")]
452            let res = ffi::lua_getinfo(state, -1, cstr!("snau"), &mut ar);
453            #[cfg(feature = "luau")]
454            mlua_assert!(res != 0, "lua_getinfo failed with `snau`");
455
456            FunctionInfo {
457                name: ptr_to_lossy_str(ar.name).map(|s| s.into_owned()),
458                #[cfg(not(feature = "luau"))]
459                name_what: match ptr_to_str(ar.namewhat) {
460                    Some("") => None,
461                    val => val,
462                },
463                #[cfg(feature = "luau")]
464                name_what: None,
465                what: ptr_to_str(ar.what).unwrap_or("main"),
466                source: ptr_to_lossy_str(ar.source).map(|s| s.into_owned()),
467                #[cfg(not(feature = "luau"))]
468                short_src: ptr_to_lossy_str(ar.short_src.as_ptr()).map(|s| s.into_owned()),
469                #[cfg(feature = "luau")]
470                short_src: ptr_to_lossy_str(ar.short_src).map(|s| s.into_owned()),
471                line_defined: linenumber_to_usize(ar.linedefined),
472                #[cfg(not(feature = "luau"))]
473                last_line_defined: linenumber_to_usize(ar.lastlinedefined),
474                #[cfg(feature = "luau")]
475                last_line_defined: None,
476                #[cfg(not(feature = "luau"))]
477                num_upvalues: ar.nups as _,
478                #[cfg(feature = "luau")]
479                num_upvalues: ar.nupvals,
480                #[cfg(not(any(feature = "lua51", feature = "luajit")))]
481                num_params: ar.nparams,
482                #[cfg(not(any(feature = "lua51", feature = "luajit")))]
483                is_vararg: ar.isvararg != 0,
484            }
485        }
486    }
487
488    /// Dumps the function as a binary chunk.
489    ///
490    /// If `strip` is true, the binary representation may not include all debug information
491    /// about the function, to save space.
492    ///
493    /// For Luau a [`Compiler`] can be used to compile Lua chunks to bytecode.
494    ///
495    /// [`Compiler`]: crate::chunk::Compiler
496    #[cfg(not(feature = "luau"))]
497    #[cfg_attr(docsrs, doc(cfg(not(feature = "luau"))))]
498    pub fn dump(&self, strip: bool) -> Vec<u8> {
499        unsafe extern "C-unwind" fn writer(
500            _state: *mut ffi::lua_State,
501            buf: *const c_void,
502            buf_len: usize,
503            data_ptr: *mut c_void,
504        ) -> c_int {
505            // If `data` is null, then it's a signal that write is finished.
506            if !data_ptr.is_null() && buf_len > 0 {
507                let data = &mut *(data_ptr as *mut Vec<u8>);
508                let buf = slice::from_raw_parts(buf as *const u8, buf_len);
509                data.extend_from_slice(buf);
510            }
511            0
512        }
513
514        let lua = self.0.lua.lock();
515        let state = lua.state();
516        let mut data: Vec<u8> = Vec::new();
517        unsafe {
518            let _sg = StackGuard::new(state);
519            assert_stack(state, 1);
520
521            lua.push_ref(&self.0);
522            let data_ptr = &mut data as *mut Vec<u8> as *mut c_void;
523            ffi::lua_dump(state, writer, data_ptr, strip as i32);
524            ffi::lua_pop(state, 1);
525        }
526
527        data
528    }
529
530    /// Retrieves recorded coverage information about this Lua function including inner calls.
531    ///
532    /// This function takes a callback as an argument and calls it providing [`CoverageInfo`]
533    /// snapshot per each executed inner function.
534    ///
535    /// Recording of coverage information is controlled by [`Compiler::set_coverage_level`] option.
536    ///
537    /// [`Compiler::set_coverage_level`]: crate::chunk::Compiler::set_coverage_level
538    #[cfg(any(feature = "luau", doc))]
539    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
540    pub fn coverage<F>(&self, func: F)
541    where
542        F: FnMut(CoverageInfo),
543    {
544        use std::ffi::CStr;
545        use std::os::raw::c_char;
546
547        unsafe extern "C-unwind" fn callback<F: FnMut(CoverageInfo)>(
548            data: *mut c_void,
549            function: *const c_char,
550            line_defined: c_int,
551            depth: c_int,
552            hits: *const c_int,
553            size: usize,
554        ) {
555            let function = if !function.is_null() {
556                Some(CStr::from_ptr(function).to_string_lossy().to_string())
557            } else {
558                None
559            };
560            let rust_callback = &*(data as *const RefCell<F>);
561            if let Ok(mut rust_callback) = rust_callback.try_borrow_mut() {
562                // Call the Rust callback with CoverageInfo
563                rust_callback(CoverageInfo {
564                    function,
565                    line_defined,
566                    depth,
567                    hits: slice::from_raw_parts(hits, size).to_vec(),
568                });
569            }
570        }
571
572        let lua = self.0.lua.lock();
573        let state = lua.state();
574        unsafe {
575            let _sg = StackGuard::new(state);
576            assert_stack(state, 1);
577
578            lua.push_ref(&self.0);
579            let func = RefCell::new(func);
580            let func_ptr = &func as *const RefCell<F> as *mut c_void;
581            ffi::lua_getcoverage(state, -1, func_ptr, callback::<F>);
582        }
583    }
584
585    /// Converts this function to a generic C pointer.
586    ///
587    /// There is no way to convert the pointer back to its original value.
588    ///
589    /// Typically this function is used only for hashing and debug information.
590    #[inline]
591    pub fn to_pointer(&self) -> *const c_void {
592        self.0.to_pointer()
593    }
594
595    /// Creates a deep clone of the Lua function.
596    ///
597    /// Copies the function prototype and all its upvalues to the
598    /// newly created function.
599    /// This function returns shallow clone (same handle) for Rust/C functions.
600    #[cfg(any(feature = "luau", doc))]
601    #[cfg_attr(docsrs, doc(cfg(feature = "luau")))]
602    pub fn deep_clone(&self) -> Result<Self> {
603        let lua = self.0.lua.lock();
604        let state = lua.state();
605        unsafe {
606            let _sg = StackGuard::new(state);
607            check_stack(state, 2)?;
608
609            lua.push_ref(&self.0);
610            if ffi::lua_iscfunction(state, -1) != 0 {
611                return Ok(self.clone());
612            }
613
614            if lua.unlikely_memory_error() {
615                ffi::lua_clonefunction(state, -1);
616            } else {
617                protect_lua!(state, 1, 1, fn(state) ffi::lua_clonefunction(state, -1))?;
618            }
619            Ok(Function(lua.pop_ref()))
620        }
621    }
622}
623
624struct WrappedFunction(pub(crate) Callback);
625
626#[cfg(feature = "async")]
627struct WrappedAsyncFunction(pub(crate) AsyncCallback);
628
629impl Function {
630    /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
631    /// trait.
632    #[inline]
633    pub fn wrap<F, A, R, E>(func: F) -> impl IntoLua
634    where
635        F: LuaNativeFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
636        A: FromLuaMulti,
637        R: IntoLuaMulti,
638        E: ExternalError,
639    {
640        WrappedFunction(Box::new(move |lua, nargs| unsafe {
641            let args = A::from_stack_args(nargs, 1, None, lua)?;
642            func.call(args).into_lua_err()?.push_into_stack_multi(lua)
643        }))
644    }
645
646    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
647    pub fn wrap_mut<F, A, R, E>(func: F) -> impl IntoLua
648    where
649        F: LuaNativeFnMut<A, Output = StdResult<R, E>> + MaybeSend + 'static,
650        A: FromLuaMulti,
651        R: IntoLuaMulti,
652        E: ExternalError,
653    {
654        let func = RefCell::new(func);
655        WrappedFunction(Box::new(move |lua, nargs| unsafe {
656            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
657            let args = A::from_stack_args(nargs, 1, None, lua)?;
658            func.call(args).into_lua_err()?.push_into_stack_multi(lua)
659        }))
660    }
661
662    /// Wraps a Rust function or closure, returning an opaque type that implements [`IntoLua`]
663    /// trait.
664    ///
665    /// This function is similar to [`Function::wrap`] but any returned `Result` will be converted
666    /// to a `ok, err` tuple without throwing an exception.
667    #[inline]
668    pub fn wrap_raw<F, A>(func: F) -> impl IntoLua
669    where
670        F: LuaNativeFn<A> + MaybeSend + 'static,
671        F::Output: IntoLuaMulti,
672        A: FromLuaMulti,
673    {
674        WrappedFunction(Box::new(move |lua, nargs| unsafe {
675            let args = A::from_stack_args(nargs, 1, None, lua)?;
676            func.call(args).push_into_stack_multi(lua)
677        }))
678    }
679
680    /// Wraps a Rust mutable closure, returning an opaque type that implements [`IntoLua`] trait.
681    ///
682    /// This function is similar to [`Function::wrap_mut`] but any returned `Result` will be
683    /// converted to a `ok, err` tuple without throwing an exception.
684    #[inline]
685    pub fn wrap_raw_mut<F, A>(func: F) -> impl IntoLua
686    where
687        F: LuaNativeFnMut<A> + MaybeSend + 'static,
688        F::Output: IntoLuaMulti,
689        A: FromLuaMulti,
690    {
691        let func = RefCell::new(func);
692        WrappedFunction(Box::new(move |lua, nargs| unsafe {
693            let mut func = func.try_borrow_mut().map_err(|_| Error::RecursiveMutCallback)?;
694            let args = A::from_stack_args(nargs, 1, None, lua)?;
695            func.call(args).push_into_stack_multi(lua)
696        }))
697    }
698
699    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
700    /// trait.
701    #[cfg(feature = "async")]
702    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
703    pub fn wrap_async<F, A, R, E>(func: F) -> impl IntoLua
704    where
705        F: LuaNativeAsyncFn<A, Output = StdResult<R, E>> + MaybeSend + 'static,
706        A: FromLuaMulti,
707        R: IntoLuaMulti,
708        E: ExternalError,
709    {
710        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
711            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
712                Ok(args) => args,
713                Err(e) => return Box::pin(future::ready(Err(e))),
714            };
715            let lua = rawlua.lua();
716            let fut = func.call(args);
717            Box::pin(async move { fut.await.into_lua_err()?.push_into_stack_multi(lua.raw_lua()) })
718        }))
719    }
720
721    /// Wraps a Rust async function or closure, returning an opaque type that implements [`IntoLua`]
722    /// trait.
723    ///
724    /// This function is similar to [`Function::wrap_async`] but any returned `Result` will be
725    /// converted to a `ok, err` tuple without throwing an exception.
726    #[cfg(feature = "async")]
727    #[cfg_attr(docsrs, doc(cfg(feature = "async")))]
728    pub fn wrap_raw_async<F, A>(func: F) -> impl IntoLua
729    where
730        F: LuaNativeAsyncFn<A> + MaybeSend + 'static,
731        F::Output: IntoLuaMulti,
732        A: FromLuaMulti,
733    {
734        WrappedAsyncFunction(Box::new(move |rawlua, nargs| unsafe {
735            let args = match A::from_stack_args(nargs, 1, None, rawlua) {
736                Ok(args) => args,
737                Err(e) => return Box::pin(future::ready(Err(e))),
738            };
739            let lua = rawlua.lua();
740            let fut = func.call(args);
741            Box::pin(async move { fut.await.push_into_stack_multi(lua.raw_lua()) })
742        }))
743    }
744}
745
746impl IntoLua for WrappedFunction {
747    #[inline]
748    fn into_lua(self, lua: &Lua) -> Result<Value> {
749        lua.lock().create_callback(self.0).map(Value::Function)
750    }
751}
752
753#[cfg(feature = "async")]
754impl IntoLua for WrappedAsyncFunction {
755    #[inline]
756    fn into_lua(self, lua: &Lua) -> Result<Value> {
757        lua.lock().create_async_callback(self.0).map(Value::Function)
758    }
759}
760
761impl LuaType for Function {
762    const TYPE_ID: c_int = ffi::LUA_TFUNCTION;
763}
764
765/// Future for asynchronous function calls.
766#[cfg(feature = "async")]
767#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
768#[must_use = "futures do nothing unless you `.await` or poll them"]
769pub struct AsyncCallFuture<R: FromLuaMulti>(Result<AsyncThread<R>>);
770
771#[cfg(feature = "async")]
772impl<R: FromLuaMulti> AsyncCallFuture<R> {
773    pub(crate) fn error(err: Error) -> Self {
774        AsyncCallFuture(Err(err))
775    }
776}
777
778#[cfg(feature = "async")]
779impl<R: FromLuaMulti> Future for AsyncCallFuture<R> {
780    type Output = Result<R>;
781
782    fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
783        let this = self.get_mut();
784        match &mut this.0 {
785            Ok(thread) => pin!(thread).poll(cx),
786            Err(err) => Poll::Ready(Err(err.clone())),
787        }
788    }
789}
790
791/// A trait for types that can be used as Lua functions.
792pub trait LuaNativeFn<A: FromLuaMulti> {
793    type Output;
794
795    fn call(&self, args: A) -> Self::Output;
796}
797
798/// A trait for types with mutable state that can be used as Lua functions.
799pub trait LuaNativeFnMut<A: FromLuaMulti> {
800    type Output;
801
802    fn call(&mut self, args: A) -> Self::Output;
803}
804
805/// A trait for types that returns a future and can be used as Lua functions.
806#[cfg(feature = "async")]
807pub trait LuaNativeAsyncFn<A: FromLuaMulti> {
808    type Output;
809
810    fn call(&self, args: A) -> impl Future<Output = Self::Output> + MaybeSend + 'static;
811}
812
813macro_rules! impl_lua_native_fn {
814    ($($A:ident),*) => {
815        impl<FN, $($A,)* R> LuaNativeFn<($($A,)*)> for FN
816        where
817            FN: Fn($($A,)*) -> R + MaybeSend + 'static,
818            ($($A,)*): FromLuaMulti,
819        {
820            type Output = R;
821
822            #[allow(non_snake_case)]
823            fn call(&self, args: ($($A,)*)) -> Self::Output {
824                let ($($A,)*) = args;
825                self($($A,)*)
826            }
827        }
828
829        impl<FN, $($A,)* R> LuaNativeFnMut<($($A,)*)> for FN
830        where
831            FN: FnMut($($A,)*) -> R + MaybeSend + 'static,
832            ($($A,)*): FromLuaMulti,
833        {
834            type Output = R;
835
836            #[allow(non_snake_case)]
837            fn call(&mut self, args: ($($A,)*)) -> Self::Output {
838                let ($($A,)*) = args;
839                self($($A,)*)
840            }
841        }
842
843        #[cfg(feature = "async")]
844        impl<FN, $($A,)* Fut, R> LuaNativeAsyncFn<($($A,)*)> for FN
845        where
846            FN: Fn($($A,)*) -> Fut + MaybeSend + 'static,
847            ($($A,)*): FromLuaMulti,
848            Fut: Future<Output = R> + MaybeSend + 'static,
849        {
850            type Output = R;
851
852            #[allow(non_snake_case)]
853            fn call(&self, args: ($($A,)*)) -> impl Future<Output = Self::Output> + MaybeSend + 'static {
854                let ($($A,)*) = args;
855                self($($A,)*)
856            }
857        }
858    };
859}
860
861impl_lua_native_fn!();
862impl_lua_native_fn!(A);
863impl_lua_native_fn!(A, B);
864impl_lua_native_fn!(A, B, C);
865impl_lua_native_fn!(A, B, C, D);
866impl_lua_native_fn!(A, B, C, D, E);
867impl_lua_native_fn!(A, B, C, D, E, F);
868impl_lua_native_fn!(A, B, C, D, E, F, G);
869impl_lua_native_fn!(A, B, C, D, E, F, G, H);
870impl_lua_native_fn!(A, B, C, D, E, F, G, H, I);
871impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J);
872impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K);
873impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L);
874impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M);
875impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
876impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
877impl_lua_native_fn!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
878
879#[cfg(test)]
880mod assertions {
881    use super::*;
882
883    #[cfg(not(feature = "send"))]
884    static_assertions::assert_not_impl_any!(Function: Send);
885    #[cfg(feature = "send")]
886    static_assertions::assert_impl_all!(Function: Send, Sync);
887
888    #[cfg(all(feature = "async", feature = "send"))]
889    static_assertions::assert_impl_all!(AsyncCallFuture<()>: Send);
890}